11using System . Collections ;
22using System . Collections . ObjectModel ;
3+ using System . Diagnostics . CodeAnalysis ;
34using System . Globalization ;
45using System . Linq ;
56using System . Reflection ;
7+ using System . Runtime . CompilerServices ;
68using System . Runtime . ExceptionServices ;
7- using System . Runtime . Serialization ;
89
910namespace ValveKeyValue
1011{
1112 // TODO: Migrate to IVisitationListener
1213 static class ObjectCopier
1314 {
14- public static TObject MakeObject < TObject > ( KVObject keyValueObject )
15+ public static TObject MakeObject < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TObject > ( KVObject keyValueObject )
1516 => MakeObject < TObject > ( keyValueObject , new DefaultObjectReflector ( ) ) ;
1617
17- public static object MakeObject ( Type objectType , KVObject keyValueObject , IObjectReflector reflector )
18+ public static object MakeObject (
19+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType , KVObject keyValueObject , IObjectReflector reflector )
1820 => InvokeGeneric ( nameof ( MakeObject ) , objectType , new object [ ] { keyValueObject , reflector } ) ;
1921
20- public static TObject MakeObject < TObject > ( KVObject keyValueObject , IObjectReflector reflector )
22+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2062" , Justification = "If the lookup value type exists at runtime then it should have enough for us to introspect." ) ]
23+ public static TObject MakeObject < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TObject > ( KVObject keyValueObject , IObjectReflector reflector )
2124 {
2225 Require . NotNull ( keyValueObject , nameof ( keyValueObject ) ) ;
2326 Require . NotNull ( reflector , nameof ( reflector ) ) ;
@@ -43,8 +46,8 @@ public static TObject MakeObject<TObject>(KVObject keyValueObject, IObjectReflec
4346
4447 // The object must remain boxed until it is fully initiallized, as this is the only way
4548 // that we can build a struct due to the nature of struct copying.
46- var typedObject = FormatterServices . GetUninitializedObject ( typeof ( TObject ) ) ;
47- CopyObject ( keyValueObject , typedObject , reflector ) ;
49+ var typedObject = RuntimeHelpers . GetUninitializedObject ( typeof ( TObject ) ) ;
50+ CopyObject ( keyValueObject , typeof ( TObject ) , typedObject , reflector ) ;
4851 return ( TObject ) typedObject ;
4952 }
5053 else if ( TryConvertValueTo < TObject > ( keyValueObject . Name , keyValueObject . Value , out var converted ) )
@@ -58,10 +61,18 @@ public static TObject MakeObject<TObject>(KVObject keyValueObject, IObjectReflec
5861 }
5962 }
6063
61- public static KVObject FromObject ( Type objectType , object managedObject , string topLevelName )
64+ public static KVObject FromObject (
65+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType ,
66+ object managedObject ,
67+ string topLevelName )
6268 => FromObjectCore ( objectType , managedObject , topLevelName , new DefaultObjectReflector ( ) , new HashSet < object > ( ) ) ;
6369
64- static KVObject FromObjectCore ( Type objectType , object managedObject , string topLevelName , IObjectReflector reflector , HashSet < object > visitedObjects )
70+ static KVObject FromObjectCore (
71+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType ,
72+ object managedObject ,
73+ string topLevelName ,
74+ IObjectReflector reflector ,
75+ HashSet < object > visitedObjects )
6576 {
6677 if ( managedObject == null )
6778 {
@@ -76,7 +87,12 @@ static KVObject FromObjectCore(Type objectType, object managedObject, string top
7687 return new KVObject ( topLevelName , transformedValue ) ;
7788 }
7889
79- static KVValue ConvertObjectToValue ( Type objectType , object managedObject , IObjectReflector reflector , HashSet < object > visitedObjects )
90+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2072" , Justification = "If the IDictionary's value object already exists at runtime then its properties will too." ) ]
91+ static KVValue ConvertObjectToValue (
92+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType ,
93+ object managedObject ,
94+ IObjectReflector reflector ,
95+ HashSet < object > visitedObjects )
8096 {
8197 if ( ! objectType . IsValueType && objectType != typeof ( string ) && ! visitedObjects . Add ( managedObject ) )
8298 {
@@ -108,38 +124,35 @@ static KVValue ConvertObjectToValue(Type objectType, object managedObject, IObje
108124 var counter = 0 ;
109125 foreach ( var child in ( IEnumerable ) managedObject )
110126 {
111- var childKVObject = CopyObject ( child , counter . ToString ( ) , reflector , visitedObjects ) ;
127+ var childKVObject = FromObjectCore ( child . GetType ( ) , child , counter . ToString ( ) , reflector , visitedObjects ) ;
112128 childObjects . Add ( childKVObject ) ;
113129
114130 counter ++ ;
115131 }
116132 }
117133 else
118134 {
119- foreach ( var member in reflector . GetMembers ( managedObject ) . OrderBy ( p => p . Name , StringComparer . InvariantCulture ) )
135+ foreach ( var member in reflector . GetMembers ( objectType , managedObject ) . OrderBy ( p => p . Name , StringComparer . InvariantCulture ) )
120136 {
121137 if ( ! member . MemberType . IsValueType && member . Value is null )
122138 {
123139 continue ;
124140 }
125141
126- childObjects . Add ( CopyObject ( member . Value , member . Name , reflector , visitedObjects ) ) ;
142+ childObjects . Add ( FromObjectCore ( member . Value . GetType ( ) , member . Value , member . Name , reflector , visitedObjects ) ) ;
127143 }
128144 }
129145
130146 return childObjects ;
131147 }
132148
133- static KVObject CopyObject ( object @object , string name , IObjectReflector reflector , HashSet < object > visitedObjects )
134- => FromObjectCore ( @object . GetType ( ) , @object , name , reflector , visitedObjects ) ;
135-
136- static void CopyObject ( KVObject kv , object obj , IObjectReflector reflector )
149+ static void CopyObject ( KVObject kv , [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType , object obj , IObjectReflector reflector )
137150 {
138151 Require . NotNull ( kv , nameof ( kv ) ) ;
139152 Require . NotNull ( obj , nameof ( obj ) ) ;
140153 Require . NotNull ( reflector , nameof ( reflector ) ) ;
141154
142- var members = reflector . GetMembers ( obj ) . ToDictionary ( m => m . Name , m => m , StringComparer . OrdinalIgnoreCase ) ;
155+ var members = reflector . GetMembers ( objectType , obj ) . ToDictionary ( m => m . Name , m => m , StringComparer . OrdinalIgnoreCase ) ;
143156
144157 foreach ( var item in kv . Children )
145158 {
@@ -148,7 +161,8 @@ static void CopyObject(KVObject kv, object obj, IObjectReflector reflector)
148161 continue ;
149162 }
150163
151- member . Value = MakeObject ( member . MemberType , item , reflector ) ;
164+ var convertedValue = MakeObject ( member . MemberType , item , reflector ) ;
165+ member . Value = convertedValue ;
152166 }
153167 }
154168
@@ -208,11 +222,18 @@ static bool IsLookupWithStringKey(Type type, out Type valueType)
208222 return true ;
209223 }
210224
211- static object MakeLookup ( Type valueType , IEnumerable < KVObject > items , IObjectReflector reflector )
225+ static object MakeLookup (
226+ [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] Type valueType ,
227+ IEnumerable < KVObject > items ,
228+ IObjectReflector reflector )
212229 => InvokeGeneric ( nameof ( MakeLookupCore ) , valueType , new object [ ] { items , reflector } ) ;
213230
214- static ILookup < string , TValue > MakeLookupCore < TValue > ( IEnumerable < KVObject > items , IObjectReflector reflector )
215- => items . ToLookup ( kv => kv . Name , kv => ConvertValue < TValue > ( kv . Value , reflector ) ) ;
231+ static ILookup < string , TValue > MakeLookupCore < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TValue > ( IEnumerable < KVObject > items , IObjectReflector reflector )
232+ {
233+ TValue valueConversionFunc ( KVObject kv ) => ConvertValue < TValue > ( kv . Value , reflector ) ;
234+
235+ return items . ToLookup ( kv => kv . Name , valueConversionFunc ) ;
236+ }
216237
217238 static readonly Dictionary < Type , Func < Type , object [ ] , IObjectReflector , object > > EnumerableBuilders = new ( )
218239 {
@@ -223,7 +244,13 @@ static ILookup<string, TValue> MakeLookupCore<TValue>(IEnumerable<KVObject> item
223244 [ typeof ( ObservableCollection < > ) ] = ( type , values , reflector ) => InvokeGeneric ( nameof ( MakeObservableCollection ) , type . GetGenericArguments ( ) [ 0 ] , new object [ ] { values , reflector } ) ,
224245 } ;
225246
226- static bool ConstructTypedEnumerable ( Type type , object [ ] values , IObjectReflector reflector , out object typedEnumerable )
247+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2072" , Justification = "If our T[] array exists then so much the element T." ) ]
248+ [ UnconditionalSuppressMessage ( "AOT" , "IL3050" , Justification = "If our T[] array exists then so much the element T." ) ]
249+ static bool ConstructTypedEnumerable (
250+ Type type ,
251+ object [ ] values ,
252+ IObjectReflector reflector ,
253+ out object typedEnumerable )
227254 {
228255 object listObject = null ;
229256
@@ -274,6 +301,9 @@ static bool IsConstructibleEnumerableType(Type type)
274301 return false ;
275302 }
276303
304+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2060" , Justification = "Analysis cannot follow MakeGenericMethod. All callers validated manually." ) ]
305+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2111" , Justification = "Analysis cannot follow MakeGenericMethod. All callers validated manually." ) ]
306+ [ UnconditionalSuppressMessage ( "AOT" , "IL3050" , Justification = "Analysis cannot follow MakeGenericMethod. All callers validated manually." ) ]
277307 static object InvokeGeneric ( string methodName , Type genericType , params object [ ] parameters )
278308 {
279309 var method = typeof ( ObjectCopier )
@@ -292,18 +322,22 @@ static object InvokeGeneric(string methodName, Type genericType, params object[]
292322 }
293323 }
294324
295- static List < TElement > MakeList < TElement > ( object [ ] items , IObjectReflector reflector )
325+ static List < TElement > MakeList < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TElement > ( object [ ] items , IObjectReflector reflector )
296326 {
297- return items . Select ( i => ConvertValue < TElement > ( i , reflector ) )
298- . ToList ( ) ;
327+ var list = new List < TElement > ( capacity : items . Length ) ;
328+ foreach ( var item in items )
329+ {
330+ list . Add ( ConvertValue < TElement > ( item , reflector ) ) ;
331+ }
332+ return list ;
299333 }
300334
301- static Collection < TElement > MakeCollection < TElement > ( object [ ] items , IObjectReflector reflector )
335+ static Collection < TElement > MakeCollection < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TElement > ( object [ ] items , IObjectReflector reflector )
302336 {
303337 return new Collection < TElement > ( MakeList < TElement > ( items , reflector ) ) ;
304338 }
305339
306- static ObservableCollection < TElement > MakeObservableCollection < TElement > ( object [ ] items , IObjectReflector reflector )
340+ static ObservableCollection < TElement > MakeObservableCollection < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TElement > ( object [ ] items , IObjectReflector reflector )
307341 {
308342 return new ObservableCollection < TElement > ( MakeList < TElement > ( items , reflector ) ) ;
309343 }
@@ -334,20 +368,25 @@ static bool IsDictionary(Type type)
334368 return true ;
335369 }
336370
337- static object MakeDictionary ( Type type , KVObject kv , IObjectReflector reflector )
371+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2060" , Justification = "Analysis cannot follow MakeGenericMethod but we should be clear by here anyway." ) ]
372+ [ UnconditionalSuppressMessage ( "AOT" , "IL3050" , Justification = "Analysis cannot follow MakeGenericMethod but we should be clear by here anyway." ) ]
373+ static object MakeDictionary (
374+ [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] Type type ,
375+ KVObject kv ,
376+ IObjectReflector reflector )
338377 {
339378 var dictionary = Activator . CreateInstance ( type ) ;
340379 var genericArguments = type . GetGenericArguments ( ) ;
341380
342- typeof ( ObjectCopier )
343- . GetMethod ( nameof ( FillDictionary ) , BindingFlags . Static | BindingFlags . NonPublic )
344- . MakeGenericMethod ( genericArguments )
381+ var method = typeof ( ObjectCopier )
382+ . GetMethod ( nameof ( FillDictionary ) , BindingFlags . Static | BindingFlags . NonPublic ) ;
383+ method . MakeGenericMethod ( genericArguments )
345384 . Invoke ( null , new [ ] { dictionary , kv , reflector } ) ;
346385
347386 return dictionary ;
348387 }
349388
350- static void FillDictionary < TKey , TValue > ( Dictionary < TKey , TValue > dictionary , KVObject kv , IObjectReflector reflector )
389+ static void FillDictionary < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TKey , [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TValue > ( Dictionary < TKey , TValue > dictionary , KVObject kv , IObjectReflector reflector )
351390 {
352391 foreach ( var item in kv . Children )
353392 {
@@ -363,9 +402,13 @@ static void FillDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary, KV
363402 }
364403 }
365404
366- static TValue ConvertValue < TValue > ( object value , IObjectReflector reflector ) => ( TValue ) ConvertValue ( value , typeof ( TValue ) , reflector ) ;
405+ static TValue ConvertValue < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TValue > ( object value , IObjectReflector reflector )
406+ => ( TValue ) ConvertValue ( value , typeof ( TValue ) , reflector ) ;
367407
368- static object ConvertValue ( object value , Type valueType , IObjectReflector reflector )
408+ static object ConvertValue (
409+ object value ,
410+ [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] Type valueType ,
411+ IObjectReflector reflector )
369412 {
370413 if ( value is KVCollectionValue collectionValue )
371414 {
0 commit comments