Skip to content

Commit 4885dae

Browse files
committed
PropertyValuesProviderGenerator using SyntaxFactory
1 parent 93343c3 commit 4885dae

File tree

10 files changed

+155
-109
lines changed

10 files changed

+155
-109
lines changed

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Extension/AttributeDataExtension.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public static bool HasNamedArgument<T>(this AttributeData attributeData, string
2323
return false;
2424
}
2525

26+
[Obsolete]
2627
public static bool HasNamedArgument<TValue>(this AttributeData attributeData, string name, Func<TValue, bool> predicate)
2728
{
2829
foreach ((string propertyName, TypedConstant constant) in attributeData.NamedArguments)

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Extension/GeneratorSyntaxContextExtension.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
// Licensed under the MIT license.
33

44
using Microsoft.CodeAnalysis;
5+
using System;
56
using System.Diagnostics.CodeAnalysis;
67
using System.Threading;
78

89
namespace Snap.Hutao.SourceGeneration.Extension;
910

1011
internal static class GeneratorSyntaxContextExtension
1112
{
13+
[Obsolete]
1214
public static bool TryGetDeclaredSymbol<TSymbol>(this GeneratorSyntaxContext context, CancellationToken token, [NotNullWhen(true)] out TSymbol? symbol)
1315
where TSymbol : class, ISymbol
1416
{
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using Microsoft.CodeAnalysis.CSharp.Syntax;
55
using System;
66

7-
namespace Snap.Hutao.SourceGeneration.Primitive;
7+
namespace Snap.Hutao.SourceGeneration.Extension;
88

99
internal static class SyntaxExtension
1010
{

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Model/AttributeInfo.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,17 @@ public AttributeSyntax GetSyntax()
6262

6363
return Attribute(IdentifierName(FullyQualifiedTypeName), AttributeArgumentList(SeparatedList([.. arguments, .. namedArguments])));
6464
}
65+
66+
public bool HasNamedArgument(string name, bool value)
67+
{
68+
foreach ((string propertyName, TypedConstantInfo constant) in NamedArgumentInfo)
69+
{
70+
if (propertyName == name)
71+
{
72+
return constant is TypedConstantInfo.Primitive.Boolean argument && argument.Value == value;
73+
}
74+
}
75+
76+
return false;
77+
}
6578
}

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Model/HierarchyInfo.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ public CompilationUnitSyntax GetCompilationUnit(ImmutableArray<MemberDeclaration
8282
//
8383
// <SYNTAX_TRIVIA>
8484
// <TYPE_HIERARCHY>
85-
return
86-
CompilationUnit()
87-
.AddMembers(typeDeclarationSyntax.WithLeadingTrivia(NullableEnableTriviaList))
88-
.NormalizeWhitespace();
85+
return CompilationUnit()
86+
.WithMembers(SingletonList<MemberDeclarationSyntax>(
87+
typeDeclarationSyntax
88+
.WithLeadingTrivia(NullableEnableTriviaList)));
8989
}
9090

9191
// Create the compilation unit with disabled warnings, target namespace and generated type.
@@ -94,8 +94,8 @@ public CompilationUnitSyntax GetCompilationUnit(ImmutableArray<MemberDeclaration
9494
// namespace <NAMESPACE>;
9595
// <TYPE_HIERARCHY>
9696
return CompilationUnit()
97-
.AddMembers(FileScopedNamespaceDeclaration(Namespace)
98-
.AddMembers(typeDeclarationSyntax))
99-
.NormalizeWhitespace();
97+
.WithMembers(SingletonList<MemberDeclarationSyntax>(FileScopedNamespaceDeclaration(Namespace)
98+
.WithMembers(SingletonList<MemberDeclarationSyntax>(typeDeclarationSyntax
99+
.WithLeadingTrivia(NullableEnableTriviaList)))));
100100
}
101101
}
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
// Copyright (c) DGP Studio. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using Microsoft.CodeAnalysis;
5+
using Snap.Hutao.SourceGeneration.Extension;
6+
47
namespace Snap.Hutao.SourceGeneration.Model;
58

69
internal sealed record PropertyInfo
710
{
8-
public PropertyInfo(string minimallyQualifiedName, TypeInfo typeInfo)
11+
public PropertyInfo(string minimallyQualifiedName, string fullyQualifiedTypeName)
912
{
1013
MinimallyQualifiedName = minimallyQualifiedName;
11-
TypeInfo = typeInfo;
14+
FullyQualifiedTypeName = fullyQualifiedTypeName;
1215
}
1316

1417
public string MinimallyQualifiedName { get; }
1518

16-
public TypeInfo TypeInfo { get; }
19+
public string FullyQualifiedTypeName { get; }
20+
21+
public static PropertyInfo Create(IPropertySymbol propertySymbol)
22+
{
23+
return new(propertySymbol.Name, propertySymbol.Type.GetFullyQualifiedNameWithNullabilityAnnotations());
24+
}
1725
}

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Model/TypeInfo.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ internal sealed record TypeInfo
1515
public TypeInfo(INamedTypeSymbol symbol)
1616
{
1717
FullyQualifiedName = symbol.GetFullyQualifiedName();
18+
FullyQualifiedMetadataName = symbol.GetFullyQualifiedMetadataName();
1819
MinimallyQualifiedName = symbol.GetMinimallyQualifiedName();
1920
Kind = symbol.TypeKind;
2021
IsRecord = symbol.IsRecord;
2122
}
2223

2324
public string FullyQualifiedName { get; }
2425

26+
public string FullyQualifiedMetadataName { get; }
27+
2528
public string MinimallyQualifiedName { get; }
2629

2730
public TypeKind Kind { get; }

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Primitive/FastSyntaxFactory.LiteralExpression.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace Snap.Hutao.SourceGeneration.Primitive;
99

1010
internal static partial class FastSyntaxFactory
1111
{
12+
public static LiteralExpressionSyntax DefaultLiteralExpression { get; } = SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression);
13+
1214
public static LiteralExpressionSyntax FalseLiteralExpression { get; } = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression);
1315

