MinimalHelpers
MinimalHelpers copied to clipboard
reference Microsoft.CodeAnalysis.CSharp version 4.9.2 is completely out of mind
Sorry if title feel harsh but how can i use source gen version if it reference Microsoft.CodeAnalysis.CSharp 4.9.2
while every tooling in newest Asp.Net core reference 4.5, is this lib suppose to use with preview version of .NET or we suppose to force reference 4.9.2 ??
i forked source gen version and build it myself using standard Microsoft.CodeAnalysis.CSharp
4.5.0 and it work fine, maybe there's some reason i dont know
this loc
if (!context.SemanticModel.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp11))
{
return default;
}
i dont see any point to force use 4.9.2 as 4.5.0 already contain definition for CSharp 11 and compatible with good amount of library outhere that target .Net 7+
we can event add branch to detect .Net 6 LanguageVersion.CSharp10
and .Net 7+ LanguageVersion.CSharp11
, with .Net 6 we generate register as
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder endpoints)
{
new global::TestRepo.Api.Routes.AccountRoute().MapEndpoints(endpoints);
return endpoints;
}
and for .Net 7+
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder endpoints)
{
global::TestRepo.Api.Routes.AccountRoute.MapEndpoints(endpoints);
return endpoints;
}
i propose my very simple implementation that can use in Net 6 +
// EndpointHandlerGenerator.cs
using System.Collections.Immutable;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MinimalHelpers.Routing.Analyzers;
[Generator]
public sealed class EndpointHandlerGenerator : IIncrementalGenerator
{
private static bool isLang11OrUp;
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context
.SyntaxProvider.CreateSyntaxProvider(
static (node, _) =>
node is ClassDeclarationSyntax classDeclaration
&& classDeclaration.HasOrPotentiallyHasBaseTypes(),
static (context, token) =>
{
var compilation = context.SemanticModel.Compilation;
if (!compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp10))
{
return default;
}
token.ThrowIfCancellationRequested();
isLang11OrUp = compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp11);
return (ClassDeclarationSyntax)context.Node;
}
)
.Where(static c => c is not null);
var compilation = context.CompilationProvider.Combine(provider.Collect());
context.RegisterSourceOutput(compilation, Execute!);
}
private static void Execute(
SourceProductionContext context,
(Compilation Compilation, ImmutableArray<ClassDeclarationSyntax> Classes) tuple
)
{
//#if DEBUG
// if (!Debugger.IsAttached)
// {
// Debugger.Launch();
// }
//#endif
var (_, classes) = tuple;
var @interface = GetIEndpointRouteHandlerBuilderInterface();
context.AddSource("IEndpointRouteHandlerBuilder.g.cs", @interface);
const string prefixCode = """
// <auto-generated />
namespace Microsoft.AspNetCore.Routing;
#nullable enable annotations
#nullable disable warnings
/// <summary>
/// Provides extension methods for <see cref="IEndpointRouteBuilder" /> to add route handlers.
/// </summary>
public static class EndpointRouteBuilderExtensions
{
/// <summary>
/// Automatically registers all the route endpoints defined in classes that implement the <see cref="IEndpointRouteHandlerBuilder "/> interface.
/// </summary>
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder" /> to add routes to.</param>
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder endpoints)
{
""";
const string suffixCode = """
return endpoints;
}
}
""";
var codeBuilder = new StringBuilder();
codeBuilder.AppendLine(prefixCode);
foreach (
var @class in classes.Where(c =>
c.BaseList?.Types.Any(t => t.Type.ToString() == "IEndpointRouteHandlerBuilder")
is true
)
)
{
var @namespace = GetNamespace(@class);
var fullClassName = $"{@namespace}.{@class.Identifier.Text}".TrimStart('.');
codeBuilder.AppendLine(
$" {(!isLang11OrUp ? $"new global::{fullClassName}()" : $"global::{fullClassName}")}.MapEndpoints(endpoints);"
);
}
codeBuilder.AppendLine(suffixCode);
context.AddSource("EndpointRouteBuilderExtensions.g.cs", codeBuilder.ToString());
}
private static string GetIEndpointRouteHandlerBuilderInterface() =>
$$"""
// <auto-generated />
namespace Microsoft.AspNetCore.Routing;
#nullable enable annotations
#nullable disable warnings
/// <summary>
/// Defines a contract for a class that holds one or more route handlers that must be registered by the application.
/// </summary>
public interface IEndpointRouteHandlerBuilder
{
/// <summary>
/// Maps route endpoints to the corresponding handlers.
/// </summary>
{{(
isLang11OrUp ? "static" : ""
)}} abstract void MapEndpoints(IEndpointRouteBuilder endpoints);
}
""";
// determine the namespace the class/enum/struct is declared in, if any
// https://andrewlock.net/creating-a-source-generator-part-5-finding-a-type-declarations-namespace-and-type-hierarchy/
private static string GetNamespace(BaseTypeDeclarationSyntax syntax)
{
var @namespace = string.Empty;
var potentialNamespaceParent = syntax.Parent;
while (
potentialNamespaceParent
is not null
and not NamespaceDeclarationSyntax
and not FileScopedNamespaceDeclarationSyntax
)
{
potentialNamespaceParent = potentialNamespaceParent.Parent;
}
if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent)
{
@namespace = namespaceParent.Name.ToString();
while (namespaceParent.Parent is NamespaceDeclarationSyntax parent)
{
@namespace = $"{namespaceParent.Name}.{@namespace}";
namespaceParent = parent;
}
}
return @namespace;
}
}
Could you please give me an example of an ASP.NET Core library that references Microsoft.CodeAnalysis.CSharp v4.5?
Closing as i choose another tool