Skip to content

Commit d360563

Browse files
committed
fix: use ToDisplayString and ToDisplayParts to make sure members are generated correctly
1 parent 3b10762 commit d360563

78 files changed

Lines changed: 9824 additions & 6555 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.

src/bunit.web.anglesharp/GeneratorConfig.cs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,34 @@ internal static class GeneratorConfig
77
internal static readonly SymbolDisplayFormat SymbolFormat = new SymbolDisplayFormat(
88
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
99
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
10-
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
10+
genericsOptions:
11+
SymbolDisplayGenericsOptions.IncludeTypeParameters |
12+
SymbolDisplayGenericsOptions.IncludeTypeConstraints |
13+
SymbolDisplayGenericsOptions.IncludeVariance,
1114
memberOptions:
12-
SymbolDisplayMemberOptions.IncludeParameters |
1315
SymbolDisplayMemberOptions.IncludeType |
14-
SymbolDisplayMemberOptions.IncludeRef |
15-
SymbolDisplayMemberOptions.IncludeContainingType,
16-
kindOptions:
17-
SymbolDisplayKindOptions.IncludeMemberKeyword,
16+
SymbolDisplayMemberOptions.IncludeModifiers |
17+
SymbolDisplayMemberOptions.IncludeAccessibility |
18+
SymbolDisplayMemberOptions.IncludeParameters |
19+
SymbolDisplayMemberOptions.IncludeConstantValue |
20+
SymbolDisplayMemberOptions.IncludeRef,
21+
kindOptions: SymbolDisplayKindOptions.IncludeMemberKeyword,
1822
parameterOptions:
1923
SymbolDisplayParameterOptions.IncludeName |
2024
SymbolDisplayParameterOptions.IncludeType |
2125
SymbolDisplayParameterOptions.IncludeParamsRefOut |
22-
SymbolDisplayParameterOptions.IncludeDefaultValue,
26+
SymbolDisplayParameterOptions.IncludeDefaultValue |
27+
SymbolDisplayParameterOptions.IncludeModifiers,
2328
localOptions: SymbolDisplayLocalOptions.IncludeType,
2429
miscellaneousOptions:
2530
SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
2631
SymbolDisplayMiscellaneousOptions.UseSpecialTypes |
27-
SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);
32+
SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier |
33+
SymbolDisplayMiscellaneousOptions.AllowDefaultLiteral);
34+
35+
internal static readonly SymbolDisplayFormat SymbolFormatDefaultValue = new SymbolDisplayFormat(
36+
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
37+
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
38+
memberOptions: SymbolDisplayMemberOptions.IncludeType,
39+
parameterOptions: SymbolDisplayParameterOptions.IncludeType);
2840
}

src/bunit.web.anglesharp/README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# Tips for developing with the generator
2+
13
When changing the source generator, to see the effect, clearing the build cache may be necessary:
24

3-
`dotnet build-server shutdown`
5+
```
6+
dotnet build-server shutdown
7+
```
8+
9+
A good way to quicky see if the generate is producing output:
10+
11+
```
12+
dotnet build-server shutdown && dotnet clean && dotnet test -p:TargetFramework=net8.0
13+
```

src/bunit.web.anglesharp/WrapperElementGenerator.cs

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.CodeAnalysis;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using System.Linq;
45
using System.Text;
56