1416
public static LiteralExpressionSyntax NullLiteralExpression { get; } = SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression);

src/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration/Xaml/AdvancedCollectionViewItemGenerator.cs

Lines changed: 0 additions & 98 deletions
This file was deleted.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) DGP Studio. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using Microsoft.CodeAnalysis;
5+
using Microsoft.CodeAnalysis.CSharp.Syntax;
6+
using Snap.Hutao.SourceGeneration.Extension;
7+
using Snap.Hutao.SourceGeneration.Model;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Collections.Immutable;
11+
using System.Linq;
12+
using System.Threading;
13+
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
14+
using static Snap.Hutao.SourceGeneration.Primitive.FastSyntaxFactory;
15+
16+
namespace Snap.Hutao.SourceGeneration.Xaml;
17+
18+
[Generator(LanguageNames.CSharp)]
19+
internal sealed class PropertyValuesProviderGenerator : IIncrementalGenerator
20+
{
21+
public const string InterfaceMetadataName = "Snap.Hutao.UI.Xaml.Data.IPropertyValuesProvider";
22+
23+
public void Initialize(IncrementalGeneratorInitializationContext context)
24+
{
25+
IncrementalValuesProvider<PropertyValuesProviderGeneratorContext> commands = context.SyntaxProvider
26+
.CreateSyntaxProvider(FilterTypeWithBaseList, ProviderType)
27+
.Where(static c => c is not null);
28+
29+
context.RegisterSourceOutput(commands, GenerateWrapper);
30+
}
31+
32+
private static bool FilterTypeWithBaseList(SyntaxNode node, CancellationToken token)
33+
{
34+
return node is TypeDeclarationSyntax { BaseList: not null };
35+
}
36+
37+
private static PropertyValuesProviderGeneratorContext ProviderType(GeneratorSyntaxContext context, CancellationToken token)
38+
{
39+
if (context.SemanticModel.GetDeclaredSymbol(context.Node) is INamedTypeSymbol typeSymbol)
40+
{
41+
if (typeSymbol.Interfaces.Any(static symbol => symbol.HasFullyQualifiedMetadataName(InterfaceMetadataName)))
42+
{
43+
return PropertyValuesProviderGeneratorContext.Create(typeSymbol);
44+
}
45+
}
46+
47+
return default!;
48+
}
49+
50+
private static void GenerateWrapper(SourceProductionContext production, PropertyValuesProviderGeneratorContext context)
51+
{
52+
try
53+
{
54+
Generate(production, context);
55+
}
56+
catch (Exception e)
57+
{
58+
production.AddSource($"Error-{Guid.NewGuid().ToString()}.g.cs", e.ToString());
59+
}
60+
}
61+
62+
private static void Generate(SourceProductionContext production, PropertyValuesProviderGeneratorContext context)
63+
{
64+
CompilationUnitSyntax syntax = context.Hierarchy.GetCompilationUnit(
65+
[
66+
MethodDeclaration(NullableObjectType, Identifier("GetPropertyValue"))
67+
.WithModifiers(PublicTokenList)
68+
.WithParameterList(ParameterList(SingletonSeparatedList(
69+
Parameter(StringType, Identifier("propertyName")))))
70+
.WithBody(Block(SingletonList(
71+
ReturnStatement(SwitchExpression(IdentifierName("propertyName"))
72+
.WithArms(SeparatedList(GenerateSwitchExpressionArms(context)))))))
73+
])
74+
.NormalizeWhitespace();
75+
76+
production.AddSource(context.Hierarchy.FileNameHint, syntax.ToFullString());
77+
}
78+
79+
private static IEnumerable<SwitchExpressionArmSyntax> GenerateSwitchExpressionArms(PropertyValuesProviderGeneratorContext context)
80+
{
81+
foreach (PropertyInfo property in context.Properties)
82+
{
83+
IdentifierNameSyntax propertyName = IdentifierName(property.MinimallyQualifiedName);
84+
85+
// nameof(${propertyName}) => ${propertyName}
86+
yield return SwitchExpressionArm(
87+
ConstantPattern(NameOf(propertyName)),
88+
propertyName);
89+
}
90+
91+
// _ => default
92+
yield return SwitchExpressionArm(DiscardPattern(), DefaultLiteralExpression);
93+
}
94+
95+
private sealed record PropertyValuesProviderGeneratorContext
96+
{
97+
public required HierarchyInfo Hierarchy { get; init; }
98+
99+
public required EquatableArray<PropertyInfo> Properties { get; init; }
100+
101+
public static PropertyValuesProviderGeneratorContext Create(INamedTypeSymbol typeSymbol)
102+
{
103+
return new()
104+
{
105+
Hierarchy = HierarchyInfo.From(typeSymbol),
106+
Properties = typeSymbol
107+
.GetMembers()
108+
.OfType<IPropertySymbol>()
109+
.Where(static prop => prop.DeclaredAccessibility is Accessibility.Public)
110+
.Select(PropertyInfo.Create)
111+
.ToImmutableArray(),
112+
};
113+
}
114+
}
115+
}

0 commit comments

Comments
 (0)