Skip to content

Commit

Permalink
changed incrementalgenerator implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
j0nimost committed Nov 8, 2023
1 parent dd86cf3 commit 0b146eb
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 132 deletions.
2 changes: 1 addition & 1 deletion src/Kafa.Generators/KafaSourceGenerator.Attribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

internal sealed partial class KafaSourceGenerator

Check warning on line 3 in src/Kafa.Generators/KafaSourceGenerator.Attribute.cs

View workflow job for this annotation

GitHub Actions / build

'nyingi.Kafa.Generators.KafaSourceGenerator': A project containing analyzers or source generators should specify the property '<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>'

Check warning on line 3 in src/Kafa.Generators/KafaSourceGenerator.Attribute.cs

View workflow job for this annotation

GitHub Actions / build

'nyingi.Kafa.Generators.KafaSourceGenerator': A project containing analyzers or source generators should specify the property '<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>'
{
private static readonly string GeneratedAttribute = $@"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{typeof(KafaSourceGenerator).Assembly.GetName().Name}"", ""0.1.0"")]";
private static readonly string GeneratedAttribute = $@"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{typeof(KafaSourceGenerator).Assembly.GetName().Name}"", ""{typeof(KafaSourceGenerator).Assembly.GetName().Version}"")]";

//lang=c#
private static readonly string KafaSerializableAttribute = $@"
Expand Down
15 changes: 11 additions & 4 deletions src/Kafa.Generators/KafaSourceGenerator.Context.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace nyingi.Kafa.Generators
{
internal sealed partial class KafaSourceGenerator
{
private record struct KafaGeneratorContext(string? actualnamespace, string name, TypeContext typeContext);

private record struct TypeContext(bool isReferenceType, string name, ImmutableArray<PropertyContext> propertyContext);

private record struct PropertyContext(string type, string name);

private static readonly SymbolDisplayFormat Format = SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable | SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);

private record struct KafaEnumContext(ClassDeclarationSyntax ClassDeclarationSyntax,
INamedTypeSymbol NamedTypeSymbol, SemanticModel SemanticModel, SyntaxList<AttributeListSyntax> AttributeList);

private record struct TypeDefinition(string Name, ImmutableArray<PropertyContext> Properties);

private record struct TypeDefinitionContext(bool IsGlobalNameSpace, string NameSpace, string Name,
ImmutableArray<TypeDefinition> TypeDefinitions)
{
public string GetFullName() => IsGlobalNameSpace ? Name : $"{NameSpace}.{Name}";
}
}
}
57 changes: 57 additions & 0 deletions src/Kafa.Generators/KafaSourceGenerator.Emitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Text;
using Microsoft.CodeAnalysis;

namespace nyingi.Kafa.Generators;

internal sealed partial class KafaSourceGenerator
{
private static void Emit(SourceProductionContext context, TypeDefinitionContext source)
{
StringBuilder builder = new StringBuilder();
string Namespace =
"{(source.Namespace is null ? String.Empty : $\"namespace {source.Namespace};{Environment.NewLine}\")}";

// lang=c#
string classDef = $@"
// <auto-generated/>
#nullable enable
{Namespace}
partial class {source.Name}
{{
}}
";

}

private static string EmitSerializer(TypeDefinitionContext source)
{

// lang=c#
string serializer = $@"
public static void Serializer(global::System.Collections.Generic.List<{source.Name}> entities, ref nyingi.Kafa.Writer.KafaWriter writer)
{{
}}
";
return "";
}

private static string EmitDeserializer(TypeDefinitionContext source)
{
// lang=c#
string deserializer = $@"
{GeneratedAttribute}
public static global::System.Collections.Generic.List<{source.Name}> Deserialize(nyingi.Kafa.Reader.RowEnumerable rows)
{{
var results = new global::System.Collections.Generic.List<{source.Name}>(rows.Length);
}}
";
return "";
}
}
171 changes: 45 additions & 126 deletions src/Kafa.Generators/KafaSourceGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
Expand All @@ -21,12 +20,46 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(PostInitializationCallback);

