-
Notifications
You must be signed in to change notification settings - Fork 0
EN 03_pipeline_architecture
🇺🇸 English | 🇯🇵 日本語 | Introduction
The Roslyn Incremental Source Generator (ISG) processes compiler events using a LINQ-like pipeline to transform syntax inputs into source code. This architecture leverages the Kassyi.Generators.Extensions pipeline helpers to ensure lean, zero-allocation transformations.
The following sequence diagram illustrates the pipeline topology, showing the chained Roslyn IncrementalValuesProvider<T> APIs. Section III details the internal class interactions.
sequenceDiagram
autonumber
participant Compiler as Roslyn Compiler
participant SP as SyntaxProvider (ISG)
participant Prepare as PrepareData (Extraction)
participant Model as DTO (ClassData/DPData)
participant Source as Sources.* (Generation)
Compiler->>SP: Syntax / Semantic change notification
SP->>SP: ForAttributeWithMetadataName...<br/>(Filters target syntax nodes)
SP->>SP: Combine(Framework, Version)
SP->>Prepare: Select(PrepareData)
Note over Prepare: Extracts pure primitive DTOs<br/>(Cached NamedArguments, deduped syntax)
Prepare-->>Model: Construct (ClassData, DependencyPropertyData)
SP->>SP: WhereNotNull()
Note over SP: If Equals == true vs previous compilation,<br/>pipeline stops here (Cache Hit)
SP->>Source: Select(Generate)
Source-->>SP: Generated C# source text
SP->>Compiler: AddSource()
The pipeline executes in the following strict order:
-
Syntax filtering: The generator uses Roslyn 4.3.0+ APIs (
ForAttributeWithMetadataName) to filter classes and records decorated with specific attributes. -
Data extraction: The
PrepareData.csandDependencyPropertyDataBuildercomponents project rawAttributeDataandINamedTypeSymbolinstances into structured DTOs. This phase uses dictionary lookups to cacheNamedArgumentsand deduplicates syntax searches to maximize extraction speed. -
Equality evaluation and caching: The Roslyn ISG driver evaluates the
Selectphase output. If the output matches the previous compilation step (Equalsreturnstrue), the pipeline bypasses source generation and uses the incremental cache. -
Source code generation: The generator runs this phase only on cache misses. It transforms DTOs into
.g.cssource strings, usingSourceWriterscope management to guarantee zero-allocation formatting.
The incremental cache hit ratio is the most critical performance metric for an ISG. The data models (DependencyPropertyData, ClassData, EventData, and sub-records) enforce strict value equality semantics (such as adopting readonly record struct and wrapping collections with EquatableArray<T>) to optimize this ratio.
Note
For detailed architectural constraints regarding the equality caching strategy, zero-allocation generation, and early detachment of Roslyn syntax trees, see 05. Code synthesis and performance.
This section defines the responsibilities of internal generator classes and the data flow constraints within the Roslyn pipeline.
The generator's internal architecture consists of four primary layers:
- Generators: Registered in the Roslyn pipeline to orchestrate execution flow.
- Data extraction: Extracts necessary metadata from the syntax and semantic models.
- Models (DTOs): Equatable value-type records that store extracted data.
- Sources: Receives DTOs and emits synthesized C# source code strings.
classDiagram
%% Generators
class AttributeGeneratorBase~TData~ {
<<abstract>>
+Initialize(IncrementalGeneratorInitializationContext)
#PrepareData(GeneratorAttributeContext) TData?
#GenerateSource(TData) string
#GetHintName(TData) string
#SupportedFrameworks IReadOnlyList~Framework~
}
class DependencyPropertyGenerator {
#PrepareData() Tuple~ClassData, DPData~
#GenerateSource() string
}
class RoutedEventGenerator {
#PrepareData() Tuple~ClassData, EventData~
}
AttributeGeneratorBase <|-- DependencyPropertyGenerator
AttributeGeneratorBase <|-- RoutedEventGenerator
classDiagram
class MultiAttributeGeneratorBase~TData~ {
<<abstract>>
+Initialize(IncrementalGeneratorInitializationContext)
#PrepareData(GeneratorMultiAttributeContext) TData?
#GenerateSource(TData) string
#GetHintName(TData) string
#SupportedFrameworks IReadOnlyList~Framework~
#SelectMany bool
}
class AttachedDependencyPropertyGenerator {
#PrepareData() Tuple~ClassData, DPData~
}
class WeakEventGenerator {
#PrepareData() Tuple~ClassData, EventData~
}
MultiAttributeGeneratorBase <|-- AttachedDependencyPropertyGenerator
MultiAttributeGeneratorBase <|-- WeakEventGenerator
classDiagram
%% Data Extraction
class PrepareData {
<<static>>
+GetDependencyPropertyData(GeneratorAttributeContext) DependencyPropertyData
+GetClassData(INamedTypeSymbol, ...) ClassData
}
class DependencyPropertyDataBuilder {
+WithCoreProperties()
+WithMetadata()
+WithDefaultValues()
+WithCallbacks()
+Build() DependencyPropertyData
}
class DependencyPropertyMetadataExtractor {
<<static>>
+GetFrameworkMetadata() FrameworkMetadataData
}
%% Models (DTOs)
class ClassData {
<<readonly record struct>>
}
class DependencyPropertyData {
<<readonly record struct>>
}
%% Source Generation
class SourceGenerationHelper {
<<static>>
+GenerateDependencyPropertySource(ClassData, DPData) string
}
%% Relationships
DependencyPropertyGenerator --> PrepareData : Called by pipeline
PrepareData --> DependencyPropertyDataBuilder : Delegates data building
DependencyPropertyDataBuilder --> DependencyPropertyMetadataExtractor : Parses metadata
DependencyPropertyDataBuilder ..> DependencyPropertyData : Creates
PrepareData ..> ClassData : Creates
DependencyPropertyGenerator --> SourceGenerationHelper : Passes DTOs
SourceGenerationHelper ..> ClassData : Reads
SourceGenerationHelper ..> DependencyPropertyData : Reads
-
AttributeGeneratorBase<TData>andMultiAttributeGeneratorBase<TData>: The core foundation of the generator. It encapsulates standard logic for syntax filtering, target framework validation (SupportedFrameworks), context encapsulation (GeneratorAttributeContext), and source output. -
PrepareData: The extraction process entry point. It provides extension methods to isolate pure data from complex Roslyn objects likeINamedTypeSymbol. -
DependencyPropertyDataBuilder: An internal builder executing step-by-step extraction logic for dependency properties, such as matching callback signatures and extracting XML documentation. -
ClassDataandDependencyPropertyData: Data models storing extracted metadata. They are implemented asreadonly record structto maximize caching performance. -
SourceGenerationHelper: Static helpers that consume data models and assemble the final C# source code usingSourceWriter.
The following diagram traces the internal execution flow, illustrating the sequence from detecting a [DependencyProperty] attribute to generating the final C# code, and detailing instantiated classes and invoked methods.
sequenceDiagram
autonumber
participant Roslyn as ISG Pipeline
participant DPG as Generator
participant PD as PrepareData
participant Builder as DPDataBuilder
participant Models as DTOs
%% Parsing Phase
Roslyn->>DPG: Syntax change notification<br/>(Detects attributed class)
%% Extraction Phase
DPG->>PD: GetClassData(classSymbol)
Note over PD: Gets modifiers, namespace, etc.
PD-->>Models: Creates ClassData
DPG->>PD: GetDependencyPropertyData(attribute)
PD->>Builder: new Builder()
Note over Builder: Extracts metadata step-by-step
Builder->>Builder: WithCoreProperties()
Builder->>Builder: WithMetadata()
Builder->>Builder: WithDefaultValues()
Builder->>Builder: WithCallbacks()
Builder-->>Models: Creates DPData
DPG-->>Roslyn: Returns Tuple (ClassData, DPData)
sequenceDiagram
autonumber
participant Roslyn as ISG Pipeline
participant DPG as Generator
participant Helper as SourceGenerationHelper
%% Caching Phase
Note over Roslyn: [IMPORTANT] Equality check via Models' Equals().<br/>If unchanged from previous compilation,<br/>stops here and uses cache.
%% Generation Phase
Roslyn->>DPG: Cache miss, requests generation
DPG->>Helper: GenerateDependencyPropertySource(Class, DP)
Note over Helper: Assembles C# string using<br/>SourceWriter (Zero Allocation)
Helper-->>DPG: Generated source code (string)
DPG-->>Roslyn: Registers to compiler via AddSource()
Note
Consolidation of performance optimization principles For detailed prohibitions and best practices regarding early detachment of Roslyn types (Symbol/Syntax) and the zero-allocation generation phase, see 05. Code synthesis and performance.
Extensibility and separation of concerns
By isolating framework-specific mapping logic (in DependencyPropertyDataBuilder) from source generation logic (SourceGenerationHelper), the architecture ensures that parsing modifications do not affect the zero-allocation generation layer.
This wiki is automatically synchronized from spec/ in the repository.
- Introduction
- 01. FAQ & Design Rationale
- 02. Foundation & Domain
- 03. Pipeline Architecture
- 04. Framework Strategies
- 05. Synthesis & Performance
- 06. Complexity Model
- 07. Test Specification
- 08. Diagnostics Reference
- 概要
- 01. 設計思想とFAQ
- 02. 基盤とドメイン
- 03. パイプライン構造
- 04. フレームワーク別生成仕様
- 05. コード生成と最適化
- 06. 計算量モデル
- 07. テスト仕様書
- 08. 診断機能リファレンス