File: PublicTopLevelProgramGenerator.cs
Web Access
Project: src\src\Framework\AspNetCoreAnalyzers\src\SourceGenerators\Microsoft.AspNetCore.App.SourceGenerators.csproj (Microsoft.AspNetCore.App.SourceGenerators)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
 
namespace Microsoft.AspNetCore.SourceGenerators;
 
[Generator]
public class PublicProgramSourceGenerator : IIncrementalGenerator
{
    private const string PublicPartialProgramClassSource = """
// <auto-generated />
public partial class Program { }
""";
 
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        var internalGeneratedProgramClass = context.CompilationProvider
            // Get the entry point associated with the compilation, this maps to the Main method definition
            .Select(static (compilation, cancellationToken) => compilation.GetEntryPoint(cancellationToken))
            // Get the containing symbol of the entry point, this maps to the Program class
            .Select(static (symbol, _) => symbol?.ContainingSymbol)
            // If the program class is already public, we don't need to generate anything.
            .Select(static (symbol, _) => symbol?.DeclaredAccessibility == Accessibility.Public ? null : symbol)
            // If the discovered `Program` type is not a class then its not
            // generated and has been defined in source, so we can skip it
            .Select(static (symbol, _) => symbol is INamedTypeSymbol { TypeKind: TypeKind.Class } ? symbol : null)
            // If there are multiple partial declarations, then do nothing since we don't want
            // to trample on visibility explicitly set by the user
            .Select(static (symbol, _) => symbol is { DeclaringSyntaxReferences: { Length: 1 } declaringSyntaxReferences } ? declaringSyntaxReferences.Single() : null)
            // If the `Program` class is already declared in user code, we don't need to generate anything.
            .Select(static (declaringSyntaxReference, cancellationToken) => declaringSyntaxReference?.GetSyntax(cancellationToken) is ClassDeclarationSyntax ? null : declaringSyntaxReference);
 
        context.RegisterSourceOutput(internalGeneratedProgramClass, (context, result) =>
        {
            if (result is not null)
            {
                context.AddSource("PublicTopLevelProgram.Generated.g.cs", PublicPartialProgramClassSource);
            }
        });
    }
}