add a scanner, but this seems to be a wrong solution. Change open-source head

This commit is contained in:
Youmu Liu
2026-07-07 18:20:38 +08:00
parent b053567eb7
commit 1705d7c245
276 changed files with 3468 additions and 7205 deletions
@@ -1,50 +1,57 @@
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.Analysis"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace StgSharp.UserInterface.Generator;
internal static class PanelStateIncrementalGeneratorAnalysis
namespace StgSharp.UserInterface.Generator
{
public static PanelStateIncrementalGeneratorOutput Analyze(
PanelStateIncrementalGeneratorInput input
)
internal static class PanelStateIncrementalGeneratorAnalysis
{
if (input.TypeTargets.IsDefaultOrEmpty)
{
return new PanelStateIncrementalGeneratorOutput(
input.Compilation,
ImmutableArray<PanelStateIncrementalGeneratorTypeAnalysis>.Empty);
}
HashSet<string> emittedTypes = new(StringComparer.Ordinal);
ImmutableArray<PanelStateIncrementalGeneratorTypeAnalysis>.Builder builder =
ImmutableArray.CreateBuilder<PanelStateIncrementalGeneratorTypeAnalysis>();
foreach (PanelStateIncrementalGeneratorTypeTarget target in input.TypeTargets
.OrderBy(static item => item.TypeDisplayName, StringComparer.Ordinal))
public static PanelStateIncrementalGeneratorOutput Analyze(
PanelStateIncrementalGeneratorInput input
)
{
if (!emittedTypes.Add(target.TypeDisplayName))
{
continue;
if (input.TypeTargets.IsDefaultOrEmpty) {
return new PanelStateIncrementalGeneratorOutput(
input.Compilation,
ImmutableArray<PanelStateIncrementalGeneratorTypeAnalysis>.Empty);
}
PanelStateSymbolPartAnalysis stateSymbols = PanelStateIncrementalGeneratorStateSymbols.Analyze(target);
StateChangeBindingPartAnalysis stateChangeBindings = PanelStateIncrementalGeneratorStateChangeBindings.Analyze(target);
HashSet<string> emittedTypes = new(StringComparer.Ordinal);
ImmutableArray<PanelStateIncrementalGeneratorTypeAnalysis>.Builder builder =
ImmutableArray.CreateBuilder<PanelStateIncrementalGeneratorTypeAnalysis>();
builder.Add(
new PanelStateIncrementalGeneratorTypeAnalysis(
target,
stateSymbols,
stateChangeBindings,
PanelStateIncrementalGeneratorStateCommandHandlers.Analyze(
target,
stateSymbols,
stateChangeBindings)));
foreach (PanelStateIncrementalGeneratorTypeTarget target in input.TypeTargets
.OrderBy(static item => item.TypeDisplayName, StringComparer.Ordinal))
{
if (!emittedTypes.Add(target.TypeDisplayName))
{
continue;
}
PanelStateSymbolPartAnalysis stateSymbols = PanelStateIncrementalGeneratorStateSymbols.Analyze(target);
StateChangeBindingPartAnalysis stateChangeBindings = PanelStateIncrementalGeneratorStateChangeBindings.Analyze(target);
builder.Add(
new PanelStateIncrementalGeneratorTypeAnalysis(target, stateSymbols,
stateChangeBindings,
PanelStateIncrementalGeneratorStateCommandHandlers.Analyze(
target,
stateSymbols,
stateChangeBindings)));
}
return new PanelStateIncrementalGeneratorOutput(
input.Compilation,
builder.ToImmutable());
}
return new PanelStateIncrementalGeneratorOutput(
input.Compilation,
builder.ToImmutable());
}
}
@@ -1,6 +1,16 @@
namespace StgSharp.UserInterface.Generator;
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.Diagnostics"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
internal static class PanelStateIncrementalGeneratorDiagnostics
namespace StgSharp.UserInterface.Generator
{
public const string Category = "StgSharp.UserInterface.Generator";
internal static class PanelStateIncrementalGeneratorDiagnostics
{
public const string Category = "StgSharp.UserInterface.Generator";
}
}
@@ -1,3 +1,10 @@
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.Emitter"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Linq;
@@ -31,8 +38,8 @@ namespace StgSharp.UserInterface.Generator
foreach (string typeName in source.TypeAnalyses
.Select(static analysis => analysis.Target.TypeDisplayName)
.Distinct()
.OrderBy(static name => name, StringComparer.Ordinal))
.Distinct()
.OrderBy(static name => name, StringComparer.Ordinal))
{
_ = builder.Append(" \"");
_ = builder.Append(typeName.Replace("\"", "\"\"", StringComparison.Ordinal));
@@ -45,7 +52,7 @@ namespace StgSharp.UserInterface.Generator
_ = builder.AppendLine(" {");
foreach (PanelStateIncrementalGeneratorTypeAnalysis analysis in source.TypeAnalyses
.OrderBy(static item => item.Target.TypeDisplayName, StringComparer.Ordinal))
.OrderBy(static item => item.Target.TypeDisplayName, StringComparer.Ordinal))
{
string summary = $"{analysis.Target.TypeDisplayName} | symbols={analysis.StateSymbols.Members.Length} | bindings={analysis.StateChangeBindings.Members.Length} | handlers={analysis.StateChangeCommandHandlers.Members.Length}";
_ = builder.Append(" \"");
@@ -1,3 +1,10 @@
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.Models"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
@@ -14,7 +21,8 @@ namespace StgSharp.UserInterface.Generator
string? metadataName
)
{
return IsStateSymbolAttribute(metadataName) || metadataName == StateChangeBindingAttribute;
return IsStateSymbolAttribute(metadataName) ||
metadataName == StateChangeBindingAttribute;
}
public static bool IsStateSymbolAttribute(
@@ -1,6 +1,13 @@
using System.Collections.Immutable;
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.Pipeline"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
using System.Threading;
namespace StgSharp.UserInterface.Generator
@@ -12,12 +19,13 @@ namespace StgSharp.UserInterface.Generator
SyntaxNode node
)
{
return node is TypeDeclarationSyntax typeDeclaration && HasAttributedMembers(typeDeclaration);
return node is TypeDeclarationSyntax typeDeclaration &&
HasAttributedMembers(typeDeclaration);
}
public static PanelStateIncrementalGeneratorTypeTarget? Transform(
GeneratorSyntaxContext context,
CancellationToken cancellationToken
GeneratorSyntaxContext context,
CancellationToken cancellationToken
)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -26,14 +34,12 @@ namespace StgSharp.UserInterface.Generator
return null;
}
if (context.SemanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken) is not INamedTypeSymbol typeSymbol)
{
if (context.SemanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken) is not INamedTypeSymbol typeSymbol) {
return null;
}
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> markedMembers = CollectMarkedMembers(typeSymbol);
if (markedMembers.IsDefaultOrEmpty)
{
if (markedMembers.IsDefaultOrEmpty) {
return null;
}
@@ -43,6 +49,50 @@ namespace StgSharp.UserInterface.Generator
markedMembers);
}
private static ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> CollectMarkedMembers(
INamedTypeSymbol typeSymbol
)
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Builder builder =
ImmutableArray.CreateBuilder<PanelStateIncrementalGeneratorMarkedMember>();
foreach (ISymbol member in typeSymbol.GetMembers())
{
foreach (AttributeData attributeData in member.GetAttributes())
{
string? metadataName = attributeData.AttributeClass?.ToDisplayString();
if (!PanelStateIncrementalGeneratorKnownAttributes.IsKnown(metadataName))
{
continue;
}
builder.Add(
new PanelStateIncrementalGeneratorMarkedMember(member, metadataName!,
member.Name,
GetSymbolTypeName(member)));
break;
}
}
return builder.ToImmutable();
}
private static string GetSymbolTypeName(
ISymbol symbol
)
{
return symbol switch
{
IFieldSymbol fieldSymbol => fieldSymbol.Type
.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
IPropertySymbol propertySymbol => propertySymbol.Type
.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
IMethodSymbol methodSymbol => methodSymbol.ReturnType
.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
_ => symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
};
}
private static bool HasAttributedMembers(
TypeDeclarationSyntax typeDeclaration
)
@@ -61,48 +111,5 @@ namespace StgSharp.UserInterface.Generator
return false;
}
private static ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> CollectMarkedMembers(
INamedTypeSymbol typeSymbol
)
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Builder builder =
ImmutableArray.CreateBuilder<PanelStateIncrementalGeneratorMarkedMember>();
foreach (ISymbol member in typeSymbol.GetMembers())
{
foreach (AttributeData attributeData in member.GetAttributes())
{
string? metadataName = attributeData.AttributeClass?.ToDisplayString();
if (!PanelStateIncrementalGeneratorKnownAttributes.IsKnown(metadataName))
{
continue;
}
builder.Add(
new PanelStateIncrementalGeneratorMarkedMember(
member,
metadataName!,
member.Name,
GetSymbolTypeName(member)));
break;
}
}
return builder.ToImmutable();
}
private static string GetSymbolTypeName(
ISymbol symbol
)
{
return symbol switch
{
IFieldSymbol fieldSymbol => fieldSymbol.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
IPropertySymbol propertySymbol => propertySymbol.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
IMethodSymbol methodSymbol => methodSymbol.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
_ => symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
};
}
}
}
@@ -1,20 +1,30 @@
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.StateChangeBindings"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System.Collections.Immutable;
using System.Linq;
namespace StgSharp.UserInterface.Generator;
internal static class PanelStateIncrementalGeneratorStateChangeBindings
namespace StgSharp.UserInterface.Generator
{
public static StateChangeBindingPartAnalysis Analyze(
PanelStateIncrementalGeneratorTypeTarget target
)
internal static class PanelStateIncrementalGeneratorStateChangeBindings
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members = target.MarkedMembers
.Where(static member => member.AttributeMetadataName == PanelStateIncrementalGeneratorKnownAttributes.StateChangeBindingAttribute)
.ToImmutableArray();
return new StateChangeBindingPartAnalysis(
target.TypeDisplayName,
members);
public static StateChangeBindingPartAnalysis Analyze(
PanelStateIncrementalGeneratorTypeTarget target
)
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members = target.MarkedMembers
.Where(static member => member.AttributeMetadataName == PanelStateIncrementalGeneratorKnownAttributes.StateChangeBindingAttribute)
.ToImmutableArray();
return new StateChangeBindingPartAnalysis(
target.TypeDisplayName,
members);
}
}
}
@@ -1,61 +1,70 @@
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.StateCommandHandlers"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
namespace StgSharp.UserInterface.Generator;
internal static class PanelStateIncrementalGeneratorStateCommandHandlers
namespace StgSharp.UserInterface.Generator
{
public static StateChangeCommandHandlerPartAnalysis Analyze(
PanelStateIncrementalGeneratorTypeTarget target,
PanelStateSymbolPartAnalysis stateSymbols,
StateChangeBindingPartAnalysis stateChangeBindings
)
internal static class PanelStateIncrementalGeneratorStateCommandHandlers
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members = MergeMembers(
stateChangeBindings.Members,
stateSymbols.Members);
return new StateChangeCommandHandlerPartAnalysis(
target.TypeDisplayName,
members);
}
private static ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> MergeMembers(
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> primaryMembers,
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> secondaryMembers
)
{
if (primaryMembers.IsDefaultOrEmpty && secondaryMembers.IsDefaultOrEmpty)
public static StateChangeCommandHandlerPartAnalysis Analyze(
PanelStateIncrementalGeneratorTypeTarget target,
PanelStateSymbolPartAnalysis stateSymbols,
StateChangeBindingPartAnalysis stateChangeBindings
)
{
return ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Empty;
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members = MergeMembers(
stateChangeBindings.Members,
stateSymbols.Members);
return new StateChangeCommandHandlerPartAnalysis(
target.TypeDisplayName,
members);
}
HashSet<string> seen = new(StringComparer.Ordinal);
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Builder builder =
ImmutableArray.CreateBuilder<PanelStateIncrementalGeneratorMarkedMember>();
AddMembers(builder, seen, primaryMembers);
AddMembers(builder, seen, secondaryMembers);
return builder.ToImmutable();
}
private static void AddMembers(
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Builder builder,
HashSet<string> seen,
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members
)
{
foreach (PanelStateIncrementalGeneratorMarkedMember member in members)
private static void AddMembers(
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Builder builder,
HashSet<string> seen,
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members
)
{
string key = member.Symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (!seen.Add(key))
foreach (PanelStateIncrementalGeneratorMarkedMember member in members)
{
continue;
string key = member.Symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (!seen.Add(key))
{
continue;
}
builder.Add(member);
}
}
private static ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> MergeMembers(
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> primaryMembers,
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> secondaryMembers
)
{
if (primaryMembers.IsDefaultOrEmpty && secondaryMembers.IsDefaultOrEmpty) {
return ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Empty;
}
builder.Add(member);
HashSet<string> seen = new(StringComparer.Ordinal);
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember>.Builder builder =
ImmutableArray.CreateBuilder<PanelStateIncrementalGeneratorMarkedMember>();
AddMembers(builder, seen, primaryMembers);
AddMembers(builder, seen, secondaryMembers);
return builder.ToImmutable();
}
}
}
@@ -1,20 +1,30 @@
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator.StateSymbols"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System.Collections.Immutable;
using System.Linq;
namespace StgSharp.UserInterface.Generator;
internal static class PanelStateIncrementalGeneratorStateSymbols
namespace StgSharp.UserInterface.Generator
{
public static PanelStateSymbolPartAnalysis Analyze(
PanelStateIncrementalGeneratorTypeTarget target
)
internal static class PanelStateIncrementalGeneratorStateSymbols
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members = target.MarkedMembers
.Where(static member => PanelStateIncrementalGeneratorKnownAttributes.IsStateSymbolAttribute(member.AttributeMetadataName))
.ToImmutableArray();
return new PanelStateSymbolPartAnalysis(
target.TypeDisplayName,
members);
public static PanelStateSymbolPartAnalysis Analyze(
PanelStateIncrementalGeneratorTypeTarget target
)
{
ImmutableArray<PanelStateIncrementalGeneratorMarkedMember> members = target.MarkedMembers
.Where(static member => PanelStateIncrementalGeneratorKnownAttributes.IsStateSymbolAttribute(member.AttributeMetadataName))
.ToImmutableArray();
return new PanelStateSymbolPartAnalysis(
target.TypeDisplayName,
members);
}
}
}
@@ -1,37 +1,65 @@
using System.Collections.Immutable;
// -----------------------------------------------------------------------------
// file="PanelStateIncrementalGenerator"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
namespace StgSharp.UserInterface.Generator;
[Generator(LanguageNames.CSharp)]
public sealed class PanelStateIncrementalGenerator : IIncrementalGenerator
namespace StgSharp.UserInterface.Generator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
[Generator(LanguageNames.CSharp)]
public sealed class PanelStateIncrementalGenerator : IIncrementalGenerator
{
IncrementalValuesProvider<PanelStateIncrementalGeneratorTypeTarget> typeTargets = context.SyntaxProvider
.CreateSyntaxProvider(
static (node, _) => PanelStateIncrementalGeneratorPipeline.IsCandidate(node),
static (syntaxContext, cancellationToken) =>
PanelStateIncrementalGeneratorPipeline.Transform(syntaxContext, cancellationToken))
.Where(static target => target is not null)
.Select(static (target, _) => target!);
IncrementalValueProvider<ImmutableArray<PanelStateIncrementalGeneratorTypeTarget>> collectedTypeTargets = typeTargets.Collect();
public void Initialize(
IncrementalGeneratorInitializationContext context
)
{
IncrementalValuesProvider<PanelStateIncrementalGeneratorTypeTarget> typeTargets = context.SyntaxProvider
.CreateSyntaxProvider(
static(
node,
_
) => PanelStateIncrementalGeneratorPipeline.IsCandidate(node),
static(
syntaxContext,
cancellationToken
) => PanelStateIncrementalGeneratorPipeline.Transform(syntaxContext, cancellationToken))
.Where(static target => target is not null)
.Select(static(
target,
_
) => target!);
IncrementalValueProvider<PanelStateIncrementalGeneratorInput> generatorInput = context.CompilationProvider
.Combine(collectedTypeTargets)
.Select(
static (pair, _) => new PanelStateIncrementalGeneratorInput(
pair.Left,
pair.Right));
IncrementalValueProvider<ImmutableArray<PanelStateIncrementalGeneratorTypeTarget>> collectedTypeTargets = typeTargets.Collect();
IncrementalValueProvider<PanelStateIncrementalGeneratorOutput> generatorOutput = generatorInput
.Select(
static (input, _) => PanelStateIncrementalGeneratorAnalysis.Analyze(input));
IncrementalValueProvider<PanelStateIncrementalGeneratorInput> generatorInput = context.CompilationProvider
.Combine(collectedTypeTargets)
.Select(
static(
pair,
_
) => new PanelStateIncrementalGeneratorInput(
pair.Left,
pair.Right));
IncrementalValueProvider<PanelStateIncrementalGeneratorOutput> generatorOutput = generatorInput
.Select(
static(
input,
_
) => PanelStateIncrementalGeneratorAnalysis.Analyze(input));
context.RegisterSourceOutput(
generatorOutput,
static(
productionContext,
source
) => PanelStateIncrementalGeneratorEmitter.Emit(productionContext, source));
}
context.RegisterSourceOutput(
generatorOutput,
static (productionContext, source) =>
PanelStateIncrementalGeneratorEmitter.Emit(productionContext, source));
}
}