11using Microsoft . CodeAnalysis ;
22using Microsoft . CodeAnalysis . CSharp ;
33using Microsoft . CodeAnalysis . CSharp . Syntax ;
4- using System . Text ;
54
65namespace RoyalCode . SmartSelector . Generators . Generators ;
76
@@ -15,6 +14,7 @@ internal static class AutoPropertiesGenerator
1514 internal static MatchOptions MatchOptions { get ; } = new ( )
1615 {
1716 OriginPropertiesRetriever = new AutoPropertyOriginPropertiesRetriever ( ) ,
17+ AdditionalAssignDescriptorResolvers = [ new AutoDetailsAssignDescriptorResolver ( ) ] ,
1818 } ;
1919
2020 internal static bool Predicate ( SyntaxNode node , CancellationToken token )
@@ -135,25 +135,37 @@ internal static AutoPropertiesInformation CreateInformation(
135135 TypeDescriptor modelType ,
136136 ITypeSymbol fromType ,
137137 AttributeData autoPropertyAttribute )
138+ {
139+ // gera o TypeDescriptor do fromType
140+ var fromTypeDescriptor = TypeDescriptor . Create ( fromType ) ;
141+
142+ return CreateInformation ( modelType , fromTypeDescriptor , autoPropertyAttribute ) ;
143+ }
144+
145+ internal static AutoPropertiesInformation CreateInformation (
146+ TypeDescriptor modelType ,
147+ TypeDescriptor fromType ,
148+ AttributeData autoPropertyAttribute )
138149 {
139150 var excluded = new HashSet < string > ( StringComparer . Ordinal ) ;
140151 var flattening = new HashSet < string > ( StringComparer . Ordinal ) ;
141152
142153 // obtém Exclude de NamedArguments
143154 foreach ( var namedArg in autoPropertyAttribute . NamedArguments )
144155 if ( namedArg . Key == "Exclude" && namedArg . Value . Kind == TypedConstantKind . Array && namedArg . Value . Values != null )
156+ {
145157 foreach ( var v in namedArg . Value . Values )
146158 if ( v . Value is string s )
147159 excluded . Add ( s ) ;
160+ }
148161 else if ( namedArg . Key == "Flattening" && namedArg . Value . Kind == TypedConstantKind . Array && namedArg . Value . Values != null )
149- foreach ( var fv in namedArg . Value . Values )
150- if ( fv . Value is string fs )
151- flattening . Add ( fs ) ;
152-
153- // gera o TypeDescriptor do fromType
154- var fromTypeDescriptor = TypeDescriptor . Create ( fromType ) ;
162+ {
163+ foreach ( var fv in namedArg . Value . Values )
164+ if ( fv . Value is string fs )
165+ flattening . Add ( fs ) ;
166+ }
155167
156- return CreateInformation ( modelType , fromTypeDescriptor , excluded , flattening ) ;
168+ return CreateInformation ( modelType , fromType , excluded , flattening ) ;
157169 }
158170
159171 internal static AutoPropertiesInformation CreateInformation (
@@ -162,10 +174,19 @@ internal static AutoPropertiesInformation CreateInformation(
162174 HashSet < string > excluded ,
163175 HashSet < string > ? flattening )
164176 {
177+ var autoDetails = new List < AutoDetailsInformation > ( ) ;
178+
165179 // declared properties in model type are always excluded
166180 foreach ( var p in modelType . CreateProperties ( p => p . SetMethod is not null ) )
181+ {
167182 excluded . Add ( p . Name ) ;
168183
184+ // processa se propriedade se tem atributo AutoDetails
185+ if ( AutoDetailsGenerator . TryCreate ( p , fromType , out var autoDetailInfo ) )
186+ {
187+ autoDetails . Add ( autoDetailInfo ! ) ;
188+ }
189+ }
169190 var sourceProps = fromType . CreateProperties ( p => p . GetMethod is not null ) ;
170191
171192 // filtra propriedades do source,
@@ -192,7 +213,7 @@ internal static AutoPropertiesInformation CreateInformation(
192213 generated . Add ( new PropertyDescriptor ( p . Type , p . Name , p . Symbol ) ) ;
193214 }
194215
195- return new AutoPropertiesInformation ( modelType , [ .. generated ] ) ;
216+ return new AutoPropertiesInformation ( modelType , [ .. generated ] , [ .. autoDetails ] ) ;
196217 }
197218
198219 private static IReadOnlyList < PropertyDescriptor > CreateFlattening (
@@ -339,8 +360,6 @@ internal static void Generate(AutoPropertiesInformation propertiesInfo, SourcePr
339360 partialClass . FileName = $ "{ origin . Name } .AutoProperties.g.cs";
340361 partialClass . Generate ( context ) ;
341362 }
342-
343-
344363}
345364
346365internal class AutoPropertyOriginPropertiesRetriever : IOriginPropertiesRetriever
@@ -351,9 +370,12 @@ internal class AutoPropertyOriginPropertiesRetriever : IOriginPropertiesRetrieve
351370
352371 public IReadOnlyList < PropertyDescriptor > GetProperties ( TypeDescriptor origin )
353372 {
373+ var originProperties = MatchOptions . GetOriginProperties ( origin ) ;
374+ origin . DefinedProperties = originProperties ;
354375 var typeSymbol = origin . Symbol ;
376+
355377 if ( typeSymbol == null )
356- return MatchOptions . GetOriginProperties ( origin ) ;
378+ return originProperties ;
357379
358380 // Verifica se no type existe:
359381 // - o AutoPropertiesAttribute com AutoSelectAttribute<TFrom>
@@ -378,18 +400,18 @@ public IReadOnlyList<PropertyDescriptor> GetProperties(TypeDescriptor origin)
378400
379401 // se não tiver, retorna o padrão
380402 if ( autoSelectAttribute == null )
381- return MatchOptions . GetOriginProperties ( origin ) ;
403+ return originProperties ;
382404
383405 // obtém o tipo TFrom
384406 var fromType = autoSelectAttribute . AttributeClass ? . TypeArguments . FirstOrDefault ( ) ;
385407 if ( fromType == null )
386- return MatchOptions . GetOriginProperties ( origin ) ;
408+ return originProperties ;
387409
388410 // cria a informação
389411 var info = AutoPropertiesGenerator . CreateInformation ( origin , fromType , autoSelectAttribute ) ;
390412
391413 // pega as propriedades da origem mais as da informação
392- return [ .. MatchOptions . GetOriginProperties ( origin ) , .. info . Properties ] ;
414+ return [ .. originProperties , .. info . Properties ] ;
393415 }
394416
395417 // obtém o AutoPropertiesAttribute<TFrom>
@@ -404,15 +426,64 @@ public IReadOnlyList<PropertyDescriptor> GetProperties(TypeDescriptor origin)
404426 // obtém o tipo TFrom
405427 var fromType = autoPropertiesAttribute . AttributeClass ? . TypeArguments . FirstOrDefault ( ) ;
406428 if ( fromType == null )
407- return MatchOptions . GetOriginProperties ( origin ) ;
429+ return originProperties ;
408430
409431 // cria a informação
410432 var info = AutoPropertiesGenerator . CreateInformation ( origin , fromType , autoPropertiesAttribute ) ;
411433
412434 // pega as propriedades da origem mais as da informação
413- return [ .. MatchOptions . GetOriginProperties ( origin ) , .. info . Properties ] ;
435+ return [ .. originProperties , .. info . Properties ] ;
414436 }
415437
416- return MatchOptions . GetOriginProperties ( origin ) ;
438+ return originProperties ;
417439 }
418440}
441+
442+ internal class AutoDetailsAssignDescriptorResolver : IAssignDescriptorResolver
443+ {
444+ public bool TryCreateAssignDescriptor (
445+ TypeDescriptor leftType ,
446+ TypeDescriptor rightType ,
447+ SemanticModel model ,
448+ MatchOptions options ,
449+ out AssignDescriptor ? descriptor )
450+ {
451+ descriptor = null ;
452+
453+ // check if the left type has defined properties
454+ if ( ! leftType . HasDefinedProperties ( ) )
455+ return false ;
456+
457+ // obtém propriedades do tipo de origem
458+ var leftProperties = options . OriginPropertiesRetriever . GetProperties ( leftType ) ;
459+
460+ // valida se tem propriedades
461+ if ( leftProperties . Count == 0 )
462+ return false ;
463+
464+ // obtém propriedades do tipo de destino
465+ var rightProperties = options . TargetPropertiesRetriever . GetProperties ( rightType ) ;
466+
467+ // valida se tem propriedades
468+ if ( rightProperties . Count == 0 )
469+ return false ;
470+
471+ // faz o match entre as propriedades
472+ // match das propriedades da classe com o attributo e a classe definida no TFrom.
473+ var matchSelection = MatchSelection . Create ( leftType , leftProperties , rightType , rightProperties , model , options ) ;
474+
475+ // se tem problemas, não é possível fazer o match.
476+ if ( matchSelection . HasMissingProperties ( out _ ) || matchSelection . HasNotAssignableProperties ( out _ ) )
477+ {
478+ return false ;
479+ }
480+
481+ descriptor = new AssignDescriptor ( )
482+ {
483+ AssignType = AssignType . NewInstance ,
484+ InnerSelection = matchSelection
485+ } ;
486+
487+ return true ;
488+ }
489+ }
0 commit comments