Skip to content

Commit

Permalink
[Rgen] Renamed CodeChanges to Binding to be more clear.
Browse files Browse the repository at this point in the history
Initially the structure was name to make it simpler to understand that
it was a code change/update that was detected by the roslyn incremental
generator. Now that the structure is shared with the transformer, it
makes more sense to rename it to 'Binding'.

We have update all the helper classes too.
  • Loading branch information
mandel-macaque committed Jan 23, 2025
1 parent e62a38f commit 99af672
Show file tree
Hide file tree
Showing 22 changed files with 197 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Microsoft.Macios.Generator;
/// </summary>
[Generator]
public class BindingSourceGeneratorGenerator : IIncrementalGenerator {
static readonly CodeChangesEqualityComparer equalityComparer = new ();
static readonly BindingEqualityComparer equalityComparer = new ();

/// <inheritdoc cref="IIncrementalGenerator"/>
public void Initialize (IncrementalGeneratorInitializationContext context)
Expand All @@ -45,16 +45,16 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
static (ctx, _) => GetChangesForSourceGen (ctx))
.Where (tuple => tuple.BindingAttributeFound);

var codeChanges = provider
.Select (static (tuple, _) => tuple.Changes)
var bindings = provider
.Select (static (tuple, _) => tuple.Bindings)
.WithComparer (equalityComparer);

// ideally we could do a distinct, because each code change can return the same libs, this makes the library
// generation more common than what we would like, but it is the smallest code generation.
var libraryProvider = provider
.Select ((tuple, _) => (tuple.RootBindingContext, tuple.Changes.LibraryPaths));
.Select ((tuple, _) => (tuple.RootBindingContext, tuple.Bindings.LibraryPaths));

context.RegisterSourceOutput (context.CompilationProvider.Combine (codeChanges.Collect ()),
context.RegisterSourceOutput (context.CompilationProvider.Combine (bindings.Collect ()),
((ctx, t) => GenerateCode (ctx, t.Right)));

context.RegisterSourceOutput (context.CompilationProvider.Combine (libraryProvider.Collect ()),
Expand All @@ -71,7 +71,7 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
_ => false,
};

static (RootBindingContext RootBindingContext, CodeChanges Changes, bool BindingAttributeFound) GetChangesForSourceGen (GeneratorSyntaxContext context)
static (RootBindingContext RootBindingContext, Binding Bindings, bool BindingAttributeFound) GetChangesForSourceGen (GeneratorSyntaxContext context)
{
var bindingContext = new RootBindingContext (context.SemanticModel);
// we do know that the context node has to be one of the base type declarations
Expand All @@ -85,14 +85,14 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
return (bindingContext, default, false);
}

var codeChanges = CodeChanges.FromDeclaration (declarationSyntax, bindingContext);
var binding = Binding.FromDeclaration (declarationSyntax, bindingContext);
// if code changes are null, return the default value and a false to later ignore the change
return codeChanges is not null
? (bindingContext, codeChanges.Value, isBindingType)
return binding is not null
? (bindingContext, binding.Value, isBindingType)
: (bindingContext, default, false);
}

