Skip to content

Commit 1ebaed9

Browse files
committed
Generate static constructors for syntax wrappers
1 parent 1bcc864 commit 1ebaed9

82 files changed

Lines changed: 731 additions & 359 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

StyleCop.Analyzers/StyleCop.Analyzers.CodeGeneration/StyleCop.Analyzers.CodeGeneration.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
<ItemGroup>
1919
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0-5.final" />
20+
<PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" Version="1.0.0-alpha.160" PrivateAssets="all" />
21+
<PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[3.1.0]" />
2022
</ItemGroup>
2123

2224
</Project>

StyleCop.Analyzers/StyleCop.Analyzers.CodeGeneration/SyntaxLightupGenerator.cs

Lines changed: 209 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/.generated/StyleCop.Analyzers.CodeGeneration/StyleCop.Analyzers.CodeGeneration.SyntaxLightupGenerator/BaseObjectCreationExpressionSyntaxWrapper.g.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ namespace StyleCop.Analyzers.Lightup
2020
private static readonly Func<ExpressionSyntax, SyntaxToken, ExpressionSyntax> WithNewKeywordAccessor;
2121
private static readonly Func<ExpressionSyntax, ArgumentListSyntax, ExpressionSyntax> WithArgumentListAccessor;
2222
private static readonly Func<ExpressionSyntax, InitializerExpressionSyntax, ExpressionSyntax> WithInitializerAccessor;
23+
static BaseObjectCreationExpressionSyntaxWrapper()
24+
{
25+
WrappedType = SyntaxWrapperHelper.GetWrappedType(typeof(BaseObjectCreationExpressionSyntaxWrapper));
26+
NewKeywordAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<ExpressionSyntax, SyntaxToken>(WrappedType, nameof(NewKeyword));
27+
ArgumentListAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<ExpressionSyntax, ArgumentListSyntax>(WrappedType, nameof(ArgumentList));
28+
InitializerAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<ExpressionSyntax, InitializerExpressionSyntax>(WrappedType, nameof(Initializer));
29+
WithNewKeywordAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<ExpressionSyntax, SyntaxToken>(WrappedType, nameof(NewKeyword));
30+
WithArgumentListAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<ExpressionSyntax, ArgumentListSyntax>(WrappedType, nameof(ArgumentList));
31+
WithInitializerAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<ExpressionSyntax, InitializerExpressionSyntax>(WrappedType, nameof(Initializer));
32+
}
33+
2334
private BaseObjectCreationExpressionSyntaxWrapper(ExpressionSyntax node)
2435
{
2536
this.node = node;

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/.generated/StyleCop.Analyzers.CodeGeneration/StyleCop.Analyzers.CodeGeneration.SyntaxLightupGenerator/BaseParameterSyntaxWrapper.g.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ namespace StyleCop.Analyzers.Lightup
2020
private static readonly Func<CSharpSyntaxNode, SyntaxList<AttributeListSyntax>, CSharpSyntaxNode> WithAttributeListsAccessor;
2121
private static readonly Func<CSharpSyntaxNode, SyntaxTokenList, CSharpSyntaxNode> WithModifiersAccessor;
2222
private static readonly Func<CSharpSyntaxNode, TypeSyntax, CSharpSyntaxNode> WithTypeAccessor;
23+
static BaseParameterSyntaxWrapper()
24+
{
25+
WrappedType = SyntaxWrapperHelper.GetWrappedType(typeof(BaseParameterSyntaxWrapper));
26+
AttributeListsAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<CSharpSyntaxNode, SyntaxList<AttributeListSyntax>>(WrappedType, nameof(AttributeLists));
27+
ModifiersAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<CSharpSyntaxNode, SyntaxTokenList>(WrappedType, nameof(Modifiers));
28+
TypeAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<CSharpSyntaxNode, TypeSyntax>(WrappedType, nameof(Type));
29+
WithAttributeListsAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<CSharpSyntaxNode, SyntaxList<AttributeListSyntax>>(WrappedType, nameof(AttributeLists));
30+
WithModifiersAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<CSharpSyntaxNode, SyntaxTokenList>(WrappedType, nameof(Modifiers));
31+
WithTypeAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<CSharpSyntaxNode, TypeSyntax>(WrappedType, nameof(Type));
32+
}
33+
2334
private BaseParameterSyntaxWrapper(CSharpSyntaxNode node)
2435
{
2536
this.node = node;

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/.generated/StyleCop.Analyzers.CodeGeneration/StyleCop.Analyzers.CodeGeneration.SyntaxLightupGenerator/BinaryPatternSyntaxWrapper.g.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ namespace StyleCop.Analyzers.Lightup
2020
private static readonly Func<CSharpSyntaxNode, CSharpSyntaxNode, CSharpSyntaxNode> WithLeftAccessor;
2121
private static readonly Func<CSharpSyntaxNode, SyntaxToken, CSharpSyntaxNode> WithOperatorTokenAccessor;
2222
private static readonly Func<CSharpSyntaxNode, CSharpSyntaxNode, CSharpSyntaxNode> WithRightAccessor;
23+
static BinaryPatternSyntaxWrapper()
24+
{
25+
WrappedType = SyntaxWrapperHelper.GetWrappedType(typeof(BinaryPatternSyntaxWrapper));
26+
LeftAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<CSharpSyntaxNode, CSharpSyntaxNode>(WrappedType, nameof(Left));
27+
OperatorTokenAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<CSharpSyntaxNode, SyntaxToken>(WrappedType, nameof(OperatorToken));
28+
RightAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<CSharpSyntaxNode, CSharpSyntaxNode>(WrappedType, nameof(Right));
29+
WithLeftAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<CSharpSyntaxNode, CSharpSyntaxNode>(WrappedType, nameof(Left));
30+
WithOperatorTokenAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<CSharpSyntaxNode, SyntaxToken>(WrappedType, nameof(OperatorToken));
31+
WithRightAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<CSharpSyntaxNode, CSharpSyntaxNode>(WrappedType, nameof(Right));
32+
}
33+
2334
private BinaryPatternSyntaxWrapper(CSharpSyntaxNode node)
2435
{
2536
this.node = node;

0 commit comments

Comments
 (0)