|
// 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);
}
}
}
|