@@ -22,7 +22,7 @@ namespace Microsoft.Macios.Generator;
2222/// </summary>
2323[ Generator ]
2424public class BindingSourceGeneratorGenerator : IIncrementalGenerator {
25- static readonly DeclarationCodeChangesEqualityComparer equalityComparer = new ( ) ;
25+ static readonly CodeChangesEqualityComparer equalityComparer = new ( ) ;
2626
2727 /// <inheritdoc cref="IIncrementalGenerator"/>
2828 public void Initialize ( IncrementalGeneratorInitializationContext context )
@@ -34,15 +34,15 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
3434 fileName , SourceText . From ( content , Encoding . UTF8 ) ) ) ;
3535 }
3636
37- // our bindings are special. Due to the fact that we write shared code in the Library.g.cs and the Trampolines.g.cs
37+ // our bindings are special. Since we write shared code in the Library.g.cs and the Trampolines.g.cs
3838 // we need to listen to all the BaseTypeDeclarationSyntax changes. We do so, generate a data model with the
39- // changes we are interested and later we transform them. This allows use to be able to use a RootBindingContext
39+ // changes we are interested, and later we transform them. This allows use to be able to use a RootBindingContext
4040 // as a bag in which we can add information about libraries and trampolines needed by the bindings.
4141 var provider = context . SyntaxProvider
4242 . CreateSyntaxProvider ( static ( node , _ ) => IsValidNode ( node ) ,
4343 static ( ctx , _ ) => GetChangesForSourceGen ( ctx ) )
4444 . Where ( tuple => tuple . BindingAttributeFound )
45- . Select ( static ( tuple , _ ) => ( tuple . Declaration , tuple . Changes ) )
45+ . Select ( static ( tuple , _ ) => tuple . Changes )
4646 . WithComparer ( equalityComparer ) ;
4747
4848 context . RegisterSourceOutput ( context . CompilationProvider . Combine ( provider . Collect ( ) ) ,
@@ -59,29 +59,28 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
5959 _ => false ,
6060 } ;
6161
62- static ( BaseTypeDeclarationSyntax Declaration , CodeChanges Changes , bool BindingAttributeFound )
63- GetChangesForSourceGen ( GeneratorSyntaxContext context )
62+ static ( CodeChanges Changes , bool BindingAttributeFound ) GetChangesForSourceGen ( GeneratorSyntaxContext context )
6463 {
6564 // we do know that the context node has to be one of the base type declarations
6665 var declarationSyntax = Unsafe . As < BaseTypeDeclarationSyntax > ( context . Node ) ;
6766
6867 // check if we do have the binding attr, else there nothing to retrieve
69- bool isBindingType = declarationSyntax . HasAttribute ( context . SemanticModel , AttributesNames . BindingAttribute ) ;
68+ bool isBindingType = declarationSyntax . HasAtLeastOneAttribute ( context . SemanticModel , AttributesNames . BindingTypes ) ;
7069
7170 if ( ! isBindingType ) {
7271 // return empty data + false
73- return ( declarationSyntax , default , false ) ;
72+ return ( default , false ) ;
7473 }
7574
7675 var codeChanges = CodeChanges . FromDeclaration ( declarationSyntax , context . SemanticModel ) ;
7776 // if code changes are null, return the default value and a false to later ignore the change
7877 return codeChanges is not null
79- ? ( declarationSyntax , codeChanges . Value , isBindingType )
80- : ( declarationSyntax , default , false ) ;
78+ ? ( codeChanges . Value , isBindingType )
79+ : ( default , false ) ;
8180 }
8281
8382 static void GenerateCode ( SourceProductionContext context , Compilation compilation ,
84- in ImmutableArray < ( BaseTypeDeclarationSyntax Declaration , CodeChanges Changes ) > changesList )
83+ in ImmutableArray < CodeChanges > changesList )
8584 {
8685 // The process is as follows, get all the changes we have received from the incremental generator,
8786 // loop over them, and based on the CodeChange.BindingType we are going to build the symbol context
@@ -90,15 +89,17 @@ static void GenerateCode (SourceProductionContext context, Compilation compilati
9089 // Once all the enums, classes and interfaces have been processed, we will use the data collected
9190 // in the RootBindingContext to generate the library and trampoline code.
9291 var rootContext = new RootBindingContext ( compilation ) ;
93- foreach ( var ( declaration , change ) in changesList ) {
92+ var sb = new TabbedStringBuilder ( new ( ) ) ;
93+ foreach ( var change in changesList ) {
9494 // init sb and add the header
95- var sb = new TabbedStringBuilder ( new ( ) ) ;
95+ sb . Clear ( ) ;
9696 sb . WriteHeader ( ) ;
97- if ( EmitterFactory . TryCreate ( change , rootContext , sb , out var emitter ) ) {
97+ if ( EmitterFactory . TryCreate ( change , out var emitter ) ) {
9898 // write the using statements
99- CollectUsingStatements ( declaration . SyntaxTree , sb , emitter ) ;
99+ CollectUsingStatements ( change , sb , emitter ) ;
100100
101- if ( emitter . TryEmit ( change , out var diagnostics ) ) {
101+ var bindingContext = new BindingContext ( rootContext , sb , change ) ;
102+ if ( emitter . TryEmit ( bindingContext , out var diagnostics ) ) {
102103 // only add a file when we do generate code
103104 var code = sb . ToString ( ) ;
104105 var namespacePath = Path . Combine ( change . Namespace . ToArray ( ) ) ;
@@ -115,7 +116,7 @@ static void GenerateCode (SourceProductionContext context, Compilation compilati
115116 context . ReportDiagnostic ( Diagnostic . Create (
116117 Diagnostics
117118 . RBI0000 , // An unexpected error ocurred while processing '{0}'. Please fill a bug report at https://github.com/xamarin/xamarin-macios/issues/new.
118- declaration . GetLocation ( ) ,
119+ null ,
119120 change . FullyQualifiedSymbol ) ) ;
120121 }
121122 }
@@ -149,22 +150,18 @@ static void GenerateLibraryCode (SourceProductionContext context, RootBindingCon
149150 }
150151
151152 /// <summary>
152- /// Collect the using statements from the class declaration root syntaxt tree and add them to the string builder
153+ /// Collect the using statements from the named ype code changes and add them to the string builder
153154 /// that will be used to generate the code. This way we ensure that we have all the namespaces needed by the
154155 /// generated code.
155156 /// </summary>
156- /// <param name="tree">Root syntax tree of the base type declaration .</param>
157+ /// <param name="codeChanges">The code changes for a given named type .</param>
157158 /// <param name="sb">String builder that will be used for the generated code.</param>
158159 /// <param name="emitter">The emitter that will generate the code. Provides any extra needed namespace.</param>
159- static void CollectUsingStatements ( SyntaxTree tree , TabbedStringBuilder sb , ICodeEmitter emitter )
160+ static void CollectUsingStatements ( in CodeChanges codeChanges , TabbedStringBuilder sb , ICodeEmitter emitter )
160161 {
161162 // collect all using from the syntax tree, add them to a hash to make sure that we don't have duplicates
162163 // and add those usings that we do know we need for bindings.
163- var usingDirectives = tree . GetRoot ( )
164- . DescendantNodes ( )
165- . OfType < UsingDirectiveSyntax > ( )
166- . Select ( d => d . Name ! . ToString ( ) ) . ToArray ( ) ;
167- var usingDirectivesToKeep = new HashSet < string > ( usingDirectives ) {
164+ var usingDirectivesToKeep = new SortedSet < string > ( codeChanges . UsingDirectives ) {
168165 // add the using statements that we know we need and print them to the sb
169166 } ;
170167
@@ -174,7 +171,7 @@ static void CollectUsingStatements (SyntaxTree tree, TabbedStringBuilder sb, ICo
174171 }
175172
176173 // add them sorted so that we have testeable generated code
177- foreach ( var ns in usingDirectivesToKeep . OrderBy ( s => s ) ) {
174+ foreach ( var ns in usingDirectivesToKeep ) {
178175 if ( string . IsNullOrEmpty ( ns ) )
179176 continue ;
180177 sb . AppendLine ( $ "using { ns } ;") ;
0 commit comments