File: TrimAnalysis\TrimAnalysisAssignmentPattern.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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;
using ILLink.RoslynAnalyzer.DataFlow;
using ILLink.Shared.DataFlow;
using ILLink.Shared.TrimAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
 
namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
    internal readonly record struct TrimAnalysisAssignmentPattern
    {
        public MultiValue Source { get; init; }
        public MultiValue Target { get; init; }
        public IOperation Operation { get; init; }
        public ISymbol OwningSymbol { get; init; }
        public FeatureContext FeatureContext { get; init; }
 
        public TrimAnalysisAssignmentPattern(
            MultiValue source,
            MultiValue target,
            IOperation operation,
            ISymbol owningSymbol,
            FeatureContext featureContext)
        {
            Source = source.DeepCopy();
            Target = target.DeepCopy();
            Operation = operation;
            OwningSymbol = owningSymbol;
            FeatureContext = featureContext;
        }
 
        public TrimAnalysisAssignmentPattern Merge(
            ValueSetLattice<SingleValue> lattice,
            FeatureContextLattice featureContextLattice,
            TrimAnalysisAssignmentPattern other)
        {
            Debug.Assert(Operation == other.Operation);
            Debug.Assert(SymbolEqualityComparer.Default.Equals(OwningSymbol, other.OwningSymbol));
 
            return new TrimAnalysisAssignmentPattern(
                lattice.Meet(Source, other.Source),
                lattice.Meet(Target, other.Target),
                Operation,
                OwningSymbol,
                featureContextLattice.Meet(FeatureContext, other.FeatureContext));
        }
 
        public void ReportDiagnostics(DataFlowAnalyzerContext context, Action<Diagnostic> reportDiagnostic)
        {
            var diagnosticContext = new DiagnosticContext(Operation.Syntax.GetLocation(), reportDiagnostic);
            if (context.EnableTrimAnalyzer &&
                !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) &&
                !FeatureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute))
            {
                foreach (var sourceValue in Source.AsEnumerable())
                {
                    foreach (var targetValue in Target.AsEnumerable())
                    {
                        // The target should always be an annotated value, but the visitor design currently prevents
                        // declaring this in the type system.
                        if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers)
                            throw new NotImplementedException();
 
                        var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeHierarchyType: null);
                        var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(diagnosticContext, reflectionAccessAnalyzer);
                        requireDynamicallyAccessedMembersAction.Invoke(sourceValue, targetWithDynamicallyAccessedMembers);
                    }
                }
            }
        }
    }
}