7
7
using ILLink . RoslynAnalyzer ;
8
8
using ILLink . RoslynAnalyzer . DataFlow ;
9
9
using ILLink . RoslynAnalyzer . TrimAnalysis ;
10
+ using ILLink . Shared . DataFlow ;
10
11
using ILLink . Shared . TypeSystemProxy ;
11
12
using Microsoft . CodeAnalysis ;
13
+ using Microsoft . CodeAnalysis . Operations ;
14
+ using MultiValue = ILLink . Shared . DataFlow . ValueSet < ILLink . Shared . DataFlow . SingleValue > ;
12
15
13
16
namespace ILLink . Shared . TrimAnalysis
14
17
{
@@ -20,15 +23,124 @@ internal partial struct HandleCallAction
20
23
readonly ISymbol _owningSymbol ;
21
24
readonly IOperation _operation ;
22
25
readonly ReflectionAccessAnalyzer _reflectionAccessAnalyzer ;
26
+ ValueSetLattice < SingleValue > _multiValueLattice ;
23
27
24
- public HandleCallAction ( in DiagnosticContext diagnosticContext , ISymbol owningSymbol , IOperation operation )
28
+ public HandleCallAction (
29
+ in DiagnosticContext diagnosticContext ,
30
+ ISymbol owningSymbol ,
31
+ IOperation operation ,
32
+ ValueSetLattice < SingleValue > multiValueLattice )
25
33
{
26
34
_owningSymbol = owningSymbol ;
27
35
_operation = operation ;
28
36
_diagnosticContext = diagnosticContext ;
29
37
_annotations = FlowAnnotations . Instance ;
30
38
_reflectionAccessAnalyzer = default ;
31
39
_requireDynamicallyAccessedMembersAction = new ( diagnosticContext , _reflectionAccessAnalyzer ) ;
40
+ _multiValueLattice = multiValueLattice ;
41
+ }
42
+
43
+ private partial bool TryHandleIntrinsic (
44
+ MethodProxy calledMethod ,
45
+ MultiValue instanceValue ,
46
+ IReadOnlyList < MultiValue > argumentValues ,
47
+ IntrinsicId intrinsicId ,
48
+ out MultiValue ? methodReturnValue )
49
+ {
50
+ MultiValue ? maybeMethodReturnValue = methodReturnValue = null ;
51
+ ValueSetLattice < SingleValue > multiValueLattice = _multiValueLattice ;
52
+
53
+ switch ( intrinsicId ) {
54
+ case IntrinsicId . Array_Empty :
55
+ AddReturnValue ( ArrayValue . Create ( 0 ) ) ;
56
+ break ;
57
+
58
+ case IntrinsicId . TypeDelegator_Ctor :
59
+ if ( _operation is IObjectCreationOperation )
60
+ AddReturnValue ( argumentValues [ 0 ] ) ;
61
+
62
+ break ;
63
+
64
+ case IntrinsicId . Object_GetType : {
65
+ foreach ( var valueNode in instanceValue . AsEnumerable ( ) ) {
66
+ // Note that valueNode can be statically typed as some generic argument type.
67
+ // For example:
68
+ // void Method<T>(T instance) { instance.GetType().... }
69
+ // But it could be that T is annotated with for example PublicMethods:
70
+ // void Method<[DAM(PublicMethods)] T>(T instance) { instance.GetType().GetMethod("Test"); }
71
+ // In this case it's in theory possible to handle it, by treating the T basically as a base class
72
+ // for the actual type of "instance". But the analysis for this would be pretty complicated (as the marking
73
+ // has to happen on the callsite, which doesn't know that GetType() will be used...).
74
+ // For now we're intentionally ignoring this case - it will produce a warning.
75
+ // The counter example is:
76
+ // Method<Base>(new Derived);
77
+ // In this case to get correct results, trimmer would have to mark all public methods on Derived. Which
78
+ // currently it won't do.
79
+
80
+ // To emulate IL tools behavior (trimmer, NativeAOT compiler), we're going to intentionally "forget" the static type
81
+ // if it is a generic argument type.
82
+
83
+ ITypeSymbol ? staticType = ( valueNode as IValueWithStaticType ) ? . StaticType ? . Type ;
84
+ if ( staticType ? . TypeKind == TypeKind . TypeParameter )
85
+ staticType = null ;
86
+
87
+ if ( staticType is null ) {
88
+ // We don't know anything about the type GetType was called on. Track this as a usual "result of a method call without any annotations"
89
+ AddReturnValue ( FlowAnnotations . Instance . GetMethodReturnValue ( calledMethod ) ) ;
90
+ } else if ( staticType . IsSealed || staticType . IsTypeOf ( "System" , "Delegate" ) || staticType . TypeKind == TypeKind . Array ) {
91
+ // We can treat this one the same as if it was a typeof() expression
92
+
93
+ // We can allow Object.GetType to be modeled as System.Delegate because we keep all methods
94
+ // on delegates anyway so reflection on something this approximation would miss is actually safe.
95
+
96
+ // We can also treat all arrays as "sealed" since it's not legal to derive from Array type (even though it is not sealed itself)
97
+
98
+ // We ignore the fact that the type can be annotated (see below for handling of annotated types)
99
+ // This means the annotations (if any) won't be applied - instead we rely on the exact knowledge
100
+ // of the type. So for example even if the type is annotated with PublicMethods
101
+ // but the code calls GetProperties on it - it will work - mark properties, don't mark methods
102
+ // since we ignored the fact that it's annotated.
103
+ // This can be seen a little bit as a violation of the annotation, but we already have similar cases
104
+ // where a parameter is annotated and if something in the method sets a specific known type to it
105
+ // we will also make it just work, even if the annotation doesn't match the usage.
106
+ AddReturnValue ( new SystemTypeValue ( new ( staticType ) ) ) ;
107
+ } else {
108
+ var annotation = FlowAnnotations . GetTypeAnnotation ( staticType ) ;
109
+ AddReturnValue ( FlowAnnotations . Instance . GetMethodReturnValue ( calledMethod , annotation ) ) ;
110
+ }
111
+ }
112
+ break ;
113
+ }
114
+
115
+ // Some intrinsics are unimplemented by the analyzer.
116
+ // These will fall back to the usual return-value handling.
117
+ case IntrinsicId . Array_CreateInstance :
118
+ case IntrinsicId . Assembly_GetFile :
119
+ case IntrinsicId . Assembly_GetFiles :
120
+ case IntrinsicId . AssemblyName_get_EscapedCodeBase :
121
+ case IntrinsicId . Assembly_get_Location :
122
+ case IntrinsicId . AssemblyName_get_CodeBase :
123
+ case IntrinsicId . Delegate_get_Method :
124
+ case IntrinsicId . Enum_GetValues :
125
+ case IntrinsicId . Marshal_DestroyStructure :
126
+ case IntrinsicId . Marshal_GetDelegateForFunctionPointer :
127
+ case IntrinsicId . Marshal_OffsetOf :
128
+ case IntrinsicId . Marshal_PtrToStructure :
129
+ case IntrinsicId . Marshal_SizeOf :
130
+ case IntrinsicId . RuntimeReflectionExtensions_GetMethodInfo :
131
+ break ;
132
+
133
+ default :
134
+ return false ;
135
+ }
136
+
137
+ methodReturnValue = maybeMethodReturnValue ;
138
+ return true ;
139
+
140
+ void AddReturnValue ( MultiValue value )
141
+ {
142
+ maybeMethodReturnValue = ( maybeMethodReturnValue is null ) ? value : multiValueLattice . Meet ( ( MultiValue ) maybeMethodReturnValue , value ) ;
143
+ }
32
144
}
33
145
34
146
private partial IEnumerable < SystemReflectionMethodBaseValue > GetMethodsOnTypeHierarchy ( TypeProxy type , string name , BindingFlags ? bindingFlags )
0 commit comments