@@ -6,6 +6,8 @@ namespace StyleCop.Analyzers.CodeGeneration
66 using System ;
77 using System . Collections . Generic ;
88 using System . Collections . Immutable ;
9+ using System . Diagnostics ;
10+ using System . Diagnostics . CodeAnalysis ;
911 using System . IO ;
1012 using System . Linq ;
1113 using System . Text ;
@@ -144,6 +146,146 @@ private void GenerateSyntaxWrapper(in GeneratorExecutionContext context, SyntaxD
144146 variables : SyntaxFactory . SingletonSeparatedList ( SyntaxFactory . VariableDeclarator ( field . WithAccessorName ) ) ) ) ) ;
145147 }
146148
149+ // WrappedType = SyntaxWrapperHelper.GetWrappedType(typeof(SyntaxWrapper));
150+ var staticCtorStatements = SyntaxFactory . SingletonList < StatementSyntax > (
151+ SyntaxFactory . ExpressionStatement ( SyntaxFactory . AssignmentExpression (
152+ SyntaxKind . SimpleAssignmentExpression ,
153+ left : SyntaxFactory . IdentifierName ( "WrappedType" ) ,
154+ right : SyntaxFactory . InvocationExpression (
155+ expression : SyntaxFactory . MemberAccessExpression (
156+ SyntaxKind . SimpleMemberAccessExpression ,
157+ expression : SyntaxFactory . IdentifierName ( "SyntaxWrapperHelper" ) ,
158+ name : SyntaxFactory . IdentifierName ( "GetWrappedType" ) ) ,
159+ argumentList : SyntaxFactory . ArgumentList ( SyntaxFactory . SingletonSeparatedList ( SyntaxFactory . Argument (
160+ SyntaxFactory . TypeOfExpression ( SyntaxFactory . IdentifierName ( nodeData . WrapperName ) ) ) ) ) ) ) ) ) ;
161+
162+ foreach ( var field in nodeData . Fields )
163+ {
164+ if ( field . IsSkipped )
165+ {
166+ continue ;
167+ }
168+
169+ if ( field . IsOverride )
170+ {
171+ // The 'get' accessor is skipped for override fields
172+ continue ;
173+ }
174+
175+ SimpleNameSyntax helperName ;
176+ if ( field . IsWrappedSeparatedSyntaxList ( syntaxData , out var elementNode ) )
177+ {
178+ Debug . Assert ( elementNode . WrapperName is not null , $ "Assertion failed: { nameof ( elementNode ) } .{ nameof ( elementNode . WrapperName ) } is not null") ;
179+
180+ // CreateSeparatedSyntaxListPropertyAccessor<SyntaxNode, T>
181+ helperName = SyntaxFactory . GenericName (
182+ identifier : SyntaxFactory . Identifier ( "CreateSeparatedSyntaxListPropertyAccessor" ) ,
183+ typeArgumentList : SyntaxFactory . TypeArgumentList ( SyntaxFactory . SeparatedList < TypeSyntax > (
184+ new [ ]
185+ {
186+ SyntaxFactory . IdentifierName ( concreteBase ) ,
187+ SyntaxFactory . IdentifierName ( elementNode . WrapperName ) ,
188+ } ) ) ) ;
189+ }
190+ else
191+ {
192+ // CreateSyntaxPropertyAccessor<SyntaxNode, T>
193+ helperName = SyntaxFactory . GenericName (
194+ identifier : SyntaxFactory . Identifier ( "CreateSyntaxPropertyAccessor" ) ,
195+ typeArgumentList : SyntaxFactory . TypeArgumentList ( SyntaxFactory . SeparatedList (
196+ new [ ]
197+ {
198+ SyntaxFactory . IdentifierName ( concreteBase ) ,
199+ SyntaxFactory . ParseTypeName ( field . GetAccessorResultType ( syntaxData ) ) ,
200+ } ) ) ) ;
201+ }
202+
203+ // ReturnTypeAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<StatementSyntax, TypeSyntax>(WrappedType, nameof(ReturnType));
204+ staticCtorStatements = staticCtorStatements . Add ( SyntaxFactory . ExpressionStatement ( SyntaxFactory . AssignmentExpression (
205+ SyntaxKind . SimpleAssignmentExpression ,
206+ left : SyntaxFactory . IdentifierName ( field . AccessorName ) ,
207+ right : SyntaxFactory . InvocationExpression (
208+ expression : SyntaxFactory . MemberAccessExpression (
209+ SyntaxKind . SimpleMemberAccessExpression ,
210+ expression : SyntaxFactory . IdentifierName ( "LightupHelpers" ) ,
211+ name : helperName ) ,
212+ argumentList : SyntaxFactory . ArgumentList ( SyntaxFactory . SeparatedList (
213+ new [ ]
214+ {
215+ SyntaxFactory . Argument ( SyntaxFactory . IdentifierName ( "WrappedType" ) ) ,
216+ SyntaxFactory . Argument ( SyntaxFactory . InvocationExpression (
217+ expression : SyntaxFactory . IdentifierName ( "nameof" ) ,
218+ argumentList : SyntaxFactory . ArgumentList ( SyntaxFactory . SingletonSeparatedList ( SyntaxFactory . Argument ( field . GetPropertyNameExpression ( syntaxData ) ) ) ) ) ) ,
219+ } ) ) ) ) ) ) ;
220+ }
221+
222+ foreach ( var field in nodeData . Fields )
223+ {
224+ if ( field . IsSkipped )
225+ {
226+ continue ;
227+ }
228+
229+ SimpleNameSyntax helperName ;
230+ if ( field . IsWrappedSeparatedSyntaxList ( syntaxData , out var elementNode ) )
231+ {
232+ Debug . Assert ( elementNode . WrapperName is not null , $ "Assertion failed: { nameof ( elementNode ) } .{ nameof ( elementNode . WrapperName ) } is not null") ;
233+
234+ // CreateSeparatedSyntaxListWithPropertyAccessor<SyntaxNode, T>
235+ helperName = SyntaxFactory . GenericName (
236+ identifier : SyntaxFactory . Identifier ( "CreateSeparatedSyntaxListWithPropertyAccessor" ) ,
237+ typeArgumentList : SyntaxFactory . TypeArgumentList ( SyntaxFactory . SeparatedList < TypeSyntax > (
238+ new [ ]
239+ {
240+ SyntaxFactory . IdentifierName ( concreteBase ) ,
241+ SyntaxFactory . IdentifierName ( elementNode . WrapperName ) ,
242+ } ) ) ) ;
243+ }
244+ else
245+ {
246+ // CreateSyntaxWithPropertyAccessor<SyntaxNode, T>
247+ helperName = SyntaxFactory . GenericName (
248+ identifier : SyntaxFactory . Identifier ( "CreateSyntaxWithPropertyAccessor" ) ,
249+ typeArgumentList : SyntaxFactory . TypeArgumentList ( SyntaxFactory . SeparatedList (
250+ new [ ]
251+ {
252+ SyntaxFactory . IdentifierName ( concreteBase ) ,
253+ SyntaxFactory . ParseTypeName ( field . GetAccessorResultType ( syntaxData ) ) ,
254+ } ) ) ) ;
255+ }
256+
257+ // WithReturnTypeAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<StatementSyntax, TypeSyntax>(WrappedType, nameof(ReturnType));
258+ staticCtorStatements = staticCtorStatements . Add ( SyntaxFactory . ExpressionStatement ( SyntaxFactory . AssignmentExpression (
259+ SyntaxKind . SimpleAssignmentExpression ,
260+ left : SyntaxFactory . IdentifierName ( field . WithAccessorName ) ,
261+ right : SyntaxFactory . InvocationExpression (
262+ expression : SyntaxFactory . MemberAccessExpression (
263+ SyntaxKind . SimpleMemberAccessExpression ,
264+ expression : SyntaxFactory . IdentifierName ( "LightupHelpers" ) ,
265+ name : helperName ) ,
266+ argumentList : SyntaxFactory . ArgumentList ( SyntaxFactory . SeparatedList (
267+ new [ ]
268+ {
269+ SyntaxFactory . Argument ( SyntaxFactory . IdentifierName ( "WrappedType" ) ) ,
270+ SyntaxFactory . Argument ( SyntaxFactory . InvocationExpression (
271+ expression : SyntaxFactory . IdentifierName ( "nameof" ) ,
272+ argumentList : SyntaxFactory . ArgumentList ( SyntaxFactory . SingletonSeparatedList ( SyntaxFactory . Argument ( field . GetPropertyNameExpression ( syntaxData ) ) ) ) ) ) ,
273+ } ) ) ) ) ) ) ;
274+ }
275+
276+ // static SyntaxWrapper()
277+ // {
278+ // WrappedType = SyntaxWrapperHelper.GetWrappedType(typeof(SyntaxWrapper));
279+ // }
280+ members = members . Add ( SyntaxFactory . ConstructorDeclaration (
281+ attributeLists : default ,
282+ modifiers : SyntaxFactory . TokenList ( SyntaxFactory . Token ( SyntaxKind . StaticKeyword ) ) ,
283+ identifier : SyntaxFactory . Identifier ( nodeData . WrapperName ) ,
284+ parameterList : SyntaxFactory . ParameterList ( ) ,
285+ initializer : null ,
286+ body : SyntaxFactory . Block ( staticCtorStatements ) ,
287+ expressionBody : null ) ) ;
288+
147289 // private SyntaxNodeWrapper(SyntaxNode node)
148290 // {
149291 // this.node = node;
@@ -713,7 +855,7 @@ public NodeData(in GeneratorExecutionContext context, XElement element)
713855 }
714856
715857 this . BaseName = element . Attribute ( "Base" ) . Value ;
716- this . Fields = element . XPathSelectElements ( "descendant::Field" ) . Select ( field => new FieldData ( field ) ) . ToImmutableArray ( ) ;
858+ this . Fields = element . XPathSelectElements ( "descendant::Field" ) . Select ( field => new FieldData ( this , field ) ) . ToImmutableArray ( ) ;
717859 }
718860
719861 public NodeKind Kind { get ; }
@@ -725,12 +867,21 @@ public NodeData(in GeneratorExecutionContext context, XElement element)
725867 public string BaseName { get ; }
726868
727869 public ImmutableArray < FieldData > Fields { get ; }
870+
871+ internal FieldData ? TryGetField ( string name )
872+ {
873+ return this . Fields . SingleOrDefault ( field => field . Name == name ) ;
874+ }
728875 }
729876
730877 private sealed class FieldData
731878 {
732- public FieldData ( XElement element )
879+ private readonly NodeData nodeData ;
880+
881+ public FieldData ( NodeData nodeData , XElement element )
733882 {
883+ this . nodeData = nodeData ;
884+
734885 this . Name = element . Attribute ( "Name" ) . Value ;
735886
736887 var type = element . Attribute ( "Type" ) . Value ;
@@ -758,26 +909,77 @@ public FieldData(XElement element)
758909
759910 public bool IsOverride { get ; }
760911
761- public string GetAccessorResultType ( SyntaxData syntaxData )
912+ public NodeData GetDeclaringNode ( SyntaxData syntaxData )
762913 {
763- var typeNode = syntaxData . TryGetNode ( this . Type ) ;
764- if ( typeNode is not null )
914+ for ( var current = this . nodeData ; current is not null ; current = syntaxData . TryGetNode ( current . BaseName ) )
765915 {
766- return syntaxData . TryGetConcreteType ( typeNode ) ? . Name ?? nameof ( SyntaxNode ) ;
916+ var currentField = current . TryGetField ( this . Name ) ;
917+ if ( currentField is { IsOverride : false } )
918+ {
919+ return currentField . nodeData ;
920+ }
767921 }
768922
923+ throw new NotSupportedException ( "Unable to find declaring node." ) ;
924+ }
925+
926+ public NameSyntax GetPropertyNameExpression ( SyntaxData syntaxData )
927+ {
928+ var declaringNode = this . GetDeclaringNode ( syntaxData ) ;
929+ if ( declaringNode == this . nodeData )
930+ {
931+ return SyntaxFactory . IdentifierName ( this . Name ) ;
932+ }
933+ else
934+ {
935+ return SyntaxFactory . QualifiedName (
936+ SyntaxFactory . IdentifierName ( declaringNode . WrapperName ?? declaringNode . Name ) ,
937+ SyntaxFactory . IdentifierName ( this . Name ) ) ;
938+ }
939+ }
940+
941+ public bool IsWrappedSeparatedSyntaxList ( SyntaxData syntaxData , [ NotNullWhen ( true ) ] out NodeData ? element )
942+ {
769943 if ( this . Type . StartsWith ( "SeparatedSyntaxList<" ) && this . Type . EndsWith ( ">" ) )
770944 {
771945 var elementTypeName = this . Type . Substring ( "SeparatedSyntaxList<" . Length , this . Type . Length - "SeparatedSyntaxList<" . Length - ">" . Length ) ;
772946 var elementTypeNode = syntaxData . TryGetNode ( elementTypeName ) ;
773947 if ( elementTypeNode is { WrapperName : not null } )
774948 {
775- return $ "SeparatedSyntaxListWrapper<{ elementTypeNode . WrapperName } >";
949+ element = elementTypeNode ;
950+ return true ;
776951 }
777952 }
778953
954+ element = null ;
955+ return false ;
956+ }
957+
958+ public string GetAccessorResultType ( SyntaxData syntaxData )
959+ {
960+ var typeNode = syntaxData . TryGetNode ( this . Type ) ;
961+ if ( typeNode is not null )
962+ {
963+ return syntaxData . TryGetConcreteType ( typeNode ) ? . Name ?? nameof ( SyntaxNode ) ;
964+ }
965+
966+ if ( this . IsWrappedSeparatedSyntaxList ( syntaxData , out var elementTypeNode ) )
967+ {
968+ return $ "SeparatedSyntaxListWrapper<{ elementTypeNode . WrapperName } >";
969+ }
970+
779971 return this . Type ;
780972 }
973+
974+ public string ? GetAccessorResultElementType ( SyntaxData syntaxData )
975+ {
976+ if ( this . IsWrappedSeparatedSyntaxList ( syntaxData , out var elementTypeNode ) )
977+ {
978+ return elementTypeNode . WrapperName ;
979+ }
980+
981+ return null ;
982+ }
781983 }
782984 }
783985}
0 commit comments