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+ public static TObject MakeObject < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TObject > ( KVObject keyValueObject , IObjectReflector reflector )
2123 {
2224 Require . NotNull ( keyValueObject , nameof ( keyValueObject ) ) ;
2325 Require . NotNull ( reflector , nameof ( reflector ) ) ;
@@ -43,7 +45,7 @@ public static TObject MakeObject<TObject>(KVObject keyValueObject, IObjectReflec
4345
4446 // The object must remain boxed until it is fully initiallized, as this is the only way
4547 // that we can build a struct due to the nature of struct copying.
46- var typedObject = FormatterServices . GetUninitializedObject ( typeof ( TObject ) ) ;
48+ var typedObject = RuntimeHelpers . GetUninitializedObject ( typeof ( TObject ) ) ;
4749 CopyObject ( keyValueObject , typedObject , reflector ) ;
4850 return ( TObject ) typedObject ;
4951 }
@@ -58,10 +60,18 @@ public static TObject MakeObject<TObject>(KVObject keyValueObject, IObjectReflec
5860 }
5961 }
6062
61- public static KVObject FromObject ( Type objectType , object managedObject , string topLevelName )
63+ public static KVObject FromObject (
64+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType ,
65+ object managedObject ,
66+ string topLevelName )
6267 => FromObjectCore ( objectType , managedObject , topLevelName , new DefaultObjectReflector ( ) , new HashSet < object > ( ) ) ;
6368
64- static KVObject FromObjectCore ( Type objectType , object managedObject , string topLevelName , IObjectReflector reflector , HashSet < object > visitedObjects )
69+ static KVObject FromObjectCore (
70+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType ,
71+ object managedObject ,
72+ string topLevelName ,
73+ IObjectReflector reflector ,
74+ HashSet < object > visitedObjects )
6575 {
6676 if ( managedObject == null )
6777 {
@@ -76,7 +86,11 @@ static KVObject FromObjectCore(Type objectType, object managedObject, string top
7686 return new KVObject ( topLevelName , transformedValue ) ;
7787 }
7888
79- static KVValue ConvertObjectToValue ( Type objectType , object managedObject , IObjectReflector reflector , HashSet < object > visitedObjects )
89+ static KVValue ConvertObjectToValue (
90+ [ DynamicallyAccessedMembers ( Trimming . Properties ) ] Type objectType ,
91+ object managedObject ,
92+ IObjectReflector reflector ,
93+ HashSet < object > visitedObjects )
8094 {
8195 if ( ! objectType . IsValueType && objectType != typeof ( string ) && ! visitedObjects . Add ( managedObject ) )
8296 {
@@ -108,38 +122,40 @@ static KVValue ConvertObjectToValue(Type objectType, object managedObject, IObje
108122 var counter = 0 ;
109123 foreach ( var child in ( IEnumerable ) managedObject )
110124 {
111- var childKVObject = CopyObject ( child , counter . ToString ( ) , reflector , visitedObjects ) ;
125+ var childKVObject = FromObjectCore ( child . GetType ( ) , child , counter . ToString ( ) , reflector , visitedObjects ) ;
112126 childObjects . Add ( childKVObject ) ;
113127
114128 counter ++ ;
115129 }
116130 }
117131 else
118132 {
119- foreach ( var member in reflector . GetMembers ( managedObject ) . OrderBy ( p => p . Name , StringComparer . InvariantCulture ) )
133+ foreach ( var member in reflector . GetMembers ( objectType , managedObject ) . OrderBy ( p => p . Name , StringComparer . InvariantCulture ) )
120134 {
121135 if ( ! member . MemberType . IsValueType && member . Value is null )
122136 {
123137 continue ;
124138 }
125139
126- childObjects . Add ( CopyObject ( member . Value , member . Name , reflector , visitedObjects ) ) ;
140+ childObjects . Add ( FromObjectCore ( member . Value . GetType ( ) , member . Value , member . Name , reflector , visitedObjects ) ) ;
127141 }
128142 }
129143
130144 return childObjects ;
131145 }
132146
133- static KVObject CopyObject ( object @object , string name , IObjectReflector reflector , HashSet < object > visitedObjects )
134- => FromObjectCore ( @object . GetType ( ) , @object , name , reflector , visitedObjects ) ;
135-
136147 static void CopyObject ( KVObject kv , object obj , IObjectReflector reflector )
137148 {
138149 Require . NotNull ( kv , nameof ( kv ) ) ;
139- Require . NotNull ( obj , nameof ( obj ) ) ;
150+
151+ if ( obj is null )
152+ {
153+ throw new ArgumentNullException ( nameof ( obj ) ) ;
154+ }
155+
140156 Require . NotNull ( reflector , nameof ( reflector ) ) ;
141157
142- var members = reflector . GetMembers ( obj ) . ToDictionary ( m => m . Name , m => m , StringComparer . OrdinalIgnoreCase ) ;
158+ var members = reflector . GetMembers ( obj . GetType ( ) , obj ) . ToDictionary ( m => m . Name , m => m , StringComparer . OrdinalIgnoreCase ) ;
143159
144160 foreach ( var item in kv . Children )
145161 {
@@ -148,7 +164,8 @@ static void CopyObject(KVObject kv, object obj, IObjectReflector reflector)
148164 continue ;
149165 }
150166
151- member . Value = MakeObject ( member . MemberType , item , reflector ) ;
167+ var convertedValue = MakeObject ( member . MemberType , item , reflector ) ;
168+ member . Value = convertedValue ;
152169 }
153170 }
154171
@@ -208,11 +225,18 @@ static bool IsLookupWithStringKey(Type type, out Type valueType)
208225 return true ;
209226 }
210227
211- static object MakeLookup ( Type valueType , IEnumerable < KVObject > items , IObjectReflector reflector )
228+ static object MakeLookup (
229+ [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] Type valueType ,
230+ IEnumerable < KVObject > items ,
231+ IObjectReflector reflector )
212232 => InvokeGeneric ( nameof ( MakeLookupCore ) , valueType , new object [ ] { items , reflector } ) ;
213233
214- static ILookup < string , TValue > MakeLookupCore < TValue > ( IEnumerable < KVObject > items , IObjectReflector reflector )
215- => items . ToLookup ( kv => kv . Name , kv => ConvertValue < TValue > ( kv . Value , reflector ) ) ;
234+ static ILookup < string , TValue > MakeLookupCore < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TValue > ( IEnumerable < KVObject > items , IObjectReflector reflector )
235+ {
236+ TValue valueConversionFunc ( KVObject kv ) => ConvertValue < TValue > ( kv . Value , reflector ) ;
237+
238+ return items . ToLookup ( kv => kv . Name , valueConversionFunc ) ;
239+ }
216240
217241 static readonly Dictionary < Type , Func < Type , object [ ] , IObjectReflector , object > > EnumerableBuilders = new ( )
218242 {
@@ -223,7 +247,13 @@ static ILookup<string, TValue> MakeLookupCore<TValue>(IEnumerable<KVObject> item
223247 [ typeof ( ObservableCollection < > ) ] = ( type , values , reflector ) => InvokeGeneric ( nameof ( MakeObservableCollection ) , type . GetGenericArguments ( ) [ 0 ] , new object [ ] { values , reflector } ) ,
224248 } ;
225249
226- static bool ConstructTypedEnumerable ( Type type , object [ ] values , IObjectReflector reflector , out object typedEnumerable )
250+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2072" , Justification = "If our T[] array exists then so much the element T." ) ]
251+ [ UnconditionalSuppressMessage ( "AOT" , "IL3050" , Justification = "If our T[] array exists then so much the element T." ) ]
252+ static bool ConstructTypedEnumerable (
253+ Type type ,
254+ object [ ] values ,
255+ IObjectReflector reflector ,
256+ out object typedEnumerable )
227257 {
228258 object listObject = null ;
229259
@@ -274,6 +304,9 @@ static bool IsConstructibleEnumerableType(Type type)
274304 return false ;
275305 }
276306
307+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2060" , Justification = "Analysis cannot follow MakeGenericMethod. All callers validated manually." ) ]
308+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2111" , Justification = "Analysis cannot follow MakeGenericMethod. All callers validated manually." ) ]
309+ [ UnconditionalSuppressMessage ( "AOT" , "IL3050" , Justification = "Analysis cannot follow MakeGenericMethod. All callers validated manually." ) ]
277310 static object InvokeGeneric ( string methodName , Type genericType , params object [ ] parameters )
278311 {
279312 var method = typeof ( ObjectCopier )
@@ -292,18 +325,22 @@ static object InvokeGeneric(string methodName, Type genericType, params object[]
292325 }
293326 }
294327
295- static List < TElement > MakeList < TElement > ( object [ ] items , IObjectReflector reflector )
328+ static List < TElement > MakeList < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TElement > ( object [ ] items , IObjectReflector reflector )
296329 {
297- return items . Select ( i => ConvertValue < TElement > ( i , reflector ) )
298- . ToList ( ) ;
330+ var list = new List < TElement > ( capacity : items . Length ) ;
331+ foreach ( var item in items )
332+ {
333+ list . Add ( ConvertValue < TElement > ( item , reflector ) ) ;
334+ }
335+ return list ;
299336 }
300337
301- static Collection < TElement > MakeCollection < TElement > ( object [ ] items , IObjectReflector reflector )
338+ static Collection < TElement > MakeCollection < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TElement > ( object [ ] items , IObjectReflector reflector )
302339 {
303340 return new Collection < TElement > ( MakeList < TElement > ( items , reflector ) ) ;
304341 }
305342
306- static ObservableCollection < TElement > MakeObservableCollection < TElement > ( object [ ] items , IObjectReflector reflector )
343+ static ObservableCollection < TElement > MakeObservableCollection < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TElement > ( object [ ] items , IObjectReflector reflector )
307344 {
308345 return new ObservableCollection < TElement > ( MakeList < TElement > ( items , reflector ) ) ;
309346 }
@@ -334,20 +371,26 @@ static bool IsDictionary(Type type)
334371 return true ;
335372 }
336373
337- static object MakeDictionary ( Type type , KVObject kv , IObjectReflector reflector )
374+ [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2060" , Justification = "Analysis cannot follow MakeGenericMethod but we should be clear by here anyway." ) ]
375+ [ UnconditionalSuppressMessage ( "AOT" , "IL3050" , Justification = "Analysis cannot follow MakeGenericMethod but we should be clear by here anyway." ) ]
376+ static object MakeDictionary (
377+ [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ]
378+ Type type ,
379+ KVObject kv ,
380+ IObjectReflector reflector )
338381 {
339382 var dictionary = Activator . CreateInstance ( type ) ;
340383 var genericArguments = type . GetGenericArguments ( ) ;
341384
342- typeof ( ObjectCopier )
343- . GetMethod ( nameof ( FillDictionary ) , BindingFlags . Static | BindingFlags . NonPublic )
344- . MakeGenericMethod ( genericArguments )
385+ var method = typeof ( ObjectCopier )
386+ . GetMethod ( nameof ( FillDictionary ) , BindingFlags . Static | BindingFlags . NonPublic ) ;
387+ method . MakeGenericMethod ( genericArguments )
345388 . Invoke ( null , new [ ] { dictionary , kv , reflector } ) ;
346389
347390 return dictionary ;
348391 }
349392
350- static void FillDictionary < TKey , TValue > ( Dictionary < TKey , TValue > dictionary , KVObject kv , IObjectReflector reflector )
393+ static void FillDictionary < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TKey , [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TValue > ( Dictionary < TKey , TValue > dictionary , KVObject kv , IObjectReflector reflector )
351394 {
352395 foreach ( var item in kv . Children )
353396 {
@@ -363,9 +406,13 @@ static void FillDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary, KV
363406 }
364407 }
365408
366- static TValue ConvertValue < TValue > ( object value , IObjectReflector reflector ) => ( TValue ) ConvertValue ( value , typeof ( TValue ) , reflector ) ;
409+ static TValue ConvertValue < [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] TValue > ( object value , IObjectReflector reflector )
410+ => ( TValue ) ConvertValue ( value , typeof ( TValue ) , reflector ) ;
367411
368- static object ConvertValue ( object value , Type valueType , IObjectReflector reflector )
412+ static object ConvertValue (
413+ object value ,
414+ [ DynamicallyAccessedMembers ( Trimming . Constructors | Trimming . Properties ) ] Type valueType ,
415+ IObjectReflector reflector )
369416 {
370417 if ( value is KVCollectionValue collectionValue )
371418 {
0 commit comments