Skip to content

Commit

Permalink
Implement first draft of TransformBehavior
Browse files Browse the repository at this point in the history
  • Loading branch information
viceroypenguin committed Jan 5, 2024
1 parent ef565ef commit 1ea0562
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
83 changes: 74 additions & 9 deletions src/Immediate.Handlers/Generators/ImmediateHandlersGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ public class ImmediateHandlersGenerator : IIncrementalGenerator
{
private sealed record Behavior
{
public required string Name { get; set; }
public required string FullTypeName { get; set; }
public required string? TRequest { get; set; }
public required string? TResponse { get; set; }
public required string RegistrationType { get; init; }
public required string ConstructorType { get; init; }
public required bool IsGeneric { get; init; }
public required string? TRequest { get; init; }
public required string? TResponse { get; init; }
}

private sealed record Handler
Expand All @@ -37,7 +38,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var behaviors = context.SyntaxProvider
.ForAttributeWithMetadataName(
"Immediate.Handlers.Shared.BehaviorsAttribute",
predicate: (_, _) => true,
(node, _) => node is CompilationUnitSyntax,
TransformBehaviors
)
.SelectMany((x, _) => x)
Expand Down Expand Up @@ -85,15 +86,79 @@ private RenderMode TransformRenderMode(GeneratorAttributeSyntaxContext context,
}
}

private static ImmutableArray<Behavior> TransformBehaviors(
private static ImmutableArray<Behavior?> TransformBehaviors(
GeneratorAttributeSyntaxContext context,
CancellationToken cancellationToken
)
{
return ImmutableArray.Create<Behavior>();
cancellationToken.ThrowIfCancellationRequested();

var semanticModel = context.SemanticModel;
var compilation = semanticModel.Compilation;
cancellationToken.ThrowIfCancellationRequested();

var attr = context.Attributes[0];
if (attr.ConstructorArguments.Length != 1)
return ImmutableArray<Behavior?>.Empty;

var ca = attr.ConstructorArguments[0];
var arrayTypeSymbol = compilation.CreateArrayTypeSymbol(
compilation.GetTypeByMetadataName("System.Type")!, 1)!;
if (!SymbolEqualityComparer.Default.Equals(
ca.Type,
arrayTypeSymbol
))
{
return ImmutableArray<Behavior?>.Empty;
}

cancellationToken.ThrowIfCancellationRequested();
var behaviorType = typeof(Behavior<,>);
var behaviorTypeSymbol = compilation.GetTypeByMetadataName(behaviorType.FullName);
if (behaviorTypeSymbol is null)
return ImmutableArray<Behavior?>.Empty;

cancellationToken.ThrowIfCancellationRequested();
var behaviors = ca.Values
.Select(v =>
{
cancellationToken.ThrowIfCancellationRequested();
if (v.Value is not INamedTypeSymbol symbol)
return null;

var originalDefinition = symbol.OriginalDefinition;
if (SymbolEqualityComparer.Default.Equals(originalDefinition, behaviorTypeSymbol))
return null;

if (!originalDefinition.ImplementsBaseClass(behaviorTypeSymbol))
return null;

if (symbol.IsUnboundGenericType && symbol.TypeParameters.Length == 2)
{
// services.AddScoped<global::Dummy.LoggingBehavior<,>>();
// global::Dummy.LoggingBehavior<,>
var typeName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
return new Behavior
{
RegistrationType = typeName,
ConstructorType = typeName,
IsGeneric = true,
TRequest = null,
TResponse = null,
};
}

// TODO:
// 1. figure out TRequest and TResponse
// 2. figure out if type is bounded on either side
throw new NotImplementedException();
})
.ToArray();

return ImmutableArray.Create(behaviors);
}

private static void RenderServiceCollectionExtension(SourceProductionContext context, (ImmutableArray<string> handlers, ImmutableArray<Behavior> behaviors) node)
private static void RenderServiceCollectionExtension(SourceProductionContext context, (ImmutableArray<string> handlers, ImmutableArray<Behavior?> behaviors) node)
{
var template = GetTemplate("ServiceCollectionExtensions");
var source = template.Render(new
Expand All @@ -115,7 +180,7 @@ CancellationToken cancellationToken
private static void RenderHandler(
SourceProductionContext context,
Handler handler,
ImmutableArray<Behavior> behaviors,
ImmutableArray<Behavior?> behaviors,
ImmutableArray<RenderMode> renderModes,
Template template
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public static class HandlerServiceCollectionExtensions
this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services)
{
{{~ for b in behaviors ~}}
services.AddScoped(typeof({{ b.full_type_name }}));
services.AddScoped(typeof({{ b.registration_type }}));
{{~ end ~}}
{{~ for h in handlers ~}}
{{ h }}.AddHandlers(services);
Expand Down
12 changes: 12 additions & 0 deletions src/Immediate.Handlers/Utility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.CodeAnalysis;

namespace Immediate.Handlers;

internal static class Utility
{
public static bool ImplementsBaseClass(this INamedTypeSymbol typeSymbol, INamedTypeSymbol typeToCheck) =>
SymbolEqualityComparer.Default.Equals(typeSymbol, typeToCheck)
|| (typeSymbol.BaseType is not null
&& ImplementsBaseClass(typeSymbol.BaseType.OriginalDefinition, typeToCheck)
);
}

0 comments on commit 1ea0562

Please sign in to comment.