static void GenerateCode (SourceProductionContext context, in ImmutableArray<CodeChanges> changesList)
static void GenerateCode (SourceProductionContext context, in ImmutableArray<Binding> bindingsList)
{
// The process is as follows, get all the changes we have received from the incremental generator,
// loop over them, and based on the CodeChange.BindingType we are going to build the symbol context
Expand All @@ -101,20 +101,20 @@ static void GenerateCode (SourceProductionContext context, in ImmutableArray<Cod
// Once all the enums, classes and interfaces have been processed, we will use the data collected
// in the RootBindingContext to generate the library and trampoline code.
var sb = new TabbedStringBuilder (new ());
foreach (var change in changesList) {
foreach (var binding in bindingsList) {
// init sb and add the header
sb.Clear ();
sb.WriteHeader ();
if (EmitterFactory.TryCreate (change, out var emitter)) {
if (EmitterFactory.TryCreate (binding, out var emitter)) {
// write the using statements
CollectUsingStatements (change, sb, emitter);
CollectUsingStatements (binding, sb, emitter);

var bindingContext = new BindingContext (sb, change);
var bindingContext = new BindingContext (sb, binding);
if (emitter.TryEmit (bindingContext, out var diagnostics)) {
// only add a file when we do generate code
var code = sb.ToString ();
var namespacePath = Path.Combine (change.Namespace.ToArray ());
var fileName = emitter.GetSymbolName (change);
var namespacePath = Path.Combine (binding.Namespace.ToArray ());
var fileName = emitter.GetSymbolName (binding);
context.AddSource ($"{Path.Combine (namespacePath, fileName)}.g.cs",
SourceText.From (code, Encoding.UTF8));
} else {
Expand All @@ -128,7 +128,7 @@ static void GenerateCode (SourceProductionContext context, in ImmutableArray<Cod
Diagnostics
.RBI0000, // An unexpected error ocurred while processing '{0}'. Please fill a bug report at https://github.com/xamarin/xamarin-macios/issues/new.
null,
change.FullyQualifiedSymbol));
binding.FullyQualifiedSymbol));
}
}
}
Expand Down Expand Up @@ -175,14 +175,14 @@ static void GenerateLibraryCode (SourceProductionContext context,
/// that will be used to generate the code. This way we ensure that we have all the namespaces needed by the
/// generated code.
/// </summary>
/// <param name="codeChanges">The code changes for a given named type.</param>
/// <param name="binding">The code changes for a given named type.</param>
/// <param name="sb">String builder that will be used for the generated code.</param>
/// <param name="emitter">The emitter that will generate the code. Provides any extra needed namespace.</param>
static void CollectUsingStatements (in CodeChanges codeChanges, TabbedStringBuilder sb, ICodeEmitter emitter)
static void CollectUsingStatements (in Binding binding, TabbedStringBuilder sb, ICodeEmitter emitter)
{
// collect all using from the syntax tree, add them to a hash to make sure that we don't have duplicates
// and add those usings that we do know we need for bindings.
var usingDirectivesToKeep = new SortedSet<string> (codeChanges.UsingDirectives) {
var usingDirectivesToKeep = new SortedSet<string> (binding.UsingDirectives) {
// add the using statements that we know we need and print them to the sb
};

Expand Down
4 changes: 2 additions & 2 deletions src/rgen/Microsoft.Macios.Generator/Context/BindingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ readonly struct BindingContext {
/// <summary>
/// Current code changes for the binding context.
/// </summary>
public CodeChanges Changes { get; }
public Binding Changes { get; }

public BindingContext (TabbedStringBuilder builder, CodeChanges changes)
public BindingContext (TabbedStringBuilder builder, Binding changes)
{
Builder = builder;
Changes = changes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace Microsoft.Macios.Generator.DataModel;

readonly partial struct CodeChanges {
readonly partial struct Binding {

/// <summary>
/// Represents the type of binding that the code changes are for.
Expand Down Expand Up @@ -146,7 +146,7 @@ static void GetMembers<T, TR> (TypeDeclarationSyntax baseDeclarationSyntax, Root
/// <param name="namespace">The namespace that contains the named type.</param>
/// <param name="fullyQualifiedSymbol">The fully qualified name of the symbol.</param>
/// <param name="symbolAvailability">The platform availability of the named symbol.</param>
internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray<string> @namespace,
internal Binding (BindingInfo bindingInfo, string name, ImmutableArray<string> @namespace,
string fullyQualifiedSymbol, SymbolAvailability symbolAvailability)
{
this.bindingInfo = bindingInfo;
Expand All @@ -157,11 +157,11 @@ internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray<strin
}

/// <summary>
/// Creates a new instance of the <see cref="CodeChanges"/> struct for a given enum declaration.
/// Creates a new instance of the <see cref="Binding"/> struct for a given enum declaration.
/// </summary>
/// <param name="enumDeclaration">The enum declaration that triggered the change.</param>
/// <param name="context">The root binding context of the current compilation.</param>
CodeChanges (EnumDeclarationSyntax enumDeclaration, RootBindingContext context)
Binding (EnumDeclarationSyntax enumDeclaration, RootBindingContext context)
{
context.SemanticModel.GetSymbolData (
declaration: enumDeclaration,
Expand Down Expand Up @@ -207,11 +207,11 @@ internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray<strin
}

/// <summary>
/// Creates a new instance of the <see cref="CodeChanges"/> struct for a given class declaration.
/// Creates a new instance of the <see cref="Binding"/> struct for a given class declaration.
/// </summary>
/// <param name="classDeclaration">The class declaration that triggered the change.</param>
/// <param name="context">The root binding context of the current compilation.</param>
CodeChanges (ClassDeclarationSyntax classDeclaration, RootBindingContext context)
Binding (ClassDeclarationSyntax classDeclaration, RootBindingContext context)
{
context.SemanticModel.GetSymbolData (
declaration: classDeclaration,
Expand Down Expand Up @@ -239,11 +239,11 @@ internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray<strin
}

/// <summary>
/// Creates a new instance of the <see cref="CodeChanges"/> struct for a given interface declaration.
/// Creates a new instance of the <see cref="Binding"/> struct for a given interface declaration.
/// </summary>
/// <param name="interfaceDeclaration">The interface declaration that triggered the change.</param>
/// <param name="context">The root binding context of the current compilation.</param>
CodeChanges (InterfaceDeclarationSyntax interfaceDeclaration, RootBindingContext context)
Binding (InterfaceDeclarationSyntax interfaceDeclaration, RootBindingContext context)
{
context.SemanticModel.GetSymbolData (
declaration: interfaceDeclaration,
Expand Down Expand Up @@ -275,13 +275,13 @@ internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray<strin
/// <param name="baseTypeDeclarationSyntax">The declaration syntax whose change we want to calculate.</param>
/// <param name="context">The root binding context of the current compilation.</param>
/// <returns>A code change or null if it could not be calculated.</returns>
public static CodeChanges? FromDeclaration (BaseTypeDeclarationSyntax baseTypeDeclarationSyntax,
public static Binding? FromDeclaration (BaseTypeDeclarationSyntax baseTypeDeclarationSyntax,
RootBindingContext context)
=> baseTypeDeclarationSyntax switch {
EnumDeclarationSyntax enumDeclarationSyntax => new CodeChanges (enumDeclarationSyntax, context),
InterfaceDeclarationSyntax interfaceDeclarationSyntax => new CodeChanges (interfaceDeclarationSyntax,
EnumDeclarationSyntax enumDeclarationSyntax => new Binding (enumDeclarationSyntax, context),
InterfaceDeclarationSyntax interfaceDeclarationSyntax => new Binding (interfaceDeclarationSyntax,
context),
ClassDeclarationSyntax classDeclarationSyntax => new CodeChanges (classDeclarationSyntax, context),
ClassDeclarationSyntax classDeclarationSyntax => new Binding (classDeclarationSyntax, context),
_ => null
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Microsoft.Macios.Generator.DataModel;
/// generated code.
/// </summary>
[StructLayout (LayoutKind.Auto)]
readonly partial struct CodeChanges {
readonly partial struct Binding {

readonly string name = string.Empty;
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ namespace Microsoft.Macios.Generator.DataModel;
/// <summary>
/// Custom code changes comparer used for the Roslyn code generation to invalidate caching.
/// </summary>
class CodeChangesEqualityComparer : EqualityComparer<CodeChanges> {
class BindingEqualityComparer : EqualityComparer<Binding> {
/// <inheritdoc />
public override bool Equals (CodeChanges x, CodeChanges y)
public override bool Equals (Binding x, Binding y)
{

// order does not matter in the using directives, use a comparer that sorts them
Expand Down Expand Up @@ -82,7 +82,7 @@ public override bool Equals (CodeChanges x, CodeChanges y)
}

/// <inheritdoc />
public override int GetHashCode (CodeChanges obj)
public override int GetHashCode (Binding obj)
{
return HashCode.Combine (obj.FullyQualifiedSymbol, obj.EnumMembers);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Microsoft.Macios.Generator.Emitters;

class CategoryEmitter : ICodeEmitter {
public string GetSymbolName (in CodeChanges codeChanges) => string.Empty;
public string GetSymbolName (in Binding binding) => string.Empty;
public IEnumerable<string> UsingStatements => [];
public bool TryEmit (in BindingContext bindingContext, [NotNullWhen (false)] out ImmutableArray<Diagnostic>? diagnostics)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
namespace Microsoft.Macios.Generator.Emitters;

class ClassEmitter : ICodeEmitter {
public string GetSymbolName (in CodeChanges codeChanges) => codeChanges.Name;
public string GetSymbolName (in Binding binding) => binding.Name;

public IEnumerable<string> UsingStatements => [
"System",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ static class EmitterFactory {
{ BindingType.Protocol, new InterfaceEmitter () },
{ BindingType.Category, new CategoryEmitter () },
};
public static bool TryCreate (CodeChanges changes, [NotNullWhen (true)] out ICodeEmitter? emitter)
public static bool TryCreate (Binding changes, [NotNullWhen (true)] out ICodeEmitter? emitter)
=> emitters.TryGetValue (changes.BindingType, out emitter);
}
38 changes: 19 additions & 19 deletions src/rgen/Microsoft.Macios.Generator/Emitters/EnumEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ namespace Microsoft.Macios.Generator.Emitters;

class EnumEmitter : ICodeEmitter {

public string GetSymbolName (in CodeChanges codeChanges) => $"{codeChanges.Name}Extensions";
public string GetSymbolName (in Binding binding) => $"{binding.Name}Extensions";
public IEnumerable<string> UsingStatements => ["Foundation", "ObjCRuntime", "System"];

void EmitEnumFieldAtIndex (TabbedStringBuilder classBlock, in CodeChanges codeChanges, int index)
void EmitEnumFieldAtIndex (TabbedStringBuilder classBlock, in Binding binding, int index)
{
var enumField = codeChanges.EnumMembers [index];
var enumField = binding.EnumMembers [index];
if (enumField.FieldInfo is null)
return;

Expand All @@ -33,36 +33,36 @@ void EmitEnumFieldAtIndex (TabbedStringBuilder classBlock, in CodeChanges codeCh
}
}

bool TryEmit (TabbedStringBuilder classBlock, in CodeChanges codeChanges)
bool TryEmit (TabbedStringBuilder classBlock, in Binding binding)
{
// keep track of the field symbols, they have to be unique, if we find a duplicate we return false and
// abort the code generation
var backingFields = new HashSet<string> ();
for (var index = 0; index < codeChanges.EnumMembers.Length; index++) {
if (codeChanges.EnumMembers [index].FieldInfo is null)
for (var index = 0; index < binding.EnumMembers.Length; index++) {
if (binding.EnumMembers [index].FieldInfo is null)
continue;
if (!backingFields.Add (codeChanges.EnumMembers [index].FieldInfo!.Value.FieldData.SymbolName)) {
if (!backingFields.Add (binding.EnumMembers [index].FieldInfo!.Value.FieldData.SymbolName)) {
return false;
}
classBlock.AppendLine ();
EmitEnumFieldAtIndex (classBlock, codeChanges, index);
EmitEnumFieldAtIndex (classBlock, binding, index);
}
return true;
}

void EmitExtensionMethods (TabbedStringBuilder classBlock, in CodeChanges codeChanges)
void EmitExtensionMethods (TabbedStringBuilder classBlock, in Binding binding)
{
if (codeChanges.EnumMembers.Length == 0)
if (binding.EnumMembers.Length == 0)
return;

// smart enum require 4 diff methods to be able to retrieve the values

// Get constant
using (var getConstantBlock = classBlock.CreateBlock ($"public static NSString? GetConstant (this {codeChanges.Name} self)", true)) {
using (var getConstantBlock = classBlock.CreateBlock ($"public static NSString? GetConstant (this {binding.Name} self)", true)) {
getConstantBlock.AppendLine ("IntPtr ptr = IntPtr.Zero;");
using (var switchBlock = getConstantBlock.CreateBlock ("switch ((int) self)", true)) {
for (var index = 0; index < codeChanges.EnumMembers.Length; index++) {
var enumMember = codeChanges.EnumMembers [index];
for (var index = 0; index < binding.EnumMembers.Length; index++) {
var enumMember = binding.EnumMembers [index];
if (enumMember.FieldInfo is null)
continue;
var (fieldData, _, _) = enumMember.FieldInfo.Value;
Expand All @@ -77,15 +77,15 @@ void EmitExtensionMethods (TabbedStringBuilder classBlock, in CodeChanges codeCh

classBlock.AppendLine ();
// Get value
using (var getValueBlock = classBlock.CreateBlock ($"public static {codeChanges.Name} GetValue (NSString constant)", true)) {
using (var getValueBlock = classBlock.CreateBlock ($"public static {binding.Name} GetValue (NSString constant)", true)) {
getValueBlock.AppendLine ("if (constant is null)");
getValueBlock.AppendLine ("\tthrow new ArgumentNullException (nameof (constant));");
foreach (var enumMember in codeChanges.EnumMembers) {
foreach (var enumMember in binding.EnumMembers) {
if (enumMember.FieldInfo is null)
continue;
var (fieldData, _, _) = enumMember.FieldInfo.Value;
getValueBlock.AppendLine ($"if (constant.IsEqualTo ({fieldData.SymbolName}))");
getValueBlock.AppendLine ($"\treturn {codeChanges.Name}.{enumMember.Name};");
getValueBlock.AppendLine ($"\treturn {binding.Name}.{enumMember.Name};");
}

getValueBlock.AppendLine (
Expand All @@ -95,7 +95,7 @@ void EmitExtensionMethods (TabbedStringBuilder classBlock, in CodeChanges codeCh
classBlock.AppendLine ();
// To ConstantArray
classBlock.AppendRaw (
@$"internal static NSString?[]? ToConstantArray (this {codeChanges.Name}[]? values)
@$"internal static NSString?[]? ToConstantArray (this {binding.Name}[]? values)
{{
if (values is null)
return null;
Expand All @@ -110,11 +110,11 @@ void EmitExtensionMethods (TabbedStringBuilder classBlock, in CodeChanges codeCh
classBlock.AppendLine ();
// ToEnumArray
classBlock.AppendRaw (
@$"internal static {codeChanges.Name}[]? ToEnumArray (this NSString[]? values)
@$"internal static {binding.Name}[]? ToEnumArray (this NSString[]? values)
{{
if (values is null)
return null;
var rv = new global::System.Collections.Generic.List<{codeChanges.Name}> ();
var rv = new global::System.Collections.Generic.List<{binding.Name}> ();
for (var i = 0; i < values.Length; i++) {{
var value = values [i];
rv.Add (GetValue (value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.Macios.Generator.Emitters;
/// Interface to be implemented by all those classes that know how to emit code for a binding.
/// </summary>
interface ICodeEmitter {
string GetSymbolName (in CodeChanges codeChanges);
string GetSymbolName (in Binding binding);
bool TryEmit (in BindingContext bindingContext, [NotNullWhen (false)] out ImmutableArray<Diagnostic>? diagnostics);
IEnumerable<string> UsingStatements { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Microsoft.Macios.Generator.Emitters;

class InterfaceEmitter : ICodeEmitter {
public string GetSymbolName (in CodeChanges codeChanges) => string.Empty;
public string GetSymbolName (in Binding binding) => string.Empty;
public IEnumerable<string> UsingStatements => [];
public bool TryEmit (in BindingContext bindingContext, [NotNullWhen (false)] out ImmutableArray<Diagnostic>? diagnostics)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.Macios.Generator.Emitters;

class TrampolineEmitter : ICodeEmitter {
public string SymbolNamespace => string.Empty;
public string GetSymbolName (in CodeChanges codeChanges) => string.Empty;
public string GetSymbolName (in Binding binding) => string.Empty;
public IEnumerable<string> UsingStatements { get; } = [];
public bool TryEmit (in BindingContext bindingContext, [NotNullWhen (false)] out ImmutableArray<Diagnostic>? diagnostics)
{
Expand Down
Loading

0 comments on commit 99af672

Please sign in to comment.