Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
hadashiA committed Jun 4, 2024
1 parent fac93e0 commit c6451c5
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 85 deletions.
96 changes: 96 additions & 0 deletions VContainer.SourceGenerator/Analyzer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace VContainer.SourceGenerator;

static class Analyzer
{
public static bool ContainsPotentialRegisterCall(string call)
{
return call.IndexOf(".Register", StringComparison.Ordinal) > 0;
}

public static TypeMeta? AnalyzeTypeSymbol(ITypeSymbol symbol, ReferenceSymbols referenceSymbols, CancellationToken cancellation = default)
{
{
if (symbol is not INamedTypeSymbol typeSymbol)
{
return null;
}

foreach (var baseTypeSymbol in typeSymbol.GetAllBaseTypes())
{
var name = baseTypeSymbol.ToDisplayString();
// Ignore
if (name == "System.Attributes")
{
return null;
}
}

foreach (var attributeData in typeSymbol.GetAttributes())
{
if (attributeData.AttributeClass != null)
{
// Ignore
if (attributeData.AttributeClass.ToDisplayString() == "VContainer.InjectIgnoreAttribute")
return null;
}

}
return new TypeMeta(Syntax, typeSymbol, referenceSymbols);

Check failure on line 44 in VContainer.SourceGenerator/Analyzer.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

The name 'Syntax' does not exist in the current context
}
}
}

record struct TypeDeclarationCandidate(TypeDeclarationSyntax Syntax, SemanticModel SemanticModel)
{
public TypeMeta? Analyze(ReferenceSymbols referenceSymbols, CancellationToken cancellation = default)
{
var symbol = SemanticModel.GetDeclaredSymbol(Syntax);
if (symbol is ITypeSymbol typeSymbol)
return Analyzer.AnalyzeTypeSymbol(typeSymbol, referenceSymbols);
return null;
}
}

record struct RegisterInvocationCandidate(InvocationExpressionSyntax Syntax, SemanticModel SemanticModel)
{
public IEnumerable<TypeMeta> Analyze(ReferenceSymbols referenceSymbols, CancellationToken cancellation = default)
{
var symbol = SemanticModel.GetSymbolInfo(Syntax).Symbol;
if (symbol is IMethodSymbol methodSymbol)
{
var typeSymbol = methodSymbol.ReceiverType;
if (SymbolEqualityComparer.Default.Equals(typeSymbol, referenceSymbols.ContainerBuilderInterface))
{
if (methodSymbol.Arity > 0)
{
foreach (var typeArgument in methodSymbol.TypeArguments)
{
if (typeArgument.TypeKind is TypeKind.Interface or TypeKind.Struct)
{
continue;
}
if (typeArgument.IsAbstract)
{
continue;
}

yield return Analyzer.AnalyzeTypeSymbol(typeArgument.ContainingType);

Check failure on line 83 in VContainer.SourceGenerator/Analyzer.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

There is no argument given that corresponds to the required parameter 'referenceSymbols' of 'Analyzer.AnalyzeTypeSymbol(ITypeSymbol, ReferenceSymbols, CancellationToken)'
}
}
else
{
foreach (var p in methodSymbol.Parameters)
{
yield return Analyzer.AnalyzeTypeSymbol(p.Type);

Check failure on line 90 in VContainer.SourceGenerator/Analyzer.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

There is no argument given that corresponds to the required parameter 'referenceSymbols' of 'Analyzer.AnalyzeTypeSymbol(ITypeSymbol, ReferenceSymbols, CancellationToken)'
}
}
}
}
}
}
19 changes: 0 additions & 19 deletions VContainer.SourceGenerator/RegisterInvocationCandidate.cs

This file was deleted.

9 changes: 5 additions & 4 deletions VContainer.SourceGenerator/TypeMeta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace VContainer.SourceGenerator;

