| File: Compiler\Dataflow\AttributeDataFlow.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection.Metadata; using ILCompiler.DependencyAnalysis; using ILCompiler.Logging; using ILLink.Shared.TrimAnalysis; using Internal.TypeSystem; using CustomAttributeValue = System.Reflection.Metadata.CustomAttributeValue<Internal.TypeSystem.TypeDesc>; using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList; using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>; #nullable enable namespace ILCompiler.Dataflow { public readonly struct AttributeDataFlow { private readonly Logger _logger; private readonly NodeFactory _factory; private readonly FlowAnnotations _annotations; private readonly MessageOrigin _origin; private readonly DiagnosticContext _diagnosticContext; public AttributeDataFlow(Logger logger, NodeFactory factory, FlowAnnotations annotations, in MessageOrigin origin) { _annotations = annotations; _factory = factory; _logger = logger; _origin = origin; _diagnosticContext = new DiagnosticContext( _origin, _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute), _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresDynamicCodeAttribute), _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute), _logger); } public DependencyList? ProcessAttributeDataflow(MethodDesc method, CustomAttributeValue arguments) { DependencyList? result = null; ReflectionMethodBodyScanner.CheckAndReportAllRequires(_diagnosticContext, method); // First do the dataflow for the constructor parameters if necessary. if (_annotations.RequiresDataflowAnalysisDueToSignature(method)) { var builder = ImmutableArray.CreateBuilder<object?>(arguments.FixedArguments.Length); foreach (var argument in arguments.FixedArguments) { builder.Add(argument.Value); } ProcessAttributeDataflow(method, builder.ToImmutableArray(), ref result); } // Named arguments next TypeDesc attributeType = method.OwningType; foreach (var namedArgument in arguments.NamedArguments) { if (namedArgument.Kind == CustomAttributeNamedArgumentKind.Field) { FieldDesc field = attributeType.GetField(System.Text.Encoding.UTF8.GetBytes(namedArgument.Name!)); if (field != null) { ReflectionMethodBodyScanner.CheckAndReportAllRequires(_diagnosticContext, field); ProcessAttributeDataflow(field, namedArgument.Value, ref result); } } else { Debug.Assert(namedArgument.Kind == CustomAttributeNamedArgumentKind.Property); PropertyPseudoDesc property = ((MetadataType)attributeType).GetProperty(namedArgument.Name, null); MethodDesc setter = property.SetMethod; if (setter != null && setter.Signature.Length > 0 && !setter.Signature.IsStatic) { ReflectionMethodBodyScanner.CheckAndReportAllRequires(_diagnosticContext, setter); ProcessAttributeDataflow(setter, ImmutableArray.Create(namedArgument.Value), ref result); } } } return result; } private void ProcessAttributeDataflow(MethodDesc method, ImmutableArray<object?> arguments, ref DependencyList? result) { foreach (var parameter in method.GetMetadataParameters()) { var parameterValue = _annotations.GetMethodParameterValue(parameter); if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { MultiValue value = GetValueForCustomAttributeArgument(arguments[parameter.MetadataIndex]); RequireDynamicallyAccessedMembers(_diagnosticContext, value, parameterValue, method, ref result); } } } private void ProcessAttributeDataflow(FieldDesc field, object? value, ref DependencyList? result) { var fieldValueCandidate = _annotations.GetFieldValue(field); if (fieldValueCandidate is ValueWithDynamicallyAccessedMembers fieldValue && fieldValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { MultiValue valueNode = GetValueForCustomAttributeArgument(value); RequireDynamicallyAccessedMembers(_diagnosticContext, valueNode, fieldValue, field, ref result); } } private static MultiValue GetValueForCustomAttributeArgument(object? argument) => argument switch { TypeDesc td => new SystemTypeValue(td), string str => new KnownStringValue(str), null => NullValue.Instance, // We shouldn't have gotten a None annotation from flow annotations since only string/Type can have annotations _ => throw new InvalidOperationException() }; private void RequireDynamicallyAccessedMembers( in DiagnosticContext diagnosticContext, in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue, TypeSystemEntity reason, ref DependencyList? result) { var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlowOrigin: null, enabled: true); var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, reason); requireDynamicallyAccessedMembersAction.Invoke(value, targetValue); if (result == null) { result = reflectionMarker.Dependencies; } else { result.AddRange(reflectionMarker.Dependencies); } } } }