77using  ILLink . RoslynAnalyzer ; 
88using  ILLink . RoslynAnalyzer . DataFlow ; 
99using  ILLink . RoslynAnalyzer . TrimAnalysis ; 
10+ using  ILLink . Shared . DataFlow ; 
1011using  ILLink . Shared . TypeSystemProxy ; 
1112using  Microsoft . CodeAnalysis ; 
13+ using  Microsoft . CodeAnalysis . Operations ; 
14+ using  MultiValue  =  ILLink . Shared . DataFlow . ValueSet < ILLink . Shared . DataFlow . SingleValue > ; 
1215
1316namespace  ILLink . Shared . TrimAnalysis 
1417{ 
@@ -20,15 +23,124 @@ internal partial struct HandleCallAction
2023		readonly  ISymbol  _owningSymbol ; 
2124		readonly  IOperation  _operation ; 
2225		readonly  ReflectionAccessAnalyzer  _reflectionAccessAnalyzer ; 
26+ 		ValueSetLattice < SingleValue >  _multiValueLattice ; 
2327
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 ) 
2533		{ 
2634			_owningSymbol  =  owningSymbol ; 
2735			_operation  =  operation ; 
2836			_diagnosticContext  =  diagnosticContext ; 
2937			_annotations  =  FlowAnnotations . Instance ; 
3038			_reflectionAccessAnalyzer  =  default ; 
3139			_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+ 			} 
32144		} 
33145
34146		private  partial  IEnumerable < SystemReflectionMethodBaseValue >  GetMethodsOnTypeHierarchy  ( TypeProxy  type ,  string  name ,  BindingFlags ?  bindingFlags ) 
0 commit comments