Skip to content

Commit 6ffab87

Browse files
Suppress CS1591 warnings for PublicTopLevelProgram.Generated.g.cs (#60727)
* Added pragma to suppress CS1591 in generated code * Fixed program declaration in explicit namespace * Accounted for comments, reverting additional logic
1 parent 1f82fa5 commit 6ffab87

File tree

2 files changed

+122
-15
lines changed

2 files changed

+122
-15
lines changed

src/Framework/AspNetCoreAnalyzers/src/SourceGenerators/PublicTopLevelProgramGenerator.cs

+13-11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ public class PublicProgramSourceGenerator : IIncrementalGenerator
1212
{
1313
private const string PublicPartialProgramClassSource = """
1414
// <auto-generated />
15+
#pragma warning disable CS1591
1516
public partial class Program { }
17+
#pragma warning restore CS1591
1618
""";
1719

1820
public void Initialize(IncrementalGeneratorInitializationContext context)
@@ -21,17 +23,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
2123
// Get the entry point associated with the compilation, this maps to the Main method definition
2224
// Get the containing symbol of the entry point, this maps to the Program class
2325
compilation.GetEntryPoint(cancellationToken)?.ContainingSymbol is INamedTypeSymbol
24-
{
25-
// If the discovered `Program` type is not a class then its not
26-
// generated and has been defined in source, so we can skip it
27-
// If the program class is already public, we don't need to generate anything.
28-
DeclaredAccessibility: not Accessibility.Public,
29-
TypeKind: TypeKind.Class,
30-
// If there are multiple partial declarations, then do nothing since we don't want
31-
// to trample on visibility explicitly set by the user
32-
DeclaringSyntaxReferences: { Length: 1 } declaringSyntaxReferences
33-
} &&
34-
// If the `Program` class is already declared in user code, we don't need to generate anything.
26+
{
27+
// If the program class is already public, we don't need to generate anything
28+
DeclaredAccessibility: not Accessibility.Public,
29+
// If the discovered `Program` type is not a class then its not
30+
// generated and has been defined in source, so we can skip it
31+
TypeKind: TypeKind.Class,
32+
// If there are multiple partial declarations, then do nothing since we don't want
33+
// to trample on visibility explicitly set by the user
34+
DeclaringSyntaxReferences: { Length: 1 } declaringSyntaxReferences
35+
} &&
36+
// If the `Program` class is already declared in user code, we don't need to generate anything
3537
declaringSyntaxReferences.Single().GetSyntax(cancellationToken) is not ClassDeclarationSyntax
3638
);
3739

src/Framework/AspNetCoreAnalyzers/test/SourceGenerators/PublicTopLevelProgramGeneratorTests.cs

+109-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ namespace Microsoft.AspNetCore.SourceGenerators.Tests;
77

88
public class PublicTopLevelProgramGeneratorTests
99
{
10+
private const string ExpectedGeneratedSource = """
11+
// <auto-generated />
12+
#pragma warning disable CS1591
13+
public partial class Program { }
14+
#pragma warning restore CS1591
15+
""";
16+
1017
[Fact]
1118
public async Task GeneratesSource_ProgramWithTopLevelStatements()
1219
{
@@ -20,12 +27,33 @@ public async Task GeneratesSource_ProgramWithTopLevelStatements()
2027
app.Run();
2128
""";
2229

23-
var expected = """
24-
// <auto-generated />
25-
public partial class Program { }
30+
await VerifyCS.VerifyAsync(source, "PublicTopLevelProgram.Generated.g.cs", ExpectedGeneratedSource);
31+
}
32+
33+
// The compiler synthesizes a Program class in the global namespace due to top-level statements
34+
// The Foo.Program class is completely unrelated to the entry point and is just as any regular type
35+
// Hence, we will expect to see the source generated in these scenarios
36+
[Theory]
37+
[InlineData("public partial class Program { }")]
38+
[InlineData("internal partial class Program { }")]
39+
public async Task GeneratesSource_IfProgramDefinedInANamespace (string declaration)
40+
{
41+
var source = $$"""
42+
using Microsoft.AspNetCore.Builder;
43+
44+
var app = WebApplication.Create();
45+
46+
app.MapGet("/", () => "Hello, World!");
47+
48+
app.Run();
49+
50+
namespace Foo
51+
{
52+
{{declaration}}
53+
}
2654
""";
2755

28-
await VerifyCS.VerifyAsync(source, "PublicTopLevelProgram.Generated.g.cs", expected);
56+
await VerifyCS.VerifyAsync(source, "PublicTopLevelProgram.Generated.g.cs", ExpectedGeneratedSource);
2957
}
3058

3159
[Fact]
@@ -86,6 +114,31 @@ public static void Main()
86114
await VerifyCS.VerifyAsync(source);
87115
}
88116

117+
[Fact]
118+
public async Task DoesNotGeneratorSource_ExplicitPublicProgramClassInNamespace()
119+
{
120+
var source = """
121+
using Microsoft.AspNetCore.Builder;
122+
123+
namespace Foo
124+
{
125+
public class Program
126+
{
127+
public static void Main()
128+
{
129+
var app = WebApplication.Create();
130+
131+
app.MapGet("/", () => "Hello, World!");
132+
133+
app.Run();
134+
}
135+
}
136+
}
137+
""";
138+
139+
await VerifyCS.VerifyAsync(source);
140+
}
141+
89142
[Fact]
90143
public async Task DoesNotGeneratorSource_ExplicitInternalProgramClass()
91144
{
@@ -108,6 +161,31 @@ public static void Main()
108161
await VerifyCS.VerifyAsync(source);
109162
}
110163

164+
[Fact]
165+
public async Task DoesNotGeneratorSource_ExplicitInternalProgramClassInNamespace()
166+
{
167+
var source = """
168+
using Microsoft.AspNetCore.Builder;
169+
170+
namespace Foo
171+
{
172+
internal class Program
173+
{
174+
public static void Main()
175+
{
176+
var app = WebApplication.Create();
177+
178+
app.MapGet("/", () => "Hello, World!");
179+
180+
app.Run();
181+
}
182+
}
183+
}
184+
""";
185+
186+
await VerifyCS.VerifyAsync(source);
187+
}
188+
111189
[Theory]
112190
[InlineData("interface")]
113191
[InlineData("struct")]
@@ -127,6 +205,33 @@ public static void Main(string[] args)
127205
app.Run();
128206
}
129207
}
208+
""";
209+
210+
await VerifyCS.VerifyAsync(source);
211+
}
212+
213+
[Theory]
214+
[InlineData("interface")]
215+
[InlineData("struct")]
216+
public async Task DoesNotGeneratorSource_ExplicitInternalProgramTypeInNamespace(string type)
217+
{
218+
var source = $$"""
219+
using Microsoft.AspNetCore.Builder;
220+
221+
namespace Foo
222+
{
223+
internal {{type}} Program
224+
{
225+
public static void Main(string[] args)
226+
{
227+
var app = WebApplication.Create();
228+
229+
app.MapGet("/", () => "Hello, World!");
230+
231+
app.Run();
232+
}
233+
}
234+
}
130235
""";
131236

132237
await VerifyCS.VerifyAsync(source);

0 commit comments

Comments
 (0)