77using System ;
88using System . Collections . Generic ;
99using System . Diagnostics ;
10- using System . Linq ;
11- using System . Text ;
1210using System . Threading ;
1311
1412namespace Riverside . CompilerPlatform . SourceGenerators ;
@@ -20,163 +18,163 @@ namespace Riverside.CompilerPlatform.SourceGenerators;
2018[ NotMyCode ]
2119public abstract class AttributeGenerator : IncrementalGenerator
2220{
23- internal Dictionary < string , SyntaxTree > ? _additionalSources = null ;
24- internal Diagnostic ? _lastError = null ;
25-
26- /// <summary>
27- /// Gets additional syntax trees to include in the source generation.
28- /// </summary>
29- protected override Dictionary < string , SyntaxTree > AdditionalSources => _additionalSources ?? new Dictionary < string , SyntaxTree > ( ) ;
30-
31- /// <inheritdoc/>
32- public override List < SyntaxTree > Code { get ; set ; } = new ( ) ;
33-
34- /// <summary>
35- /// Process the compilation to find and generate code for relevant nodes.
36- /// </summary>
37- public abstract void ProcessCompilation ( Compilation compilation , CancellationToken cancellationToken ) ;
38-
39- /// <summary>
40- /// Called when initializing the generator.
41- /// </summary>
42- /// <param name="context">The post-initialization context.</param>
43- protected virtual void OnInitialize ( IncrementalGeneratorPostInitializationContext context ) { }
44-
45- /// <summary>
46- /// Called before source generation begins.
47- /// </summary>
48- protected override void OnBeforeGeneration ( Compilation compilation , CancellationToken cancellationToken )
49- {
50- // Clear previous results
51- Code . Clear ( ) ;
52- _additionalSources = new Dictionary < string , SyntaxTree > ( ) ;
53-
54- // Process the compilation
55- try
56- {
57- ProcessCompilation ( compilation , cancellationToken ) ;
58- }
59- catch ( Exception ex )
60- {
61- // Use the diagnostic helper from IncrementalGenerator
62- var diagnostic = CreateDiagnostic (
63- "GEN001" ,
64- "Attribute Generator Error" ,
65- $ "An error occurred during attribute processing: { ex . Message } ",
66- DiagnosticSeverity . Error ) ;
67-
68- if ( ! SuppressDiagnostics )
69- {
70- _lastError = diagnostic ;
71- }
72- }
73- }
74-
75- /// <summary>
76- /// Creates a syntax tree for the given parameters using the appropriate language factory.
77- /// </summary>
78- /// <param name="symbol">The symbol for which the code is being generated.</param>
79- /// <param name="namespaceName">The namespace name.</param>
80- /// <param name="className">The class name.</param>
81- /// <param name="memberCode">The member code to include in the class.</param>
82- /// <returns>A syntax tree representing the generated code.</returns>
83- protected SyntaxTree CreateLanguageSpecificSyntaxTree ( ISymbol symbol , string namespaceName , string className , string memberCode )
84- {
85- return CreateCSharpSyntaxTree ( symbol , namespaceName , className , memberCode ) ;
86- }
87-
88- /// <summary>
89- /// Creates a C# syntax tree using the C# Roslyn API.
90- /// </summary>
91- /// <param name="symbol">The symbol for which the code is being generated.</param>
92- /// <param name="namespaceName">The namespace name.</param>
93- /// <param name="className">The class name.</param>
94- /// <param name="memberCode">The member code to include in the class.</param>
95- /// <returns>A syntax tree representing the generated code.</returns>
96- protected SyntaxTree CreateCSharpSyntaxTree ( ISymbol symbol , string namespaceName , string className , string memberCode )
97- {
98- using ( var _ = new ParserOptionsScope ( ) )
99- {
100- // Using Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.CSharp.Syntax
101- var namespaceDecl = SyntaxFactory . NamespaceDeclaration (
102- SyntaxFactory . ParseName ( namespaceName ) )
103- . WithLeadingTrivia ( SyntaxFactory . Comment ( "// <auto-generated>" ) ,
104- SyntaxFactory . Comment ( $ "// This code was auto-generated by a tool for { symbol } .") ,
105- SyntaxFactory . Comment ( "// </auto-generated>" ) ,
106- SyntaxFactory . Trivia ( SyntaxFactory . NullableDirectiveTrivia (
107- SyntaxFactory . Token ( SyntaxKind . EnableKeyword ) , true ) ) ) ;
108-
109- // Create attribute for GeneratedCode
110- var generatedAttribute = SyntaxFactory . AttributeList (
111- SyntaxFactory . SingletonSeparatedList (
112- SyntaxFactory . Attribute (
113- SyntaxFactory . ParseName ( "global::System.CodeDom.Compiler.GeneratedCodeAttribute" ) ,
114- SyntaxFactory . AttributeArgumentList (
115- SyntaxFactory . SeparatedList < AttributeArgumentSyntax > (
116- new AttributeArgumentSyntax [ ] {
117- SyntaxFactory . AttributeArgument (
118- SyntaxFactory . LiteralExpression (
119- SyntaxKind . StringLiteralExpression ,
120- SyntaxFactory . Literal ( "Riverside.CompilerPlatform.SourceGenerators" ) ) ) ,
121- SyntaxFactory . AttributeArgument (
122- SyntaxFactory . LiteralExpression (
123- SyntaxKind . StringLiteralExpression ,
124- SyntaxFactory . Literal ( FileVersionInfo . GetVersionInfo (
125- System . Reflection . Assembly . GetExecutingAssembly ( ) . Location ) . ToString ( ) ) ) )
126- } ) ) ) ) ) ;
127-
128- // Create class declaration with the generated member code
129- var classDecl = SyntaxFactory . ClassDeclaration ( className )
130- . WithModifiers ( SyntaxFactory . TokenList (
131- SyntaxFactory . Token ( SyntaxKind . PartialKeyword ) ) )
132- . WithAttributeLists ( SyntaxFactory . List ( new [ ] { generatedAttribute } ) )
133- . WithMembers ( SyntaxFactory . List < MemberDeclarationSyntax > (
134- new [ ] { SyntaxFactory . ParseMemberDeclaration ( memberCode ) ! } ) ) ;
135-
136- // Add the class to the namespace
137- namespaceDecl = namespaceDecl . AddMembers ( classDecl ) ;
138-
139- // Create the compilation unit
140- var compilationUnit = SyntaxFactory . CompilationUnit ( )
141- . AddMembers ( namespaceDecl )
142- . NormalizeWhitespace ( ) ;
143-
144- // Create the syntax tree
145- return compilationUnit . SyntaxTree ;
146- }
147- }
148-
149- /// <summary>
150- /// Called after source generation completes.
151- /// </summary>
152- protected override void OnAfterGeneration ( SourceProductionContext context )
153- {
154- // Report any diagnostic that was created during OnBeforeGeneration
155- if ( _lastError != null && ! SuppressDiagnostics )
156- {
157- context . ReportDiagnostic ( _lastError ) ;
158- _lastError = null ;
159- }
160-
161- base . OnAfterGeneration ( context ) ;
162- }
163-
164- /// <summary>
165- /// A scope for parser options that ensures proper disposal.
166- /// </summary>
167- protected class ParserOptionsScope : IDisposable
168- {
169- public ParserOptionsScope ( )
170- {
171- // Set up parser options
172- }
173-
174- /// <inheritdoc/>
175- public void Dispose ( )
176- {
177- // Clean up
178- }
179- }
21+ internal Dictionary < string , SyntaxTree > ? _additionalSources = null ;
22+ internal Diagnostic ? _lastError = null ;
23+
24+ /// <summary>
25+ /// Gets additional syntax trees to include in the source generation.
26+ /// </summary>
27+ protected override Dictionary < string , SyntaxTree > AdditionalSources => _additionalSources ?? new Dictionary < string , SyntaxTree > ( ) ;
28+
29+ /// <inheritdoc/>
30+ public override List < SyntaxTree > Code { get ; set ; } = new ( ) ;
31+
32+ /// <summary>
33+ /// Process the compilation to find and generate code for relevant nodes.
34+ /// </summary>
35+ public abstract void ProcessCompilation ( Compilation compilation , CancellationToken cancellationToken ) ;
36+
37+ /// <summary>
38+ /// Called when initializing the generator.
39+ /// </summary>
40+ /// <param name="context">The post-initialization context.</param>
41+ protected virtual void OnInitialize ( IncrementalGeneratorPostInitializationContext context ) { }
42+
43+ /// <summary>
44+ /// Called before source generation begins.
45+ /// </summary>
46+ protected override void OnBeforeGeneration ( Compilation compilation , CancellationToken cancellationToken )
47+ {
48+ // Clear previous results
49+ Code . Clear ( ) ;
50+ _additionalSources = new Dictionary < string , SyntaxTree > ( ) ;
51+
52+ // Process the compilation
53+ try
54+ {
55+ ProcessCompilation ( compilation , cancellationToken ) ;
56+ }
57+ catch ( Exception ex )
58+ {
59+ // Use the diagnostic helper from IncrementalGenerator
60+ var diagnostic = CreateDiagnostic (
61+ "GEN001" ,
62+ "Attribute Generator Error" ,
63+ $ "An error occurred during attribute processing: { ex . Message } ",
64+ DiagnosticSeverity . Error ) ;
65+
66+ if ( ! SuppressDiagnostics )
67+ {
68+ _lastError = diagnostic ;
69+ }
70+ }
71+ }
72+
73+ /// <summary>
74+ /// Creates a syntax tree for the given parameters using the appropriate language factory.
75+ /// </summary>
76+ /// <param name="symbol">The symbol for which the code is being generated.</param>
77+ /// <param name="namespaceName">The namespace name.</param>
78+ /// <param name="className">The class name.</param>
79+ /// <param name="memberCode">The member code to include in the class.</param>
80+ /// <returns>A syntax tree representing the generated code.</returns>
81+ protected SyntaxTree CreateLanguageSpecificSyntaxTree ( ISymbol symbol , string namespaceName , string className , string memberCode )
82+ {
83+ return CreateCSharpSyntaxTree ( symbol , namespaceName , className , memberCode ) ;
84+ }
85+
86+ /// <summary>
87+ /// Creates a C# syntax tree using the C# Roslyn API.
88+ /// </summary>
89+ /// <param name="symbol">The symbol for which the code is being generated.</param>
90+ /// <param name="namespaceName">The namespace name.</param>
91+ /// <param name="className">The class name.</param>
92+ /// <param name="memberCode">The member code to include in the class.</param>
93+ /// <returns>A syntax tree representing the generated code.</returns>
94+ protected SyntaxTree CreateCSharpSyntaxTree ( ISymbol symbol , string namespaceName , string className , string memberCode )
95+ {
96+ using ( var _ = new ParserOptionsScope ( ) )
97+ {
98+ // Using Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.CSharp.Syntax
99+ var namespaceDecl = SyntaxFactory . NamespaceDeclaration (
100+ SyntaxFactory . ParseName ( namespaceName ) )
101+ . WithLeadingTrivia ( SyntaxFactory . Comment ( "// <auto-generated>" ) ,
102+ SyntaxFactory . Comment ( $ "// This code was auto-generated by a tool for { symbol } .") ,
103+ SyntaxFactory . Comment ( "// </auto-generated>" ) ,
104+ SyntaxFactory . Trivia ( SyntaxFactory . NullableDirectiveTrivia (
105+ SyntaxFactory . Token ( SyntaxKind . EnableKeyword ) , true ) ) ) ;
106+
107+ // Create attribute for GeneratedCode
108+ var generatedAttribute = SyntaxFactory . AttributeList (
109+ SyntaxFactory . SingletonSeparatedList (
110+ SyntaxFactory . Attribute (
111+ SyntaxFactory . ParseName ( "global::System.CodeDom.Compiler.GeneratedCodeAttribute" ) ,
112+ SyntaxFactory . AttributeArgumentList (
113+ SyntaxFactory . SeparatedList < AttributeArgumentSyntax > (
114+ new AttributeArgumentSyntax [ ] {
115+ SyntaxFactory . AttributeArgument (
116+ SyntaxFactory . LiteralExpression (
117+ SyntaxKind . StringLiteralExpression ,
118+ SyntaxFactory . Literal ( "Riverside.CompilerPlatform.SourceGenerators" ) ) ) ,
119+ SyntaxFactory . AttributeArgument (
120+ SyntaxFactory . LiteralExpression (
121+ SyntaxKind . StringLiteralExpression ,
122+ SyntaxFactory . Literal ( FileVersionInfo . GetVersionInfo (
123+ System . Reflection . Assembly . GetExecutingAssembly ( ) . Location ) . ToString ( ) ) ) )
124+ } ) ) ) ) ) ;
125+
126+ // Create class declaration with the generated member code
127+ var classDecl = SyntaxFactory . ClassDeclaration ( className )
128+ . WithModifiers ( SyntaxFactory . TokenList (
129+ SyntaxFactory . Token ( SyntaxKind . PartialKeyword ) ) )
130+ . WithAttributeLists ( SyntaxFactory . List ( new [ ] { generatedAttribute } ) )
131+ . WithMembers ( SyntaxFactory . List < MemberDeclarationSyntax > (
132+ new [ ] { SyntaxFactory . ParseMemberDeclaration ( memberCode ) ! } ) ) ;
133+
134+ // Add the class to the namespace
135+ namespaceDecl = namespaceDecl . AddMembers ( classDecl ) ;
136+
137+ // Create the compilation unit
138+ var compilationUnit = SyntaxFactory . CompilationUnit ( )
139+ . AddMembers ( namespaceDecl )
140+ . NormalizeWhitespace ( ) ;
141+
142+ // Create the syntax tree
143+ return compilationUnit . SyntaxTree ;
144+ }
145+ }
146+
147+ /// <summary>
148+ /// Called after source generation completes.
149+ /// </summary>
150+ protected override void OnAfterGeneration ( SourceProductionContext context )
151+ {
152+ // Report any diagnostic that was created during OnBeforeGeneration
153+ if ( _lastError != null && ! SuppressDiagnostics )
154+ {
155+ context . ReportDiagnostic ( _lastError ) ;
156+ _lastError = null ;
157+ }
158+
159+ base . OnAfterGeneration ( context ) ;
160+ }
161+
162+ /// <summary>
163+ /// A scope for parser options that ensures proper disposal.
164+ /// </summary>
165+ protected class ParserOptionsScope : IDisposable
166+ {
167+ public ParserOptionsScope ( )
168+ {
169+ // Set up parser options
170+ }
171+
172+ /// <inheritdoc/>
173+ public void Dispose ( )
174+ {
175+ // Clean up
176+ }
177+ }
180178}
181179
182180#endif
0 commit comments