@@ -18,7 +19,7 @@ internal static string GenerateWrapperTypeSource(StringBuilder source, INamedTyp
1819
source.AppendLine("""namespace Bunit.Web.AngleSharp;""");
1920
source.AppendLine();
2021
source.AppendLine("/// <inheritdoc/>");
21-
source.AppendLine("""[System.Diagnostics.DebuggerDisplay("{OuterHtml,nq}")]""");
22+
source.AppendLine("[System.Diagnostics.DebuggerDisplay(\"{OuterHtml,nq}\")]");
2223
source.AppendLine("[System.Diagnostics.DebuggerNonUserCode]");
2324
source.AppendLine("[System.CodeDom.Compiler.GeneratedCodeAttribute(\"Bunit.Web.AngleSharp\", \"1.0.0.0\")]");
2425
source.AppendLine($"internal sealed class {name} : WrapperBase<{wrappedTypeName}>, {wrappedTypeName}");
@@ -60,64 +61,59 @@ internal static string GenerateWrapperTypeSource(StringBuilder source, INamedTyp
6061

6162
private static void GenerateOrdinaryMethod(StringBuilder source, IMethodSymbol method)
6263
{
63-
// Determine the return type of the method
64-
string returnType = method.ReturnType.ToDisplayString(GeneratorConfig.SymbolFormat);
65-
66-
// Start building the method signature
67-
source.AppendLine();
68-
source.AppendLine("\t/// <inheritdoc/>");
69-
source.AppendLine("\t[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
70-
source.AppendLine("\t[System.Diagnostics.DebuggerHidden]");
71-
source.AppendLine("\t[System.Diagnostics.DebuggerStepThrough]");
72-
source.Append($"\tpublic {returnType} {method.Name}(");
73-
74-
// Append parameters directly to the StringBuilder using a for loop
75-
var parameters = method.Parameters;
76-
for (int i = 0; i < parameters.Length; i++)
64+
var methodParts = method.ToDisplayParts(GeneratorConfig.SymbolFormat);
65+
66+
// It seems that the ToDisplayParts will return ...
67+
//
68+
// public global::AngleSharp.Dom.IShadowRoot AttachShadow(global::AngleSharp.Dom.ShadowRootMode mode = 0)
69+
//
70+
// when called on a method with a default enum parameters specified.
71+
// However, the C# compiler changes this afterword to ...
72+
//
73+
// public global::AngleSharp.Dom.IShadowRoot AttachShadow(global::AngleSharp.Dom.ShadowRootMode mode = Open)
74+
//
75+
// which doesn't compile.
76+
// So this entire IF is there to fix this, and instead generate ...
77+
//
78+
// public global::AngleSharp.Dom.IShadowRoot AttachShadow(global::AngleSharp.Dom.ShadowRootMode mode = global::AngleSharp.Dom.ShadowRootMode.Open)
79+
if (method.Parameters.SingleOrDefault(x => x.HasExplicitDefaultValue && x.Type.BaseType?.ToString() == "System.Enum") is IParameterSymbol parameter)
7780
{
78-
if (i > 0)
79-
source.Append(", ");
80-
81-
source.Append($"{parameters[i].Type.ToDisplayString(GeneratorConfig.SymbolFormat)} {parameters[i].Name}");
81+
var defaultValue = parameter.Type
82+
.GetMembers()
83+
.OfType<IFieldSymbol>()
84+
.Single(x => x.ConstantValue == parameter.ExplicitDefaultValue);
85+
86+
methodParts = methodParts[0..^2]
87+
.AddRange(methodParts[0..2])
88+
.AddRange(defaultValue.ToDisplayParts())
89+
.Add(methodParts[^1]);
8290
}
8391

84-
// Complete the method signature and start the method body
85-
source.Append($") => WrappedElement.{method.Name}(");
86-
87-
// Append method invocation parameters using a for loop
88-
for (int i = 0; i < parameters.Length; i++)
89-
{
90-
if (i > 0)
91-
source.Append(", ");
92-
93-
source.Append(parameters[i].Name);
94-
}
95-
96-
// Close the method invocation
97-
source.AppendLine(");");
92+
source.AppendLine();
93+
source.AppendInheritDoc();
94+
source.AppendDefaultAttributes("\t");
95+
source.Append("\tpublic ").AppendLine(methodParts.ToDisplayString());
96+
source.Append($"\t\t=> WrappedElement.{method.Name}(")
97+
.AppendCallParameters(method.Parameters)
98+
.AppendLine(");");
9899
}
99100

100101
private static void GenerateRegularProperty(StringBuilder source, IPropertySymbol property)
101102
{
102103
source.AppendLine();
103-
source.AppendLine("\t/// <inheritdoc/>");
104-
source.Append($"\tpublic {property.Type.ToDisplayString(GeneratorConfig.SymbolFormat)} {property.Name}");
105-
source.AppendLine();
104+
source.AppendInheritDoc();
105+
source.Append("\tpublic ").AppendLine(property.ToDisplayString(GeneratorConfig.SymbolFormat));
106106
source.AppendLine("\t{");
107107

108108
if (property.GetMethod is IMethodSymbol)
109109
{
110-
source.AppendLine("\t\t[System.Diagnostics.DebuggerHidden]");
111-
source.AppendLine("\t\t[System.Diagnostics.DebuggerStepThrough]");
112-
source.AppendLine("\t\t[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
110+
source.AppendDefaultAttributes();
113111
source.AppendLine($"\t\tget => WrappedElement.{property.Name};");
114112
}
115113

116114
if (property.SetMethod is IMethodSymbol)
117115
{
118-
source.AppendLine("\t\t[System.Diagnostics.DebuggerHidden]");
119-
source.AppendLine("\t\t[System.Diagnostics.DebuggerStepThrough]");
120-
source.AppendLine("\t\t[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
116+
source.AppendDefaultAttributes();
121117
source.AppendLine($"\t\tset => WrappedElement.{property.Name} = value;");
122118
}
123119

@@ -127,55 +123,32 @@ private static void GenerateRegularProperty(StringBuilder source, IPropertySymbo
127123
private static void GenerateIndexerProperty(StringBuilder source, IPropertySymbol property)
128124
{
129125
source.AppendLine();
130-
source.AppendLine("\t/// <inheritdoc/>");
131-
source.Append($"\tpublic {property.Type.ToDisplayString(GeneratorConfig.SymbolFormat)} this[");
132-
133-
foreach (var p in property.Parameters)
134-
{
135-
source.Append($"{p.Type.ToDisplayString(GeneratorConfig.SymbolFormat)} {p.Name}");
136-
}
137-
138-
source.Append("]");
139-
source.AppendLine();
126+
source.AppendInheritDoc();
127+
source.Append("\tpublic ").AppendLine(property.ToDisplayString(GeneratorConfig.SymbolFormat));
140128
source.AppendLine("\t{");
141129

142130
if (property.GetMethod is IMethodSymbol)
143131
{
144-
source.AppendLine("\t\t[System.Diagnostics.DebuggerHidden]");
145-
source.AppendLine("\t\t[System.Diagnostics.DebuggerStepThrough]");
146-
source.AppendLine("\t\t[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
132+
source.AppendDefaultAttributes();
147133
source.Append("\t\tget => WrappedElement[");
148-
PrintCallParameters();
134+
source.AppendCallParameters(property.Parameters);
149135
source.AppendLine("];");
150136
}
151137

152138
if (property.SetMethod is IMethodSymbol)
153139
{
154-
source.AppendLine("\t\t[System.Diagnostics.DebuggerHidden]");
155-
source.AppendLine("\t\t[System.Diagnostics.DebuggerStepThrough]");
156-
source.AppendLine("\t\t[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
140+
source.AppendDefaultAttributes();
157141
source.Append("\t\tset => WrappedElement[");
158-
PrintCallParameters();
142+
source.AppendCallParameters(property.Parameters);
159143
source.AppendLine("] = value;");
160144
}
161145
source.AppendLine("\t}");
162-
163-
void PrintCallParameters()
164-
{
165-
for (int i = 0; i < property.Parameters.Length; i++)
166-
{
167-
if (i > 0)
168-
source.Append(", ");
169-
170-
source.Append(property.Parameters[i].Name);
171-
}
172-
}
173146
}
174147

175148
private static void GenerateEventProperty(StringBuilder source, IEventSymbol eventSymbol)
176149
{
177150
source.AppendLine();
178-
source.AppendLine("\t/// <inheritdoc/>");
151+
source.AppendInheritDoc();
179152
source.AppendLine($"\tpublic event {eventSymbol.Type.ToDisplayString(GeneratorConfig.SymbolFormat)} {eventSymbol.Name}");
180153
source.AppendLine("\t{");
181154
source.AppendLine("\t\t[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
@@ -200,6 +173,44 @@ private static IEnumerable<ISymbol> GetAllMembers(this INamedTypeSymbol symbol)
200173
}
201174
}
202175

176+
private static StringBuilder AppendInputArguments(this StringBuilder source, ImmutableArray<IParameterSymbol> parameters)
177+
{
178+
for (int i = 0; i < parameters.Length; i++)
179+
{
180+
if (i > 0)
181+
source.Append(", ");
182+
183+
source.Append($"{parameters[i].Type.ToDisplayString(GeneratorConfig.SymbolFormat)} {parameters[i].Name}");
184+
}
185+
return source;
186+
}
187+
188+
private static StringBuilder AppendCallParameters(this StringBuilder source, ImmutableArray<IParameterSymbol> parameters)
189+
{
190+
for (int i = 0; i < parameters.Length; i++)
191+
{
192+
if (i > 0)
193+
source.Append(", ");
194+
195+
source.Append(parameters[i].Name);
196+
}
197+
return source;
198+
}
199+
200+
private static StringBuilder AppendInheritDoc(this StringBuilder source)
201+
{
202+
source.AppendLine("\t/// <inheritdoc/>");
203+
return source;
204+
}
205+
206+
private static StringBuilder AppendDefaultAttributes(this StringBuilder source, string tabs = "\t\t")
207+
{
208+
source.Append(tabs).AppendLine("[System.Diagnostics.DebuggerHidden]");
209+
source.Append(tabs).AppendLine("[System.Diagnostics.DebuggerStepThrough]");
210+
source.Append(tabs).AppendLine("[System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]");
211+
return source;
212+
}
213+
203214
private static bool IsSpecialMethod(string methodName)
204215
{
205216
return methodName.StartsWith("add_") || methodName.StartsWith("remove_") ||

src/bunit.web.anglesharp/WrapperElementsGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3333

3434
private static void GenerateStaticContent(SourceProductionContext context, ISymbol assembly)
3535
{
36-
if (assembly is not IAssemblySymbol angleSharpAssembly)
36+
if (assembly is not IAssemblySymbol)
3737
return;
3838

3939
var elementFactorySource = ReadEmbeddedResource("Bunit.Web.AngleSharp.IElementFactory.cs");

src/bunit.web.anglesharp/bunit.web.anglesharp.csproj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@
1212
<EmbeddedResource Include="WrapperBase.cs" />
1313
</ItemGroup>
1414

15-
<ItemGroup>
15+
<ItemGroup>
1616
<PackageReference Include="AngleSharp" Version="1.0.7" />
17+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
1718
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
1819
<PrivateAssets>all</PrivateAssets>
1920
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2021
</PackageReference>
21-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
22+
<PackageReference Include="Meziantou.Polyfill" Version="1.0.30">
23+
<PrivateAssets>all</PrivateAssets>
24+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
25+
</PackageReference>
2226
</ItemGroup>
2327

2428
</Project>

src/bunit.web/bunit.web.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@
7878

7979
<ItemGroup>
8080
<ProjectReference Include="..\bunit.core\bunit.core.csproj" />
81-
<ProjectReference Include="..\bunit.web.anglesharp\bunit.web.anglesharp.csproj"
82-
OutputItemType="Analyzer"
83-
ReferenceOutputAssembly="false" />
81+
<ProjectReference Include="..\bunit.web.anglesharp\bunit.web.anglesharp.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
8482
</ItemGroup>
8583

8684
<ItemGroup Label="Implicit usings" Condition="$(MSBuildProjectName) != 'bunit.template' AND $(MSBuildProjectName) != 'bunit'">

0 commit comments

Comments
 (0)