1- using System . Linq ;
1+ using System . Collections . Generic ;
2+ using System . Linq ;
23using System . Text ;
34using System . Text . RegularExpressions ;
45using Microsoft . CodeAnalysis ;
@@ -12,15 +13,15 @@ namespace StructId;
1213[ Generator ( LanguageNames . CSharp ) ]
1314public class TemplatedGenerator : IIncrementalGenerator
1415{
15- record KnownTypes ( INamedTypeSymbol String , INamedTypeSymbol ? IStructId , INamedTypeSymbol ? TStructId , INamedTypeSymbol ? TStructIdT ) ;
16+ record KnownTypes ( string StructIdNamespace , INamedTypeSymbol String , INamedTypeSymbol ? IStructId , INamedTypeSymbol ? TStructId , INamedTypeSymbol ? TStructIdT ) ;
1617 record IdTemplate ( INamedTypeSymbol StructId , Template Template ) ;
17- record Template ( INamedTypeSymbol TSelf , ITypeSymbol TId , AttributeData Attribute , bool IsGenericTId )
18+ record Template ( INamedTypeSymbol TSelf , ITypeSymbol TId , AttributeData Attribute , string StructIdNamespace , bool IsGenericTId )
1819 {
1920 public Regex NameExpr { get ; } = new Regex ( $@ "\b{ TSelf . Name } \b", RegexOptions . Compiled | RegexOptions . Multiline ) ;
2021
21- public string Text { get ; } = GetTemplateCode ( TSelf , TId , Attribute ) ;
22+ public string Text { get ; } = GetTemplateCode ( TSelf , TId , Attribute , StructIdNamespace ) ;
2223
23- static string GetTemplateCode ( INamedTypeSymbol self , ITypeSymbol tid , AttributeData attribute )
24+ static string GetTemplateCode ( INamedTypeSymbol self , ITypeSymbol tid , AttributeData attribute , string StructIdNamespace )
2425 {
2526 if ( self . DeclaringSyntaxReferences [ 0 ] . GetSyntax ( ) is not TypeDeclarationSyntax declaration )
2627 return "" ;
@@ -50,18 +51,48 @@ static string GetTemplateCode(INamedTypeSymbol self, ITypeSymbol tid, AttributeD
5051 root = root . ReplaceNode ( update , updated ) ;
5152 }
5253
53- return root . SyntaxTree . GetRoot ( ) . ToFullString ( ) . Trim ( ) ;
54+ // replace usings/namespace from StructId > StructIdNamespace
55+ var usings = root . DescendantNodes ( ) . OfType < UsingDirectiveSyntax > ( ) . ToList ( ) ;
56+ var ns = root . DescendantNodes ( ) . OfType < NamespaceDeclarationSyntax > ( ) . FirstOrDefault ( ) ;
57+ var nsname = ns ? . Name . ToString ( ) ;
58+
59+ if ( nsname == "StructId" )
60+ root = root . ReplaceNode ( ns ! , ns ! . WithName ( ParseName ( StructIdNamespace ) ) ) ;
61+ else if ( nsname != StructIdNamespace )
62+ usings . Add ( UsingDirective ( ParseName ( StructIdNamespace ) ) ) ;
63+
64+ // deduplicate usings just in case
65+ var unique = new HashSet < string > ( ) ;
66+ root = root . ReplaceNodes ( usings , ( old , _ ) =>
67+ {
68+ // replace 'StructId' > StructIdNamespace
69+ if ( old . Name ? . ToString ( ) == "StructId" )
70+ {
71+ unique . Add ( StructIdNamespace ) ;
72+ return old . WithName ( ParseName ( StructIdNamespace ) ) ;
73+ }
74+
75+ if ( unique . Add ( old . Name ? . ToString ( ) ?? "" ) )
76+ return old ;
77+
78+ return null ! ;
79+ } ) ;
80+
81+ var code = root . SyntaxTree . GetRoot ( ) . NormalizeWhitespace ( ) . ToFullString ( ) . Trim ( ) ;
82+
83+ return code ;
5484 }
5585 }
5686
5787 public void Initialize ( IncrementalGeneratorInitializationContext context )
5888 {
59- var targetNamespace = context . AnalyzerConfigOptionsProvider
89+ var structIdNamespace = context . AnalyzerConfigOptionsProvider
6090 . Select ( ( x , _ ) => x . GlobalOptions . TryGetValue ( "build_property.StructIdNamespace" , out var ns ) ? ns : "StructId" ) ;
6191
6292 var known = context . CompilationProvider
63- . Combine ( targetNamespace )
93+ . Combine ( structIdNamespace )
6494 . Select ( ( x , _ ) => new KnownTypes (
95+ x . Right ,
6596 // get string known type
6697 x . Left . GetTypeByMetadataName ( "System.String" ) ! ,
6798 x . Left . GetTypeByMetadataName ( $ "{ x . Right } .IStructId`1") ,
@@ -91,14 +122,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
91122 var ( structId , known ) = x ;
92123 var attribute = structId . GetAttributes ( ) . FirstOrDefault ( a => a . AttributeClass != null && a . AttributeClass . Is ( known . TStructIdT ) ) ;
93124 if ( attribute != null )
94- return new Template ( structId , attribute . AttributeClass ! . TypeArguments [ 0 ] , attribute , true ) ;
125+ return new Template ( structId , attribute . AttributeClass ! . TypeArguments [ 0 ] , attribute , known . StructIdNamespace , true ) ;
95126
96127 // If we don't have the generic attribute, infer the idType from the required
97128 // primary constructor Value parameter type
98129 var idType = structId . GetMembers ( ) . OfType < IPropertySymbol > ( ) . First ( p => p . Name == "Value" ) . Type ;
99130 attribute = structId . GetAttributes ( ) . First ( a => a . AttributeClass != null && a . AttributeClass . Is ( known . TStructId ) ) ;
100131
101- return new Template ( structId , idType , attribute , false ) ;
132+ return new Template ( structId , idType , attribute , known . StructIdNamespace , false ) ;
102133 } )
103134 . Collect ( ) ;
104135
0 commit comments