IncrementalValuesProvider<TypeDefinitionContext> provider = context.SyntaxProvider
.ForAttributeWithMetadataName(_kafaAttributeName, SyntacticPredicate, SemanticTransformer)
.Collect()
.SelectMany(
static ImmutableArray<IGrouping<ISymbol?, KafaEnumContext>> (ImmutableArray<KafaEnumContext> source,

Check warning on line 27 in src/Kafa.Generators/KafaSourceGenerator.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 27 in src/Kafa.Generators/KafaSourceGenerator.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
CancellationToken cancellationToken) =>
{
return source
.GroupBy(c => c.NamedTypeSymbol, SymbolEqualityComparer.Default)
.ToImmutableArray();
})
.Select(static TypeDefinitionContext (IGrouping<ISymbol?, KafaEnumContext> sources,

Check warning on line 34 in src/Kafa.Generators/KafaSourceGenerator.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 34 in src/Kafa.Generators/KafaSourceGenerator.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
CancellationToken cancellationToken) =>
{
var source = sources.First();

var typeDefinitions = ImmutableArray.CreateBuilder<TypeDefinition>(source.AttributeList.Count);

foreach (var attributeListSyntax in source.AttributeList)
{
foreach (var attributeList in attributeListSyntax.Attributes)
{
var attributeArgument = attributeList.ArgumentList!.Arguments[0]; // first param
SymbolInfo info = source.SemanticModel.GetSymbolInfo(attributeArgument);
var symbol = (ITypeSymbol)info.Symbol;
var members = symbol.GetMembers()
.Where(static bool (ISymbol member) => member.Kind == SymbolKind.Field)
.Select(static PropertyContext (ISymbol propertySymbol) =>
new PropertyContext(propertySymbol.Name, propertySymbol.ToDisplayString(Format)))
.ToImmutableArray();
var typeDefinition = new TypeDefinition(symbol.ToDisplayString(Format), members);
typeDefinitions.Add(typeDefinition);
}
}

IncrementalValuesProvider<KafaGeneratorContext> provider = context.SyntaxProvider
.CreateSyntaxProvider(SyntacticPredicate, SemanticTransformer)
.Where(static ((INamedTypeSymbol, INamedTypeSymbol)? types) => types.HasValue)
.Select(static ((INamedTypeSymbol, INamedTypeSymbol)? types, CancellationToken cancellationToken) =>
TransformType(types!.Value));
return new TypeDefinitionContext(source.NamedTypeSymbol.ContainingNamespace.IsGlobalNamespace,
source.NamedTypeSymbol.ContainingNamespace.ToDisplayString(),
source.NamedTypeSymbol.Name,
typeDefinitions.MoveToImmutable());
});

}

Expand All @@ -41,131 +74,17 @@ private static bool SyntacticPredicate(SyntaxNode syntaxNode, CancellationToken
AttributeLists.Count: > 0,
} candidate
&& candidate.Modifiers.Any(SyntaxKind.PartialKeyword)
&& !candidate.Modifiers.Any(SyntaxKind.StaticKeyword);
&& candidate.Modifiers.Any(SyntaxKind.StaticKeyword); // might need the definition to be static for easier invoke
}

private static (INamedTypeSymbol, INamedTypeSymbol)? SemanticTransformer(GeneratorSyntaxContext context, CancellationToken cancellationToken)
private static KafaEnumContext SemanticTransformer(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
{
var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node;
var classDeclarationSyntax = (ClassDeclarationSyntax)context.TargetNode;

INamedTypeSymbol? namedTypeSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, cancellationToken);
var namedTypeSymbol = (INamedTypeSymbol)context.TargetSymbol;


if (namedTypeSymbol is not null
&& TryGetAttribute(classDeclarationSyntax, _kafaAttributeName, context.SemanticModel, cancellationToken,
out AttributeSyntax? attributeSyntax)
&& TryGetType(attributeSyntax, context.SemanticModel, cancellationToken,
out INamedTypeSymbol? typeSymbol))
{
return (namedTypeSymbol, typeSymbol);
}

return null;
}


