Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into dev/rolf/windows-test…
Browse files Browse the repository at this point in the history
…s-html-report
  • Loading branch information
rolfbjarne committed Jan 7, 2025
2 parents 456d9f5 + b472b63 commit 60061e5
Show file tree
Hide file tree
Showing 72 changed files with 8,007 additions and 976 deletions.
19 changes: 19 additions & 0 deletions src/ObjCRuntime/RegistrarHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,25 @@ static MapInfo GetMapEntry (string assemblyName)
{
if (TryGetMapEntry (assemblyName, out var rv))
return rv;

#if TRACE
Runtime.NSLog ($"RegistrarHelper.GetMapEntry ({assemblyName}) => failed to find entry, will ensure module constructors are called for all loaded assemblies.");
#endif
// An assembly is only registered if we've (tried to) execute code from it, which is not guaranteed to
// happen before we get here (in particular for app extensions, which don't have a managed Main method).
// So here we loop over all the assemblies in the current domain, make sure the module constructor
// has been called for all of them, and then we try again.
var assemblies = AppDomain.CurrentDomain.GetAssemblies ();
foreach (var asm in assemblies)
RuntimeHelpers.RunModuleConstructor (asm.ManifestModule.ModuleHandle);

if (TryGetMapEntry (assemblyName, out rv))
return rv;

#if TRACE
Runtime.NSLog ($"RegistrarHelper.GetMapEntry ({assemblyName}) => failed to find entry for the second time.");
#endif

throw ErrorHelper.CreateError (8055, Errors.MX8055 /* Could not find the type 'ObjCRuntime.__Registrar__' in the assembly '{0}' */, assemblyName);
}

Expand Down
7 changes: 7 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/AttributesNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ static class AttributesNames {
public const string UnsupportedOSPlatformAttribute = "System.Runtime.Versioning.UnsupportedOSPlatformAttribute";
public const string ObsoletedOSPlatformAttribute = "System.Runtime.Versioning.ObsoletedOSPlatformAttribute";

public static readonly string [] BindingTypes = [
BindingAttribute,
BindingCategoryAttribute,
BindingClassAttribute,
BindingProtocolAttribute
];


public static string? GetBindingTypeAttributeName<T> () where T : Enum
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace Microsoft.Macios.Generator;
/// </summary>
[Generator]
public class BindingSourceGeneratorGenerator : IIncrementalGenerator {
static readonly DeclarationCodeChangesEqualityComparer equalityComparer = new ();
static readonly CodeChangesEqualityComparer equalityComparer = new ();

/// <inheritdoc cref="IIncrementalGenerator"/>
public void Initialize (IncrementalGeneratorInitializationContext context)
Expand All @@ -34,15 +34,15 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
fileName, SourceText.From (content, Encoding.UTF8)));
}

// our bindings are special. Due to the fact that we write shared code in the Library.g.cs and the Trampolines.g.cs
// our bindings are special. Since we write shared code in the Library.g.cs and the Trampolines.g.cs
// we need to listen to all the BaseTypeDeclarationSyntax changes. We do so, generate a data model with the
// changes we are interested and later we transform them. This allows use to be able to use a RootBindingContext
// changes we are interested, and later we transform them. This allows use to be able to use a RootBindingContext
// as a bag in which we can add information about libraries and trampolines needed by the bindings.
var provider = context.SyntaxProvider
.CreateSyntaxProvider (static (node, _) => IsValidNode (node),
static (ctx, _) => GetChangesForSourceGen (ctx))
.Where (tuple => tuple.BindingAttributeFound)
.Select (static (tuple, _) => (tuple.Declaration, tuple.Changes))
.Select (static (tuple, _) => tuple.Changes)
.WithComparer (equalityComparer);

context.RegisterSourceOutput (context.CompilationProvider.Combine (provider.Collect ()),
Expand All @@ -59,29 +59,28 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
_ => false,
};

