-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
270 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
namespace nyingi.Kafa.Generators; | ||
|
||
internal sealed partial class KafaSourceGenerator | ||
{ | ||
private static readonly string GeneratedAttribute = $@"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{typeof(KafaSourceGenerator).Assembly.GetName().Name}"", ""0.1.0"")]"; | ||
|
||
//lang=c# | ||
private static readonly string KafaSerializableAttribute = $@" | ||
//<auto-generated/> | ||
#nullable enable | ||
namespace nyingi.Kafa.Generators; | ||
{GeneratedAttribute} | ||
[global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple =true, Inherited = false)] | ||
internal sealed class KafaSerializableAttribute : global::System.Attribute | ||
{{ | ||
public global::System.Type Type {{ get; }} | ||
public KafaSerializableAttribute(global::System.Type type) | ||
{{ | ||
Type = type; | ||
}} | ||
}} | ||
"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
|
||
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); | ||
|
||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
using System; | ||
using System.Collections.Immutable; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Linq; | ||
using System.Runtime.CompilerServices; | ||
using System.Text; | ||
using System.Threading; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace nyingi.Kafa.Generators | ||
{ | ||
|
||
[Generator] | ||
internal sealed partial class KafaSourceGenerator : IIncrementalGenerator | ||
{ | ||
private const string _kafaAttributeName = "nyingi.Kafa.Generators.KafaSerializableAttribute"; | ||
public void Initialize(IncrementalGeneratorInitializationContext context) | ||
{ | ||
context.RegisterPostInitializationOutput(PostInitializationCallback); | ||
|
||
|
||
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)); | ||
|
||
} | ||
|
||
private static void PostInitializationCallback(IncrementalGeneratorPostInitializationContext context) | ||
{ | ||
context.AddSource("KafaSerializableAttribute.g.cs", SourceText.From(KafaSerializableAttribute, Encoding.UTF8)); | ||
} | ||
private static bool SyntacticPredicate(SyntaxNode syntaxNode, CancellationToken cancellationToken) | ||
{ | ||
return syntaxNode is ClassDeclarationSyntax | ||
{ | ||
AttributeLists.Count: > 0, | ||
} candidate | ||
&& candidate.Modifiers.Any(SyntaxKind.PartialKeyword) | ||
&& !candidate.Modifiers.Any(SyntaxKind.StaticKeyword); | ||
} | ||
|
||
private static (INamedTypeSymbol, INamedTypeSymbol)? SemanticTransformer(GeneratorSyntaxContext context, CancellationToken cancellationToken) | ||
{ | ||
var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node; | ||
|
||
INamedTypeSymbol? namedTypeSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, cancellationToken); | ||
|
||
|
||
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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.Collections.Generic; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace nyingi.Kafa.Generators; | ||
|
||
internal static class NameTypeSymbolExtensions | ||
{ | ||
|
||
public static IEnumerable<INamedTypeSymbol> GetTypeAndSubtypes(this INamedTypeSymbol? type) | ||
{ | ||
INamedTypeSymbol? current = type; | ||
while (current is not null) | ||
{ | ||
yield return current; | ||
current = current.BaseType; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using nyingi.Kafa.Reader; | ||
using nyingi.Kafa.Writer; | ||
|
||
namespace nyingi.Kafa; | ||
|
||
public interface IKafaFormatter<T> | ||
{ | ||
public static abstract void Serialize(ref KafaWriter writer, scoped ref T? entity); | ||
public static abstract void Deserialize(ref KafaReader reader, scoped ref T? entity); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters