@@ -18,12 +18,16 @@ public OutputType Convert(Type type, ContractedType? contractedType = null)
1818 {
1919 ArgumentNullException . ThrowIfNull ( type ) ;
2020
21+ var typeName = type . Name . Split ( '`' ) . First ( ) ;
22+
2123 return new (
22- type . Name ,
24+ typeName ,
2325 type . FullName ! ,
24- CasingHelpers . ToCasing ( type . Name . Replace ( "_" , "" ) , configuration . Casing ) ,
25- contractedType ?? ContractedType . FromName ( type . FullName ! , type , configuration ) ,
26+ CasingHelpers . ToCasing ( typeName . Replace ( "_" , "" ) , configuration . Casing ) ,
27+ contractedType ?? ContractedType . FromName ( type . FullName ?? typeName , type , configuration ) ,
2628 type . IsEnum ,
29+ type . IsGenericType ,
30+ type . IsGenericType ? ( ( TypeInfo ) type ) . GenericTypeParameters . Select ( x => GetDestinationType ( x , [ ] , false , TypeChecks . IsNullable ( x ) ) ) . ToList ( ) : [ ] ,
2731 type . IsEnum ? null : GetProperties ( type ) . Distinct ( ) . ToList ( ) ,
2832 type . IsEnum ? GetEnumProperties ( type ) : null
2933 ) ;
@@ -71,7 +75,19 @@ private List<OutputProperty> GetProperties(Type type)
7175
7276 var destinationName = GetDestinationName ( property . Name ) ;
7377 var destinationType = GetDestinationType ( property . PropertyType , property . CustomAttributes , isReadonly , TypeChecks . IsNullable ( property . PropertyType ) ) ;
74- var outputProperty = new OutputProperty ( property . Name , property . PropertyType , destinationType . InnerType , destinationName , destinationType . TypeName , destinationType . ImportType , destinationType . IsBuiltin , destinationType . IsArray , TypeChecks . IsNullable ( property ) , destinationType . IsReadonly ) ;
78+ var outputProperty = new OutputProperty (
79+ property . Name ,
80+ property . PropertyType ,
81+ destinationType . InnerType ,
82+ destinationName ,
83+ destinationType . TypeName ,
84+ destinationType . ImportType ,
85+ destinationType . IsBuiltin ,
86+ destinationType . IsArray ,
87+ TypeChecks . IsNullable ( property ) ,
88+ destinationType . IsReadonly ,
89+ destinationType . IsGeneric ,
90+ destinationType . GenericTypeArguments ) ;
7591
7692 var obsolete = property . CustomAttributes . FirstOrDefault ( x => x . AttributeType . FullName == "System.ObsoleteAttribute" ) ;
7793 outputProperty . Obsolete = obsolete is not null ? new ObsoleteInfo ( ( string ? ) obsolete . ConstructorArguments . FirstOrDefault ( ) . Value ) : null ;
@@ -94,11 +110,14 @@ private List<OutputProperty> GetProperties(Type type)
94110
95111 public DestinationType GetDestinationType ( in Type sourceType , IEnumerable < CustomAttributeData > customAttributes , bool isReadonly , bool isNullable )
96112 {
97- if ( configuration . TypeMaps . TryGetValue ( sourceType . FullName ! , out var destType ) )
98- return new DestinationType ( destType . Replace ( "[]" , string . Empty ) , sourceType . FullName , true , destType . Contains ( "[]" ) , isReadonly , isNullable || TypeChecks . IsNullable ( sourceType ) , null ) ;
113+ if ( ! sourceType . IsGenericParameter && configuration . TypeMaps . TryGetValue ( sourceType . FullName ! , out var destType ) )
114+ return new DestinationType ( destType . Replace ( "[]" , string . Empty ) , sourceType . FullName , true , destType . Contains ( "[]" ) , isReadonly , isNullable || TypeChecks . IsNullable ( sourceType ) , false , [ ] , null , sourceType ) ;
99115
100116 if ( CustomMappedTypes . TryGetValue ( sourceType , out var customType ) )
101- return new DestinationType ( customType . Name , customType . FullName , false , false , isReadonly , TypeChecks . IsNullable ( sourceType ) , null ) ;
117+ return new DestinationType ( customType . Name , customType . FullName , false , false , isReadonly , TypeChecks . IsNullable ( sourceType ) , customType . IsGeneric , customType . GenericTypeArguments , null , customType . ContractedType . Type ) ;
118+
119+ if ( sourceType . IsGenericTypeParameter )
120+ return new DestinationType ( sourceType . Name , null , true , false , false , isNullable , true , [ ] , null , sourceType , "" ) ;
102121
103122 if ( TypeChecks . ImplementsIDictionary ( sourceType ) )
104123 {
@@ -108,15 +127,15 @@ public DestinationType GetDestinationType(in Type sourceType, IEnumerable<Custom
108127
109128 var isBuiltin = keyType . IsBuiltin && valueDestinationType . IsBuiltin ;
110129
111- return new DestinationType ( $ "{{ [key: { keyType . TypeName } ]: { valueDestinationType . FullTypeName } }}", valueDestinationType . FullName , isBuiltin , false , isReadonly , valueDestinationType . IsNullable , valueType , valueDestinationType . ImportType ) ;
130+ return new DestinationType ( $ "{{ [key: { keyType . TypeName } ]: { valueDestinationType . FullTypeName } }}", valueDestinationType . FullName , isBuiltin , false , isReadonly , valueDestinationType . IsNullable , valueDestinationType . IsGeneric , valueDestinationType . GenericTypeArguments , valueType , valueDestinationType . SourceType , valueDestinationType . ImportType ) ;
112131 }
113132
114133 if ( TypeChecks . ImplementsIEnumerable ( sourceType ) )
115134 {
116135 var innerType = TypeChecks . GetGenericType ( sourceType ) ;
117136
118- var ( TypeName , FullName , _, IsBuiltin , _, IsReadonly , IsNullable , _) = GetDestinationType ( innerType , customAttributes , isReadonly , isNullable ) ;
119- return new DestinationType ( TypeName , FullName , IsBuiltin , true , IsReadonly , IsNullable , innerType ) ;
137+ var ( TypeName , FullName , _, IsBuiltin , _, IsReadonly , IsNullable , IsGeneric , _ , _ , _) = GetDestinationType ( innerType , customAttributes , isReadonly , isNullable ) ;
138+ return new DestinationType ( TypeName , FullName , IsBuiltin , true , IsReadonly , IsNullable , IsGeneric , [ ] , innerType , sourceType ) ;
120139 }
121140
122141 if ( TypeChecks . IsValueTuple ( sourceType ) )
@@ -128,21 +147,37 @@ public DestinationType GetDestinationType(in Type sourceType, IEnumerable<Custom
128147 var argumentList = argumentDestinationTypes . Select ( ( arg , idx ) => $ "item{ idx + 1 } : { arg . FullTypeName } ") ;
129148 var typeName = $ "{{ { string . Join ( ", " , argumentList ) } }}";
130149
131- return new DestinationType ( typeName , sourceType . FullName , isBuiltin , false , isReadonly , false , null ) ;
150+ return new DestinationType ( typeName , sourceType . FullName , isBuiltin , false , isReadonly , false , false , [ ] , null , sourceType ) ;
132151 }
133152
134153 if ( TypeChecks . IsNullable ( sourceType ) )
135154 {
136155 return GetDestinationType ( sourceType . GenericTypeArguments . First ( ) , customAttributes , isReadonly , true ) ;
137156 }
138157
158+ if ( sourceType . IsGenericType && sourceType . GenericTypeArguments . Length > 0 )
159+ {
160+ var genericType = sourceType . GetGenericTypeDefinition ( ) ;
161+ var genericOutputType = Convert ( genericType ) ;
162+ CustomMappedTypes . TryAdd ( genericType , genericOutputType ) ;
163+
164+ var genericArguments = sourceType . GenericTypeArguments
165+ . Select ( x => GetDestinationType ( x , customAttributes , isReadonly , TypeChecks . IsNullable ( x ) ) )
166+ . ToList ( ) ;
167+
168+ var importType = genericOutputType . Name . Split ( '`' ) . First ( ) ;
169+ var typeName = importType + $ "<{ string . Join ( ", " , genericArguments . Select ( x => x . TypeName ) ) } >";
170+
171+ return new DestinationType ( typeName , genericOutputType . FullName , false , false , isReadonly , isNullable , true , genericArguments , null , genericOutputType . ContractedType . Type , importType ) ;
172+ }
173+
139174 if ( customAttributes . Any ( x => x . AttributeType . FullName == "System.Runtime.CompilerServices.DynamicAttribute" ) )
140- return new DestinationType ( DestinationTypes . Dynamic , null , true , false , isReadonly , true , null ) ;
175+ return new DestinationType ( DestinationTypes . Dynamic , null , true , false , isReadonly , true , false , [ ] , null , null ) ;
141176
142177 // FIXME: Check if this is one of our types?
143178 var outputType = Convert ( sourceType ) ;
144179 CustomMappedTypes . Add ( sourceType , outputType ) ;
145- return new DestinationType ( outputType . Name , outputType . FullName , false , false , isReadonly , isNullable || TypeChecks . IsNullable ( sourceType ) , null ) ;
180+ return new DestinationType ( outputType . Name , outputType . FullName , false , false , isReadonly , isNullable || TypeChecks . IsNullable ( sourceType ) , outputType . IsGeneric , outputType . GenericTypeArguments , null , sourceType ) ;
146181
147182 // throw new ArgumentException($"Unexpected type: {sourceType}");
148183 }
0 commit comments