static (BaseTypeDeclarationSyntax Declaration, CodeChanges Changes, bool BindingAttributeFound)
GetChangesForSourceGen (GeneratorSyntaxContext context)
static (CodeChanges Changes, bool BindingAttributeFound) GetChangesForSourceGen (GeneratorSyntaxContext context)
{
// we do know that the context node has to be one of the base type declarations
var declarationSyntax = Unsafe.As<BaseTypeDeclarationSyntax> (context.Node);

// check if we do have the binding attr, else there nothing to retrieve
bool isBindingType = declarationSyntax.HasAttribute (context.SemanticModel, AttributesNames.BindingAttribute);
bool isBindingType = declarationSyntax.HasAtLeastOneAttribute (context.SemanticModel, AttributesNames.BindingTypes);

if (!isBindingType) {
// return empty data + false
return (declarationSyntax, default, false);
return (default, false);
}

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

static void GenerateCode (SourceProductionContext context, Compilation compilation,
in ImmutableArray<(BaseTypeDeclarationSyntax Declaration, CodeChanges Changes)> changesList)
in ImmutableArray<CodeChanges> changesList)
{
// 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 @@ -90,15 +89,17 @@ static void GenerateCode (SourceProductionContext context, Compilation compilati
// 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 rootContext = new RootBindingContext (compilation);
foreach (var (declaration, change) in changesList) {
var sb = new TabbedStringBuilder (new ());
foreach (var change in changesList) {
// init sb and add the header
var sb = new TabbedStringBuilder (new ());
sb.Clear ();
sb.WriteHeader ();
if (EmitterFactory.TryCreate (change, rootContext, sb, out var emitter)) {
if (EmitterFactory.TryCreate (change, out var emitter)) {
// write the using statements
CollectUsingStatements (declaration.SyntaxTree, sb, emitter);
CollectUsingStatements (change, sb, emitter);

if (emitter.TryEmit (change, out var diagnostics)) {
var bindingContext = new BindingContext (rootContext, sb, change);
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 ());
Expand All @@ -115,7 +116,7 @@ static void GenerateCode (SourceProductionContext context, Compilation compilati
context.ReportDiagnostic (Diagnostic.Create (
Diagnostics
.RBI0000, // An unexpected error ocurred while processing '{0}'. Please fill a bug report at https://github.com/xamarin/xamarin-macios/issues/new.
declaration.GetLocation (),
null,
change.FullyQualifiedSymbol));
}
}
Expand Down Expand Up @@ -149,22 +150,18 @@ static void GenerateLibraryCode (SourceProductionContext context, RootBindingCon
}

/// <summary>
/// Collect the using statements from the class declaration root syntaxt tree and add them to the string builder
/// Collect the using statements from the named ype code changes and add them to the string builder
/// 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="tree">Root syntax tree of the base type declaration.</param>
/// <param name="codeChanges">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 (SyntaxTree tree, TabbedStringBuilder sb, ICodeEmitter emitter)
static void CollectUsingStatements (in CodeChanges codeChanges, 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 usingDirectives = tree.GetRoot ()
.DescendantNodes ()
.OfType<UsingDirectiveSyntax> ()
.Select (d => d.Name!.ToString ()).ToArray ();
var usingDirectivesToKeep = new HashSet<string> (usingDirectives) {
var usingDirectivesToKeep = new SortedSet<string> (codeChanges.UsingDirectives) {
// add the using statements that we know we need and print them to the sb
};

Expand All @@ -174,7 +171,7 @@ static void CollectUsingStatements (SyntaxTree tree, TabbedStringBuilder sb, ICo
}

// add them sorted so that we have testeable generated code
foreach (var ns in usingDirectivesToKeep.OrderBy (s => s)) {
foreach (var ns in usingDirectivesToKeep) {
if (string.IsNullOrEmpty (ns))
continue;
sb.AppendLine ($"using {ns};");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

namespace Microsoft.Macios.Generator;

public class ListComparer<T> : EqualityComparer<IList<T>> {
public class CollectionComparer<T> : EqualityComparer<IReadOnlyCollection<T>> {
readonly IComparer<T>? comparer;
readonly IEqualityComparer<T> valueComparer;

public ListComparer (IComparer<T>? sortComparer = null, IEqualityComparer<T>? equalityComparer = null)
public CollectionComparer (IComparer<T>? sortComparer = null, IEqualityComparer<T>? equalityComparer = null)
{
comparer = sortComparer;
valueComparer = equalityComparer ?? EqualityComparer<T>.Default;
}

/// <inheritdoc/>
public override bool Equals (IList<T>? x, IList<T>? y)
public override bool Equals (IReadOnlyCollection<T>? x, IReadOnlyCollection<T>? y)
{
// bases cases for null or diff size
if (x is null && y is null)
Expand All @@ -42,7 +42,7 @@ public override bool Equals (IList<T>? x, IList<T>? y)
}

/// <inheritdoc/>
public override int GetHashCode (IList<T> obj)
public override int GetHashCode (IReadOnlyCollection<T> obj)
{
var hash = new HashCode ();
foreach (var element in obj) {
Expand Down
29 changes: 29 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/Context/BindingContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.Macios.Generator.DataModel;

namespace Microsoft.Macios.Generator.Context;

readonly struct BindingContext {

/// <summary>
/// The root context of the current binding operation.
/// </summary>
public RootBindingContext RootContext { get; }

/// <summary>
/// Tabbed string builder that can be used to write the generated code.
/// </summary>
public TabbedStringBuilder Builder { get; }

/// <summary>
/// Current code changes for the binding context.
/// </summary>
public CodeChanges Changes { get; }

public BindingContext (RootBindingContext rootContext, TabbedStringBuilder builder, CodeChanges changes)
{
RootContext = rootContext;
Builder = builder;
Changes = changes;
}

}
19 changes: 16 additions & 3 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;

namespace Microsoft.Macios.Generator.DataModel;
Expand All @@ -18,6 +19,11 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
public SymbolAvailability SymbolAvailability { get; }

/// <summary>
/// The data of the field attribute used to mark the value as a property binding.
/// </summary>
public ExportData<ObjCBindings.Property>? ExportPropertyData { get; init; }

/// <summary>
/// List of attribute code changes of the accessor.
/// </summary>
Expand All @@ -33,13 +39,18 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
/// <param name="accessorKind">The kind of accessor.</param>
/// <param name="symbolAvailability">The os availability of the symbol.</param>
/// <param name="exportPropertyData">The data of the export attribute found in the accessor.</param>
/// <param name="attributes">The list of attributes attached to the accessor.</param>
/// <param name="modifiers">The list of visibility modifiers of the accessor.</param>
public Accessor (AccessorKind accessorKind, SymbolAvailability symbolAvailability, ImmutableArray<AttributeCodeChange> attributes,
public Accessor (AccessorKind accessorKind,
SymbolAvailability symbolAvailability,
ExportData<ObjCBindings.Property>? exportPropertyData,
ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers)
{
Kind = accessorKind;
SymbolAvailability = symbolAvailability;
ExportPropertyData = exportPropertyData;
Attributes = attributes;
Modifiers = modifiers;
}
Expand All @@ -51,6 +62,8 @@ public bool Equals (Accessor other)
return false;
if (SymbolAvailability != other.SymbolAvailability)
return false;
if (ExportPropertyData != other.ExportPropertyData)
return false;

var attrsComparer = new AttributesEqualityComparer ();
if (!attrsComparer.Equals (Attributes, other.Attributes))
Expand All @@ -68,7 +81,7 @@ public override bool Equals (object? obj)
/// <inheritdoc />
public override int GetHashCode ()
{
return HashCode.Combine ((int) Kind, Attributes, Modifiers);
return HashCode.Combine ((int) Kind, SymbolAvailability, ExportPropertyData, Attributes, Modifiers);
}

public static bool operator == (Accessor left, Accessor right)
Expand All @@ -84,7 +97,7 @@ public override int GetHashCode ()
/// <inheritdoc />
public override string ToString ()
{
var sb = new StringBuilder ($"{{ Kind: {Kind}, Supported Platforms: {SymbolAvailability} Modifiers: [");
var sb = new StringBuilder ($"{{ Kind: {Kind}, Supported Platforms: {SymbolAvailability}, ExportData: {ExportPropertyData?.ToString () ?? "null"} Modifiers: [");
sb.AppendJoin (",", Modifiers.Select (x => x.Text));
sb.Append ("], Attributes: [");
sb.AppendJoin (", ", Attributes);
Expand Down
Loading

0 comments on commit 60061e5

Please sign in to comment.