private static bool TryGetAttribute(ClassDeclarationSyntax classDeclarationSyntax, string attributeName,
SemanticModel semanticModel, CancellationToken cancellationToken,
out AttributeSyntax? value)
{
foreach (AttributeListSyntax attributeList in classDeclarationSyntax.AttributeLists)
{
foreach (AttributeSyntax attributeSyntax in attributeList.Attributes)
{
SymbolInfo info = semanticModel.GetSymbolInfo(attributeSyntax, cancellationToken);
ISymbol? symbol = info.Symbol;

if (symbol is IMethodSymbol methodSymbol
&& methodSymbol.ContainingType.ToDisplayString()
.Equals(attributeName, StringComparison.Ordinal))
{
value = attributeSyntax;
return true;
}
}
}

value = null;
return false;
}


private static bool TryGetType(AttributeSyntax attributeSyntax, SemanticModel semanticModel,
CancellationToken cancellationToken, out INamedTypeSymbol? namedTypeSymbol)
{
var argumentList = attributeSyntax.ArgumentList;
if (argumentList!.Arguments.Count > 1) ;
{
AttributeArgumentSyntax argumentSyntax = argumentList.Arguments[0];

if (argumentSyntax.Expression is TypeOfExpressionSyntax typeOf)
{
SymbolInfo info = semanticModel.GetSymbolInfo(typeOf.Type, cancellationToken);
ISymbol? symbol = info.Symbol;

if (symbol is INamedTypeSymbol typeSymbol)
{
namedTypeSymbol = typeSymbol;
return true;
}
}
}

namedTypeSymbol = null;
return false;
}

private static KafaGeneratorContext TransformType((INamedTypeSymbol kafaPartialGeneratorType, INamedTypeSymbol targetType) types)
{
string? @namespace = types.kafaPartialGeneratorType.ContainingNamespace.IsGlobalNamespace
? null
: types.kafaPartialGeneratorType.ContainingNamespace.ToDisplayString();

string name = types.kafaPartialGeneratorType.Name;

bool isReferenceType = types.kafaPartialGeneratorType.IsReferenceType;
string targetTypeName = types.targetType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

bool areInternalSymbolsAccessible =
types.targetType.ContainingAssembly.GivesAccessTo((types.kafaPartialGeneratorType.ContainingAssembly));

ImmutableArray<PropertyContext> propertyContexts = types.targetType.GetTypeAndSubtypes()
.Reverse()
.SelectMany(static type => type.GetMembers())
.Where(member => FilterProperty(member, areInternalSymbolsAccessible))
.Select(static member => TransformProperty(member))
.Distinct()
.ToImmutableArray();


return new KafaGeneratorContext(@namespace, name,
new TypeContext(isReferenceType, targetTypeName, propertyContexts));
}


private static bool FilterProperty(ISymbol member, bool areInernalSymbolsAccessible)
{
if (!member.IsStatic && member.Kind == SymbolKind.Property)
{
var property = (IPropertySymbol)member;

return property.GetMethod is { } get
&& (get.DeclaredAccessibility is Accessibility.Public
|| (areInernalSymbolsAccessible &&
(get.DeclaredAccessibility is Accessibility.Internal
or Accessibility.ProtectedOrInternal)));
}

return false;
}

private static PropertyContext TransformProperty(ISymbol member)
{
var property = (IPropertySymbol)member;
string type = property.Type.ToDisplayString(Format);
string name = property.Name;

return new PropertyContext(type, name);
return new KafaEnumContext(classDeclarationSyntax, namedTypeSymbol, context.SemanticModel, classDeclarationSyntax.AttributeLists);
}
}
}
2 changes: 1 addition & 1 deletion src/Kafa/Writer/KafaPooledWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace nyingi.Kafa.Writer
{
public class KafaPooledWriter : IBufferWriter<byte>, IDisposable
{
private const int DefaultBufferLength = 65556;
private const int DefaultBufferLength = 65536;
private byte[] _buffer;

private int _index;
Expand Down

0 comments on commit 0b146eb

Please sign in to comment.