class TypeMeta
{
public TypeDeclarationSyntax Syntax { get; }
public INamedTypeSymbol Symbol { get; }
public string TypeName { get; }
public string FullTypeName { get; }
Expand All @@ -20,11 +21,11 @@ class TypeMeta

public bool IsGenerics => Symbol.Arity > 0;

ReferenceSymbols references;
TypeDeclarationSyntax? syntax;
readonly ReferenceSymbols references;

public TypeMeta(INamedTypeSymbol symbol, ReferenceSymbols references, TypeDeclarationSyntax? syntax = null)
public TypeMeta(TypeDeclarationSyntax syntax, INamedTypeSymbol symbol, ReferenceSymbols references)
{
Syntax = syntax;
Symbol = symbol;
this.references = references;

Expand All @@ -45,7 +46,7 @@ public TypeMeta(INamedTypeSymbol symbol, ReferenceSymbols references, TypeDeclar

public Location GetLocation()
{
return syntax?.Identifier.GetLocation() ?? Symbol.Locations.FirstOrDefault() ?? Location.None;
return Syntax.Identifier.GetLocation();
}

public bool InheritsFrom(INamedTypeSymbol baseSymbol)
Expand Down
90 changes: 28 additions & 62 deletions VContainer.SourceGenerator/VContainerIncrementalSourceGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand Down Expand Up @@ -37,30 +35,29 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
});

// Find Types based on Register* methods
var incrementalValueProvider3 = context.SyntaxProvider
var registerInvocations = context.SyntaxProvider
.CreateSyntaxProvider(
(s, cancellation) =>
{
if (s is InvocationExpressionSyntax syntax &&
RegisterInvocationFinder.ContainsPotentialRegisterCall(syntax.ToString()))
Analyzer.ContainsPotentialRegisterCall(syntax.ToString()))
{
return true;
}
return false;
},
(generatorSyntaxContext, cancellation) => generatorSyntaxContext)
(ctx, cancellation) => ctx)
.Combine(vcontainerReferenceValueProvider)
.Where(tuple => tuple.Right)
.Select((tuple, cancellation) =>
{
var context = tuple.Left;
var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node;
var recieverSymbolInfo = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax.Expression).Symbol;
if (SymbolEqualityComparer.Default.Equals(recieverSymbolInfo, refe))
var invocationExpressionSyntax = (InvocationExpressionSyntax)tuple.Left.Node;
var semanticModel = tuple.Left.SemanticModel;
return new RegisterInvocationCandidate(invocationExpressionSyntax, semanticModel);
});

// Find types by explicit [Inject]
var p3 = context.SyntaxProvider
var typeDeclarations = context.SyntaxProvider
.CreateSyntaxProvider((s, cancellation) =>
{
if (s is not ClassDeclarationSyntax syntax)
Expand All @@ -74,21 +71,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

return true;
},
(ctx, cancellation) =>
{
return (TypeDeclarationSyntax)ctx.Node;
})
.Where(x => x != null)
(ctx, cancellation) => ctx)
.Combine(vcontainerReferenceValueProvider)
.Where(tuple => tuple.Right)
.Select((tuple, cancellatio) => tuple.Left);
.Select((tuple, cancellatio) =>
{
return new TypeDeclarationCandidate((TypeDeclarationSyntax)tuple.Left.Node, tuple.Left.SemanticModel);
});

// Generate the source code.
context.RegisterSourceOutput(
context.CompilationProvider.Combine(p3.Collect()),
(sourceProductionContext, t) =>
context.CompilationProvider
.Combine(typeDeclarations.Collect())
.Combine(registerInvocations.Collect()),
(sourceProductionContext, tuple) =>
{
var (compilation, list) = t;
var compilation = tuple.Left.Left;
var typeDeclarationCandidates = tuple.Left.Right;
var registerInvocationCandidates = tuple.Right;

var references = ReferenceSymbols.Create(compilation);
if (references is null)
Expand All @@ -98,10 +98,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

var codeWriter = new CodeWriter();

foreach (var x in list)
{
var typeMeta = new TypeMeta(x!, references);
var typeMetas = typeDeclarationCandidates
.Select(x => x.Analyze(references))
.Where(x => x != null);

var typeMetasFromRegister = registerInvocationCandidates
.SelectMany(x => x.Analyze(references))
.Where(x => x != null);

foreach (var typeMeta in typeMetas.Concat(typeMetasFromRegister))
{
if (TryEmitGeneratedInjector(typeMeta, codeWriter, references, in sourceProductionContext))

Check warning on line 111 in VContainer.SourceGenerator/VContainerIncrementalSourceGenerator.cs

View workflow job for this annotation

GitHub Actions / test-dotnet

Possible null reference argument for parameter 'typeMeta' in 'bool VContainerIncrementalSourceGenerator.TryEmitGeneratedInjector(TypeMeta typeMeta, CodeWriter codeWriter, ReferenceSymbols references, in SourceProductionContext context)'.
{
var fullType = typeMeta.FullTypeName
Expand All @@ -115,46 +121,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
});
}

static INamedTypeSymbol? AnalyzeClassDeclarationSyntax(TypeDeclarationSyntax syntax)
{
if (context.Node is not TypeDeclarationSyntax syntax)
{
return null;
}

var symbol = context.SemanticModel.GetDeclaredSymbol(context.Node, cancellation);
if (symbol is not INamedTypeSymbol typeSymbol)
{
return null;
}

foreach (var baseTypeSymbol in typeSymbol.GetAllBaseTypes())
{
var name = baseTypeSymbol.ToDisplayString();
// Ignore
if (name == "System.Attributes")
{
return null;
}
}

foreach (var attributeListSyntax in syntax.AttributeLists)
{
foreach (var attributeSyntax in attributeListSyntax.Attributes)
{
if (context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
continue;

var attributeName = attributeSymbol.ContainingType.ToDisplayString();

// Ignore
if (attributeName == "VContainer.InjectIgnoreAttribute")
return null;
}
}
return typeSymbol;
}

static bool TryEmitGeneratedInjector(
TypeMeta typeMeta,
CodeWriter codeWriter,
Expand Down

0 comments on commit c6451c5

Please sign in to comment.