1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
using System;
using System.Diagnostics.CodeAnalysis;
using Mono.Cecil;
#nullable enable
namespace Mono.Linker
{
/// Tracks dependencies created via DynamicDependencyAttribute in the linker.
/// This is almost identical to DynamicDependencyAttribute, but it holds a
/// TypeReference instead of a Type, and it has a reference to the original
/// CustomAttribute for dependency tracing. It is also a place for helper
/// methods related to the attribute.
[System.AttributeUsage (System.AttributeTargets.Constructor | System.AttributeTargets.Field | System.AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
internal class DynamicDependency : Attribute
{
public CustomAttribute? OriginalAttribute { get; private set; }
public DynamicDependency (string memberSignature)
{
MemberSignature = memberSignature;
}
public DynamicDependency (string memberSignature, TypeReference type)
{
MemberSignature = memberSignature;
Type = type;
}
public DynamicDependency (string memberSignature, string typeName, string assemblyName)
{
MemberSignature = memberSignature;
TypeName = typeName;
AssemblyName = assemblyName;
}
public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, TypeReference type)
{
MemberTypes = memberTypes;
Type = type;
}
public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName)
{
MemberTypes = memberTypes;
TypeName = typeName;
AssemblyName = assemblyName;
}
public string? MemberSignature { get; }
public DynamicallyAccessedMemberTypes MemberTypes { get; }
public TypeReference? Type { get; }
public string? TypeName { get; }
public string? AssemblyName { get; }
public string? Condition { get; set; }
public static DynamicDependency? ProcessAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute)
{
if (!(provider is IMemberDefinition member))
return null;
if (!(member is MethodDefinition || member is FieldDefinition))
return null;
// Don't honor the Condition until we have figured out the behavior for DynamicDependencyAttribute:
// https://github.com/mono/linker/issues/1231
// if (!ShouldProcess (context, customAttribute))
// return null;
var dynamicDependency = GetDynamicDependency (customAttribute);
if (dynamicDependency != null)
return dynamicDependency;
context.LogWarning ($"The 'DynamicDependencyAttribute' could not be analyzed.", 2034, member);
return null;
}
static DynamicDependency? GetDynamicDependency (CustomAttribute ca)
{
var args = ca.ConstructorArguments;
if (args.Count < 1 || args.Count > 3)
return null;
DynamicDependency? result = args[0].Value switch {
string stringMemberSignature => args.Count switch {
1 => new DynamicDependency (stringMemberSignature),
2 when args[1].Value is TypeReference type => new DynamicDependency (stringMemberSignature, type),
3 when args[1].Value is string typeName && args[2].Value is string assemblyName => new DynamicDependency (stringMemberSignature, typeName, assemblyName),
_ => null,
},
int memberTypes => args.Count switch {
2 when args[1].Value is TypeReference type => new DynamicDependency ((DynamicallyAccessedMemberTypes) memberTypes, type),
3 when args[1].Value is string typeName && args[2].Value is string assemblyName => new DynamicDependency ((DynamicallyAccessedMemberTypes) memberTypes, typeName, assemblyName),
_ => null,
},
_ => null,
};
if (result != null)
result.OriginalAttribute = ca;
return result;
}
public static bool ShouldProcess (LinkContext context, CustomAttribute ca)
{
if (ca.HasProperties && ca.Properties[0].Name == "Condition") {
var condition = ca.Properties[0].Argument.Value as string;
switch (condition) {
case "":
case null:
return true;
case "DEBUG":
if (!context.KeepMembersForDebugger)
return false;
break;
default:
// Don't have yet a way to match the general condition so everything is excluded
return false;
}
}
return true;
}
}
}
|