Skip to content

Commit

Permalink
Do not emit unused fields in RDG source (#48426)
Browse files Browse the repository at this point in the history
* Do not emit unused fields in RDG source

Do not emit unused private fields for HTTP verbs that are not used by any of the user-code endpoints.
Resolves #48381.

* Move verbs to incremental pipeline

Use another incremental pipeline to produce the HTTP verbs.

* Add custom comparer

Add custom comparer for endpoints by their HTTP method.
  • Loading branch information
martincostello authored Jul 10, 2023
1 parent b930c67 commit 427163d
Show file tree
Hide file tree
Showing 42 changed files with 88 additions and 181 deletions.
32 changes: 25 additions & 7 deletions src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Analyzers.Infrastructure;
using Microsoft.AspNetCore.App.Analyzers.Infrastructure;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel.Emitters;
using Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel;
using Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel.Emitters;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Operations;

namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator;

Expand Down Expand Up @@ -122,7 +123,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Collect()
.Select((endpoints, _) =>
{
var dedupedByDelegate = endpoints.Distinct<Endpoint>(EndpointDelegateComparer.Instance);
var dedupedByDelegate = endpoints.Distinct(EndpointDelegateComparer.Instance);
using var stringWriter = new StringWriter(CultureInfo.InvariantCulture);
using var codeWriter = new CodeWriter(stringWriter, baseIndent: 2);
foreach (var endpoint in dedupedByDelegate)
Expand Down Expand Up @@ -169,6 +170,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return stringWriter.ToString();
});

var httpVerbs = endpoints
.Collect()
.Select((endpoints, _) =>
{
return endpoints
.Distinct(EndpointHttpMethodComparer.Instance)
.Select(endpoint => endpoint.EmitterContext.HttpMethod!)
.Where(verb => verb is not null)
.ToImmutableHashSet();
});

var endpointHelpers = endpoints
.Collect()
.Select((endpoints, _) =>
Expand Down Expand Up @@ -260,11 +272,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return stringWriter.ToString();
});

var thunksAndEndpoints = thunks.Collect().Combine(stronglyTypedEndpointDefinitions).Combine(endpointHelpers).Combine(helperTypes);
var thunksAndEndpoints = thunks
.Collect()
.Combine(stronglyTypedEndpointDefinitions)
.Combine(httpVerbs)
.Combine(endpointHelpers)
.Combine(helperTypes);

context.RegisterSourceOutput(thunksAndEndpoints, (context, sources) =>
{
var (((thunks, endpointsCode), helperMethods), helperTypes) = sources;
var ((((thunks, endpointsCode), httpVerbs), helperMethods), helperTypes) = sources;
if (thunks.IsDefaultOrEmpty || string.IsNullOrEmpty(endpointsCode))
{
Expand All @@ -282,7 +299,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
thunks: thunksCode.ToString(),
endpoints: endpointsCode,
helperMethods: helperMethods ?? string.Empty,
helperTypes: helperTypes ?? string.Empty);
helperTypes: helperTypes ?? string.Empty,
verbs: httpVerbs);
context.AddSource("GeneratedRouteBuilderExtensions.g.cs", code);
});
Expand Down
42 changes: 33 additions & 9 deletions src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.CSharp;
namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator;

Expand Down Expand Up @@ -436,7 +439,7 @@ public override bool IsDefined(Type attributeType, bool inherit)
}
""";
public static string GetGeneratedRouteBuilderExtensionsSource(string genericThunks, string thunks, string endpoints, string helperMethods, string helperTypes) => $$"""
public static string GetGeneratedRouteBuilderExtensionsSource(string genericThunks, string thunks, string endpoints, string helperMethods, string helperTypes, ImmutableHashSet<string> verbs) => $$"""
{{SourceHeader}}
namespace Microsoft.AspNetCore.Builder
Expand All @@ -454,7 +457,7 @@ public SourceKey(string path, int line)
}
}
{{GetEndpoints(endpoints)}}
{{GetEndpoints(endpoints, verbs)}}
}
namespace Microsoft.AspNetCore.Http.Generated
Expand Down Expand Up @@ -595,7 +598,15 @@ internal static RouteHandlerBuilder MapCore(
}
""" : string.Empty;
private static string GetEndpoints(string endpoints) => endpoints != string.Empty ? $$"""
private static string GetEndpoints(string endpoints, ImmutableHashSet<string> verbs)
{
if (endpoints == string.Empty)
{
return string.Empty;
}
var builder = new StringBuilder();
builder.Append($$"""
// This class needs to be internal so that the compiled application
// has access to the strongly-typed endpoint definitions that are
// generated by the compiler so that they will be favored by
Expand All @@ -604,13 +615,26 @@ private static string GetEndpoints(string endpoints) => endpoints != string.Empt
{{GeneratedCodeAttribute}}
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };
""");
foreach (string verb in verbs.OrderBy(p => p, System.StringComparer.Ordinal))
{
builder.AppendLine($$"""
private static readonly string[] {{verb}}Verb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.{{verb}} };
""");
}
if (verbs.Count > 0)
{
builder.AppendLine();
}
builder.Append($$"""
{{endpoints}}
}
""" : string.Empty;
""");
return builder.ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ internal sealed class EmitterContext
public bool HasEndpointMetadataProvider { get; set; }
public bool HasEndpointParameterMetadataProvider { get; set; }
public bool HasResponseMetadata { get; set; }
public string? HttpMethod { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel;

internal sealed class EndpointHttpMethodComparer : IEqualityComparer<Endpoint>
{
public static readonly EndpointHttpMethodComparer Instance = new();
private static readonly IEqualityComparer<string> OrdinalComparer = StringComparer.Ordinal;

public bool Equals(Endpoint x, Endpoint y) => OrdinalComparer.Equals(x.HttpMethod, y.HttpMethod);

public int GetHashCode(Endpoint obj) => OrdinalComparer.GetHashCode(obj.HttpMethod);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,20 @@ public static string EmitSourceKey(this Endpoint endpoint)

public static string EmitVerb(this Endpoint endpoint)
{
return endpoint.HttpMethod switch
{
"MapGet" => "GetVerb",
"MapPut" => "PutVerb",
"MapPost" => "PostVerb",
"MapDelete" => "DeleteVerb",
"MapPatch" => "PatchVerb",
"MapMethods" => "httpMethods",
"Map" => "null",
"MapFallback" => "null",
(var verbSymbol, endpoint.EmitterContext.HttpMethod) = endpoint.HttpMethod switch
{
"MapGet" => ("GetVerb", "Get"),
"MapPut" => ("PutVerb", "Put"),
"MapPost" => ("PostVerb", "Post"),
"MapDelete" => ("DeleteVerb", "Delete"),
"MapPatch" => ("PatchVerb", "Patch"),
"MapMethods" => ("httpMethods", null),
"Map" => ("null", null),
"MapFallback" => ("null", null),
_ => throw new ArgumentException($"Received unexpected HTTP method: {endpoint.HttpMethod}")
};

return verbSymbol;
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ namespace Microsoft.AspNetCore.Builder
%GENERATEDCODEATTRIBUTE%
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ namespace Microsoft.AspNetCore.Builder
internal static class GenerateRouteBuilderEndpoints
{
private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get };
private static readonly string[] PostVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Post };
private static readonly string[] PutVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Put };
private static readonly string[] DeleteVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Delete };
private static readonly string[] PatchVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Patch };

internal static global::Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(
this global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints,
Expand Down
Loading

0 comments on commit 427163d

Please sign in to comment.