|
// 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.CodeAnalysis;
using ILLink.Shared.TrimAnalysis;
using Mono.Cecil;
using Mono.Linker.Steps;
using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
namespace Mono.Linker.Dataflow
{
public readonly struct AttributeDataFlow
{
readonly LinkContext _context;
readonly MarkStep _markStep;
readonly MessageOrigin _origin;
public AttributeDataFlow(LinkContext context, MarkStep markStep, in MessageOrigin origin)
{
_context = context;
_markStep = markStep;
_origin = origin;
}
public void ProcessAttributeDataflow(MethodDefinition method, IList<CustomAttributeArgument> arguments)
{
foreach (var parameter in method.GetMetadataParameters())
{
var parameterValue = _context.Annotations.FlowAnnotations.GetMethodParameterValue(parameter);
if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None)
{
MultiValue value = GetValueForCustomAttributeArgument(arguments[parameter.MetadataIndex]);
var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _context);
RequireDynamicallyAccessedMembers(diagnosticContext, value, parameterValue);
}
}
}
public void ProcessAttributeDataflow(FieldDefinition field, CustomAttributeArgument value)
{
MultiValue valueNode = GetValueForCustomAttributeArgument(value);
var fieldValueCandidate = _context.Annotations.FlowAnnotations.GetFieldValue(field);
if (fieldValueCandidate is not ValueWithDynamicallyAccessedMembers fieldValue)
return;
var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _context);
RequireDynamicallyAccessedMembers(diagnosticContext, valueNode, fieldValue);
}
MultiValue GetValueForCustomAttributeArgument(CustomAttributeArgument argument)
{
if (argument.Type.Name == "Type")
{
if (argument.Value is null)
return NullValue.Instance;
TypeDefinition? referencedType = ((TypeReference)argument.Value).ResolveToTypeDefinition(_context);
return referencedType == null
? UnknownValue.Instance
: new SystemTypeValue(new(referencedType, _context));
}
if (argument.Type.MetadataType == MetadataType.String)
return argument.Value is null ? NullValue.Instance : new KnownStringValue((string)argument.Value);
// We shouldn't have gotten a non-null annotation for this from GetParameterAnnotation
throw new InvalidOperationException();
}
void RequireDynamicallyAccessedMembers(in DiagnosticContext diagnosticContext, in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue)
{
var reflectionMarker = new ReflectionMarker(_context, _markStep, enabled: true);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(_context, reflectionMarker, diagnosticContext);
requireDynamicallyAccessedMembersAction.Invoke(value, targetValue);
}
}
}
|