File: TrimAnalysis\TrimAnalysisPatternStore.cs
Web Access
Project: src\src\tools\illink\src\ILLink.RoslynAnalyzer\ILLink.RoslynAnalyzer.csproj (ILLink.RoslynAnalyzer)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
using System.Collections.Generic;
using System.Diagnostics;
using ILLink.RoslynAnalyzer.DataFlow;
using ILLink.Shared.DataFlow;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
 
namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
	public readonly struct TrimAnalysisPatternStore
	{
		readonly Dictionary<(IOperation, bool), TrimAnalysisAssignmentPattern> AssignmentPatterns;
		readonly Dictionary<IOperation, TrimAnalysisFieldAccessPattern> FieldAccessPatterns;
		readonly Dictionary<IOperation, TrimAnalysisGenericInstantiationPattern> GenericInstantiationPatterns;
		readonly Dictionary<IOperation, TrimAnalysisMethodCallPattern> MethodCallPatterns;
		readonly Dictionary<IOperation, TrimAnalysisReflectionAccessPattern> ReflectionAccessPatterns;
		readonly Dictionary<IOperation, FeatureCheckReturnValuePattern> FeatureCheckReturnValuePatterns;
		readonly ValueSetLattice<SingleValue> Lattice;
		readonly FeatureContextLattice FeatureContextLattice;
 
		public TrimAnalysisPatternStore (
			ValueSetLattice<SingleValue> lattice,
			FeatureContextLattice featureContextLattice)
		{
			AssignmentPatterns = new Dictionary<(IOperation, bool), TrimAnalysisAssignmentPattern> ();
			FieldAccessPatterns = new Dictionary<IOperation, TrimAnalysisFieldAccessPattern> ();
			GenericInstantiationPatterns = new Dictionary<IOperation, TrimAnalysisGenericInstantiationPattern> ();
			MethodCallPatterns = new Dictionary<IOperation, TrimAnalysisMethodCallPattern> ();
			ReflectionAccessPatterns = new Dictionary<IOperation, TrimAnalysisReflectionAccessPattern> ();
			FeatureCheckReturnValuePatterns = new Dictionary<IOperation, FeatureCheckReturnValuePattern> ();
			Lattice = lattice;
			FeatureContextLattice = featureContextLattice;
		}
 
		public void Add (TrimAnalysisAssignmentPattern trimAnalysisPattern, bool isReturnValue)
		{
			// Finally blocks will be analyzed multiple times, once for normal control flow and once
			// for exceptional control flow, and these separate analyses could produce different
			// trim analysis patterns.
			// The current algorithm always does the exceptional analysis last, so the final state for
			// an operation will include all analysis patterns (since the exceptional state is a superset)
			// of the normal control-flow state.
			// We still add patterns to the operation, rather than replacing, to make this resilient to
			// changes in the analysis algorithm.
			if (!AssignmentPatterns.TryGetValue ((trimAnalysisPattern.Operation, isReturnValue), out var existingPattern)) {
				AssignmentPatterns.Add ((trimAnalysisPattern.Operation, isReturnValue), trimAnalysisPattern);
				return;
			}
 
			AssignmentPatterns[(trimAnalysisPattern.Operation, isReturnValue)] = trimAnalysisPattern.Merge (Lattice, FeatureContextLattice, existingPattern);
		}
 
		public void Add (TrimAnalysisFieldAccessPattern pattern)
		{
			if (!FieldAccessPatterns.TryGetValue (pattern.Operation, out var existingPattern)) {
				FieldAccessPatterns.Add (pattern.Operation, pattern);
				return;
			}
 
			FieldAccessPatterns[pattern.Operation] = pattern.Merge (Lattice, FeatureContextLattice, existingPattern);
		}
 
		public void Add (TrimAnalysisGenericInstantiationPattern pattern)
		{
			if (!GenericInstantiationPatterns.TryGetValue (pattern.Operation, out var existingPattern)) {
				GenericInstantiationPatterns.Add (pattern.Operation, pattern);
				return;
			}
 
			GenericInstantiationPatterns[pattern.Operation] = pattern.Merge (FeatureContextLattice, existingPattern);
		}
 
		public void Add (TrimAnalysisMethodCallPattern pattern)
		{
			if (!MethodCallPatterns.TryGetValue (pattern.Operation, out var existingPattern)) {
				MethodCallPatterns.Add (pattern.Operation, pattern);
				return;
			}
 
			MethodCallPatterns[pattern.Operation] = pattern.Merge (Lattice, FeatureContextLattice, existingPattern);
		}
 
		public void Add (TrimAnalysisReflectionAccessPattern pattern)
		{
			if (!ReflectionAccessPatterns.TryGetValue (pattern.Operation, out var existingPattern)) {
				ReflectionAccessPatterns.Add (pattern.Operation, pattern);
				return;
			}
 
			ReflectionAccessPatterns[pattern.Operation] = pattern.Merge (Lattice, FeatureContextLattice, existingPattern);
		}
 
		public void Add (FeatureCheckReturnValuePattern pattern)
		{
			if (!FeatureCheckReturnValuePatterns.TryGetValue (pattern.Operation, out var existingPattern)) {
				FeatureCheckReturnValuePatterns.Add (pattern.Operation, pattern);
				return;
			}
 
			Debug.Assert (existingPattern == pattern, "Return values should be identical");
		}
 
		public IEnumerable<Diagnostic> CollectDiagnostics (DataFlowAnalyzerContext context)
		{
			foreach (var assignmentPattern in AssignmentPatterns.Values) {
				foreach (var diagnostic in assignmentPattern.CollectDiagnostics (context))
					yield return diagnostic;
			}
 
			foreach (var fieldAccessPattern in FieldAccessPatterns.Values) {
				foreach (var diagnostic in fieldAccessPattern.CollectDiagnostics (context))
					yield return diagnostic;
			}
 
			foreach (var genericInstantiationPattern in GenericInstantiationPatterns.Values) {
				foreach (var diagnostic in genericInstantiationPattern.CollectDiagnostics (context))
					yield return diagnostic;
			}
 
			foreach (var methodCallPattern in MethodCallPatterns.Values) {
				foreach (var diagnostic in methodCallPattern.CollectDiagnostics (context))
					yield return diagnostic;
			}
 
			foreach (var reflectionAccessPattern in ReflectionAccessPatterns.Values) {
				foreach (var diagnostic in reflectionAccessPattern.CollectDiagnostics (context))
					yield return diagnostic;
			}
 
			foreach (var returnValuePattern in FeatureCheckReturnValuePatterns.Values) {
				foreach (var diagnostic in returnValuePattern.CollectDiagnostics (context))
					yield return diagnostic;
			}
		}
	}
}