Skip to content

Commit

Permalink
Optimize generator by checking invocations in the predicate
Browse files Browse the repository at this point in the history
Rather than on the transform. This should reduce the amount of invocations to the transform delegate and improve performance.
  • Loading branch information
kzu committed Nov 13, 2024
1 parent e7ba415 commit 3d8089d
Showing 1 changed file with 9 additions and 13 deletions.
22 changes: 9 additions & 13 deletions src/DependencyInjection/IncrementalGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ bool IsExport(AttributeData attr)
// First get all AddServices(type, regex, lifetime) invocations.
var methodInvocations = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (node, _) => node is InvocationExpressionSyntax,
predicate: static (node, _) => node is InvocationExpressionSyntax invocation && invocation.ArgumentList.Arguments.Count != 0 && GetInvokedMethodName(invocation) == nameof(AddServicesNoReflectionExtension.AddServices),
transform: static (ctx, _) => GetServiceRegistration((InvocationExpressionSyntax)ctx.Node, ctx.SemanticModel))
.Where(details => details != null)
.Collect();
Expand Down Expand Up @@ -205,21 +205,17 @@ void RegisterServicesOutput(IncrementalGeneratorInitializationContext context, I
(ctx, data) => AddPartial("AddKeyedTransient", ctx, data));
}

static ServiceRegistration? GetServiceRegistration(InvocationExpressionSyntax invocation, SemanticModel semanticModel)
static string? GetInvokedMethodName(InvocationExpressionSyntax invocation) => invocation.Expression switch
{
static string? GetInvokedMethodName(InvocationExpressionSyntax invocation) => invocation.Expression switch
{
MemberAccessExpressionSyntax memberAccess => memberAccess.Name.Identifier.Text,
IdentifierNameSyntax identifierName => identifierName.Identifier.Text,
_ => null
};

// Quick checks first without semantic analysis of any kind.
if (invocation.ArgumentList.Arguments.Count == 0 || GetInvokedMethodName(invocation) != nameof(AddServicesNoReflectionExtension.AddServices))
return null;
MemberAccessExpressionSyntax memberAccess => memberAccess.Name.Identifier.Text,
IdentifierNameSyntax identifierName => identifierName.Identifier.Text,
_ => null
};

static ServiceRegistration? GetServiceRegistration(InvocationExpressionSyntax invocation, SemanticModel semanticModel)
{
// This is somewhat expensive, so we try to first discard invocations that don't look like our
// target first (no args and wrong method name), before moving on to semantic analyis.
// target first (no args and wrong method name), in the predicate, before moving on to semantic analyis here.

var options = (CSharpParseOptions)invocation.SyntaxTree.Options;

Expand Down

0 comments on commit 3d8089d

Please sign in to comment.