| File: TrimAnalysis\TrimAnalysisMethodCallPattern.cs | Web Access |
| Project: src\runtime\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; using System.Collections.Immutable; using System.Diagnostics; using ILLink.RoslynAnalyzer.DataFlow; using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>; namespace ILLink.RoslynAnalyzer.TrimAnalysis { internal readonly record struct TrimAnalysisMethodCallPattern { public IMethodSymbol CalledMethod { get; init; } public MultiValue Instance { get; init; } public ImmutableArray<MultiValue> Arguments { get; init; } public IOperation Operation { get; init; } public ISymbol OwningSymbol { get; init; } public FeatureContext FeatureContext { get; init; } public TrimAnalysisMethodCallPattern( IMethodSymbol calledMethod, MultiValue instance, ImmutableArray<MultiValue> arguments, IOperation operation, ISymbol owningSymbol, FeatureContext featureContext) { CalledMethod = calledMethod; Instance = instance.DeepCopy(); if (arguments.IsEmpty) { Arguments = ImmutableArray<MultiValue>.Empty; } else { var builder = ImmutableArray.CreateBuilder<MultiValue>(); foreach (var argument in arguments) { builder.Add(argument.DeepCopy()); } Arguments = builder.ToImmutableArray(); } Operation = operation; OwningSymbol = owningSymbol; FeatureContext = featureContext.DeepCopy(); } public TrimAnalysisMethodCallPattern Merge( ValueSetLattice<SingleValue> lattice, FeatureContextLattice featureContextLattice, TrimAnalysisMethodCallPattern other) { Debug.Assert(Operation == other.Operation); Debug.Assert(SymbolEqualityComparer.Default.Equals(CalledMethod, other.CalledMethod)); Debug.Assert(SymbolEqualityComparer.Default.Equals(OwningSymbol, other.OwningSymbol)); Debug.Assert(Arguments.Length == other.Arguments.Length); var argumentsBuilder = ImmutableArray.CreateBuilder<MultiValue>(); for (int i = 0; i < Arguments.Length; i++) { argumentsBuilder.Add(lattice.Meet(Arguments[i], other.Arguments[i])); } return new TrimAnalysisMethodCallPattern( CalledMethod, lattice.Meet(Instance, other.Instance), argumentsBuilder.ToImmutable(), Operation, OwningSymbol, featureContextLattice.Meet(FeatureContext, other.FeatureContext)); } public void ReportDiagnostics(DataFlowAnalyzerContext context, Action<Diagnostic> reportDiagnostic) { Location location = Operation.Syntax.GetLocation(); if (context.TrimAnalyzer is not null && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) && !FeatureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { var typeNameResolver = new TypeNameResolver(context.Compilation); TrimAnalysisVisitor.HandleCall(context.TrimAnalyzer, FeatureContext, typeNameResolver, Operation, OwningSymbol, CalledMethod, Instance, Arguments, location, reportDiagnostic, default, out var _); } // For Requires, make the location the reference to the method, not the entire invocation. // The parameters are not part of the issue, and including them in the location can be misleading. location = Operation.Syntax switch { InvocationExpressionSyntax invocationSyntax => invocationSyntax.Expression.GetLocation(), _ => location }; var diagnosticContext = new DiagnosticContext(location, reportDiagnostic); foreach (var requiresAnalyzer in context.EnabledRequiresAnalyzers) { if (!requiresAnalyzer.IsIntrinsicallyHandled(CalledMethod, Instance, Arguments)) requiresAnalyzer.CheckAndCreateRequiresDiagnostic(Operation, CalledMethod, OwningSymbol, context, FeatureContext, in diagnosticContext); } } } }