@@ -10,48 +10,35 @@ 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
- }
23
- // If the discovered `Program` type is an interface, struct or generic type then its not
26
+ . Select ( ( symbol , _ ) => symbol ? . DeclaredAccessibility == Accessibility . Public ? null : symbol )
27
+ // If the discovered `Program` type is not a class 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 { TypeKind : TypeKind . Class } ? symbol : null )
29
30
// If there are multiple partial declarations, then do nothing since we don't want
30
31
// to trample on visibility explicitly set by the user
31
- if ( program . DeclaringSyntaxReferences . Length > 1 )
32
- {
33
- return null ;
34
- }
32
+ . Select ( ( symbol , _ ) => symbol is { DeclaringSyntaxReferences : { Length : 1 } declaringSyntaxReferences } ? declaringSyntaxReferences . Single ( ) : null )
35
33
// 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
- } ) ;
34
+ . Select ( ( declaringSyntaxReference , cancellationToken ) => declaringSyntaxReference ? . GetSyntax ( cancellationToken ) is ClassDeclarationSyntax ? null : declaringSyntaxReference ) ;
42
35
43
- context . RegisterSourceOutput ( internalGeneratedProgramClass , ( context , symbol ) =>
36
+ context . RegisterSourceOutput ( internalGeneratedProgramClass , ( context , result ) =>
44
37
{
45
- if ( symbol is null )
38
+ if ( result is not null )
46
39
{
47
- return ;
40
+ context . AddSource ( "PublicTopLevelProgram.Generated.g.cs" , PublicPartialProgramClassSource ) ;
48
41
}
49
-
50
- var output = """
51
- // <auto-generated />
52
- public partial class Program { }
53
- """ ;
54
- context . AddSource ( "PublicTopLevelProgram.Generated.cs" , output ) ;
55
42
} ) ;
56
43
}
57
44
}