@@ -10,48 +10,36 @@ namespace Microsoft.AspNetCore.SourceGenerators;
10
10
[ Generator ]
11
11
public class PublicProgramSourceGenerator : IIncrementalGenerator
12
12
{
13
+ private const string PublicPartialProgramClassSource = """
14
+ // <auto-generated />
15
+ public partial class Program { }
16
+ """ ;
17
+
13
18
public void Initialize ( IncrementalGeneratorInitializationContext context )
14
19
{
15
- var internalGeneratedProgramClass = context . CompilationProvider . Select ( ( compilation , cancellationToken ) =>
16
- {
17
- var program = compilation . GetTypeByMetadataName ( "Program" ) ;
20
+ var internalGeneratedProgramClass = context . CompilationProvider
21
+ // Get the entry point associated with the compilation, this maps to the Main method definition
22
+ . Select ( ( compilation , cancellationToken ) => compilation . GetEntryPoint ( cancellationToken ) )
23
+ // Get the containing symbol of the entry point, this maps to the Program class
24
+ . Select ( ( symbol , _ ) => symbol ? . ContainingSymbol )
18
25
// If the program class is already public, we don't need to generate anything.
19
- if ( program is null || program . DeclaredAccessibility == Accessibility . Public )
20
- {
21
- return null ;
22
- }
26
+ . Select ( ( symbol , _ ) => symbol ? . DeclaredAccessibility == Accessibility . Public ? null : symbol )
23
27
// If the discovered `Program` type is an interface, struct or generic type then its not
24
28
// generated and has been defined in source, so we can skip it
25
- if ( program . TypeKind == TypeKind . Struct || program . TypeKind == TypeKind . Interface || program . IsGenericType )
26
- {
27
- return null ;
28
- }
29
+ . Select ( ( symbol , _ ) => symbol is INamedTypeSymbol namedSymbol
30
+ && ( namedSymbol . TypeKind == TypeKind . Struct || namedSymbol . TypeKind == TypeKind . Interface || namedSymbol . IsGenericType ) ? null : symbol )
29
31
// If there are multiple partial declarations, then do nothing since we don't want
30
32
// to trample on visibility explicitly set by the user
31
- if ( program . DeclaringSyntaxReferences . Length > 1 )
32
- {
33
- return null ;
34
- }
33
+ . Select ( ( symbol , _ ) => symbol ? . DeclaringSyntaxReferences . Length > 1 ? null : symbol )
35
34
// If the `Program` class is already declared in user code, we don't need to generate anything.
36
- if ( program . DeclaringSyntaxReferences . SingleOrDefault ( ) ? . GetSyntax ( cancellationToken ) is ClassDeclarationSyntax )
37
- {
38
- return null ;
39
- }
40
- return program ;
41
- } ) ;
35
+ . Select ( ( symbol , cancellationToken ) => symbol ? . DeclaringSyntaxReferences . SingleOrDefault ( ) ? . GetSyntax ( cancellationToken ) is ClassDeclarationSyntax ? null : symbol ) ;
42
36
43
37
context . RegisterSourceOutput ( internalGeneratedProgramClass , ( context , symbol ) =>
44
38
{
45
- if ( symbol is null )
39
+ if ( symbol is not null )
46
40
{
47
- return ;
41
+ context . AddSource ( "PublicTopLevelProgram.Generated.g.cs" , PublicPartialProgramClassSource ) ;
48
42
}
49
-
50
- var output = """
51
- // <auto-generated />
52
- public partial class Program { }
53
- """ ;
54
- context . AddSource ( "PublicTopLevelProgram.Generated.cs" , output ) ;
55
43
} ) ;
56
44
}
57
45
}