@@ -32,6 +32,18 @@ public void FindBestConstructor(ITypeSymbol sourceType, ITypeSymbol destinationT
3232 }
3333
3434 var allConstructors = destinationType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . Where ( m => m . MethodKind == MethodKind . Constructor && m . DeclaredAccessibility == Accessibility . Public ) . ToList ( ) ;
35+
36+ if ( ! allConstructors . Any ( ) )
37+ {
38+ var destinationBaseType = destinationType . BaseType ;
39+ while ( destinationBaseType != null )
40+ {
41+ allConstructors = allConstructors . Concat ( destinationBaseType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . Where ( m => m . MethodKind == MethodKind . Constructor && m . DeclaredAccessibility == Accessibility . Public ) ) . ToList ( ) ;
42+ if ( allConstructors . Any ( ) ) break ;
43+ destinationBaseType = destinationBaseType . BaseType ;
44+ }
45+ }
46+
3547 if ( ! allConstructors . Any ( ) )
3648 {
3749 plan . Creation . Method = CreationMethod . None ;
@@ -50,6 +62,18 @@ public void FindBestConstructor(ITypeSymbol sourceType, ITypeSymbol destinationT
5062 public void FindBestFactory ( ITypeSymbol sourceType , ITypeSymbol destinationType , MappingPlan plan )
5163 {
5264 var factories = destinationType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . Where ( m => m . IsStatic && m . DeclaredAccessibility == Accessibility . Public && SymbolEqualityComparer . Default . Equals ( m . ReturnType , destinationType ) ) ;
65+
66+ if ( ! factories . Any ( ) )
67+ {
68+ var destinationBaseType = destinationType . BaseType ;
69+ while ( destinationType != null )
70+ {
71+ factories = factories . Concat ( destinationType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . Where ( m => m . IsStatic && m . DeclaredAccessibility == Accessibility . Public && SymbolEqualityComparer . Default . Equals ( m . ReturnType , destinationType ) ) ) ;
72+ if ( factories . Any ( ) ) break ;
73+ destinationType = destinationType . BaseType ;
74+ }
75+ }
76+
5377 FindBestCandidate ( factories , sourceType , plan , isFactory : true ) ;
5478 }
5579
@@ -68,8 +92,20 @@ private void FindBestCandidate(IEnumerable<IMethodSymbol> candidates, ITypeSymbo
6892 public void MapRemainingProperties ( ITypeSymbol sourceType , ITypeSymbol destinationType , MappingPlan plan , IEnumerable < string > ? ignoredMembers )
6993 {
7094 var sourceProperties = sourceType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . ToList ( ) ;
95+ var sourceBaseType = sourceType . BaseType ;
96+ while ( sourceBaseType != null )
97+ {
98+ sourceProperties . AddRange ( sourceBaseType . GetMembers ( ) . OfType < IPropertySymbol > ( ) ) ;
99+ sourceBaseType = sourceBaseType . BaseType ;
100+ }
71101 var alreadyMapped = new HashSet < string > ( plan . Creation . ParametersMap . Values . Select ( p => p . SourceProperty . Name ) . Concat ( plan . Instructions . Select ( i => i . Destination . Name ) ) ) ;
72102 var destinationProperties = destinationType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . Where ( p => ! alreadyMapped . Contains ( p . Name ) ) ;
103+ var destinationBaseType = destinationType . BaseType ;
104+ while ( destinationBaseType != null )
105+ {
106+ destinationProperties = destinationProperties . Concat ( destinationBaseType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . Where ( p => ! alreadyMapped . Contains ( p . Name ) ) ) ;
107+ destinationBaseType = destinationBaseType . BaseType ;
108+ }
73109
74110 var ignoredSet = ignoredMembers != null ? new HashSet < string > ( ignoredMembers , System . StringComparer . OrdinalIgnoreCase ) : new HashSet < string > ( ) ;
75111 destinationProperties = destinationProperties . Where ( p => ! ignoredSet . Contains ( p . Name ) ) ;
@@ -115,6 +151,12 @@ public void MapRemainingProperties(ITypeSymbol sourceType, ITypeSymbol destinati
115151 private bool CanSatisfyParameters ( IMethodSymbol method , ITypeSymbol sourceType , MappingPlan plan )
116152 {
117153 var sourceProperties = sourceType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . ToList ( ) ;
154+ var sourceBaseType = sourceType . BaseType ;
155+ while ( sourceBaseType != null )
156+ {
157+ sourceProperties . AddRange ( sourceBaseType . GetMembers ( ) . OfType < IPropertySymbol > ( ) ) ;
158+ sourceBaseType = sourceBaseType . BaseType ;
159+ }
118160 return method . Parameters . All ( p =>
119161 {
120162 if ( p . IsOptional || p . NullableAnnotation == NullableAnnotation . Annotated || p . Type . OriginalDefinition . SpecialType == SpecialType . System_Nullable_T ) return true ;
@@ -130,6 +172,12 @@ private bool CanSatisfyParameters(IMethodSymbol method, ITypeSymbol sourceType,
130172 private Dictionary < IParameterSymbol , CreationInfo . ParameterMappingInfo > MapMethodParameters ( IMethodSymbol method , ITypeSymbol sourceType , MappingPlan plan )
131173 {
132174 var sourceProperties = sourceType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . ToList ( ) ;
175+ var sourceBaseType = sourceType . BaseType ;
176+ while ( sourceBaseType != null )
177+ {
178+ sourceProperties . AddRange ( sourceBaseType . GetMembers ( ) . OfType < IPropertySymbol > ( ) ) ;
179+ sourceBaseType = sourceBaseType . BaseType ;
180+ }
133181 var map = new Dictionary < IParameterSymbol , CreationInfo . ParameterMappingInfo > ( SymbolEqualityComparer . Default ) ;
134182 foreach ( var param in method . Parameters )
135183 {
@@ -151,8 +199,33 @@ private bool CanSatisfyParameters(IMethodSymbol method, ITypeSymbol sourceType,
151199 private IMethodSymbol ? FindRecordPrimaryConstructor ( ITypeSymbol recordType )
152200 {
153201 var recordProperties = recordType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . Where ( p => ! p . IsStatic ) . ToDictionary ( p => p . Name , System . StringComparer . OrdinalIgnoreCase ) ;
202+ var baseRecordType = recordType . BaseType ;
203+ while ( baseRecordType != null && baseRecordType . IsRecord )
204+ {
205+ foreach ( var prop in baseRecordType . GetMembers ( ) . OfType < IPropertySymbol > ( ) . Where ( p => ! p . IsStatic ) )
206+ {
207+ if ( ! recordProperties . ContainsKey ( prop . Name ) )
208+ {
209+ recordProperties [ prop . Name ] = prop ;
210+ }
211+ }
212+ baseRecordType = baseRecordType . BaseType ;
213+ }
154214 if ( ! recordProperties . Any ( ) ) return null ;
155- return recordType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . FirstOrDefault ( m => m . MethodKind == MethodKind . Constructor ) ;
215+
216+ var result = recordType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . FirstOrDefault ( m => m . MethodKind == MethodKind . Constructor ) ;
217+
218+ if ( result == null )
219+ {
220+ baseRecordType = recordType . BaseType ;
221+ while ( baseRecordType != null && baseRecordType . IsRecord )
222+ {
223+ result = baseRecordType . GetMembers ( ) . OfType < IMethodSymbol > ( ) . FirstOrDefault ( m => m . MethodKind == MethodKind . Constructor ) ;
224+ if ( result != null ) break ;
225+ baseRecordType = baseRecordType . BaseType ;
226+ }
227+ }
228+ return result ;
156229 }
157230
158231 private INamedTypeSymbol ? FindMapperFor ( ITypeSymbol sourceType , ITypeSymbol destinationType )
0 commit comments