Skip to content

Commit

Permalink
[Rgen] Share DataModel between the generator and the transformer. (#2…
Browse files Browse the repository at this point in the history
…2015)

In this change we are making the necesary changes to share the data
model code between the generator and the transformer.

When we talk about sharing code in C# the average dotnet developer would
create a csproj with the shared code and would reference it. In normal
circumtances this is not a bad option, but our case is different and
here are some of the reasons we cannot take that path:

1. Roslyn code generators with more than one dll are problematic to
distribute. You can already see how bad it is by looking at the dll
shared between the code generator and the analyzer. The shared library
has to be added as an analyzer so that it loads with the generator. We
want to keep the number of dlls to a minimun.
2. While the data models are similar, they are not identical. The
attributes used by the code generator and the old api defintions are
different. We would around this by splitting the definitions in 2 files:
a - A common file with all date that does not depend on the attributes.
b - A application specific file that contains the properties needed by
the common parts BUT that uses structures specific for the application.
An example is the ExportData. The ExportData is a generic in the
generator (which contains flags) while it is not in the transformer. We
also split the TryCreate and Constructor methods since those need to
init the application specific parths.

In this commit we do not implement the transformer parts since that
would make the diff hader. We are only moving code around and adding
dummy implementations for the transformer project to compile.

---------

Co-authored-by: GitHub Actions Autoformatter <[email protected]>
  • Loading branch information
mandel-macaque and GitHub Actions Autoformatter authored Jan 20, 2025
1 parent dc720d4 commit 05a3831
Show file tree
Hide file tree
Showing 27 changed files with 1,073 additions and 663 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;

namespace Microsoft.Macios.Generator.DataModel;

readonly partial struct Accessor {

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

public bool MarshalNativeExceptions
=> ExportPropertyData is not null && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions);

/// <summary>
/// Create a new code change in a property accessor.
/// </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,
ExportData<ObjCBindings.Property>? exportPropertyData,
ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers)
{
Kind = accessorKind;
SymbolAvailability = symbolAvailability;
ExportPropertyData = exportPropertyData;
Attributes = attributes;
Modifiers = modifiers;
}

/// <summary>
/// Retrieve the selector to be used with the associated property.
/// </summary>
/// <param name="associatedProperty">The property associated with the accessor.</param>
/// <returns>The selector to use for the accessor.</returns>
public string? GetSelector (in Property associatedProperty)
{
// this is not a property but a field, we cannot retrieve a selector.
if (!associatedProperty.IsProperty)
return null;

// There are two possible cases, the current accessor has an export attribute, if that
// is the case, we will use the selector in that attribute. Otherwise, we have:
//
// * getter: return the property selector.
// * setter: use the registrar code (it has the right logic) to get the setter.
if (ExportPropertyData is null) {
return Kind == AccessorKind.Getter
? associatedProperty.ExportPropertyData.Value.Selector
: Registrar.Registrar.CreateSetterSelector (associatedProperty.ExportPropertyData.Value.Selector);
}

return ExportPropertyData.Value.Selector;
}

/// <summary>
/// Returns if the accessor should marshal native exceptions with the associated property.
/// </summary>
/// <param name="property">The property associated with the accessor.</param>
/// <returns>True if either the accessor or the property were marked with the MarshalNativeExceptions flag.</returns>
public bool ShouldMarshalNativeExceptions (in Property property)
=> MarshalNativeExceptions || property.MarshalNativeExceptions;

}
67 changes: 3 additions & 64 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;

namespace Microsoft.Macios.Generator.DataModel;

readonly struct Accessor : IEquatable<Accessor> {
[StructLayout (LayoutKind.Auto)]
readonly partial struct Accessor : IEquatable<Accessor> {
/// <summary>
/// The kind of accessor.
/// </summary>
Expand All @@ -21,14 +22,6 @@ 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; }

public bool MarshalNativeExceptions
=> ExportPropertyData is not null && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions);

/// <summary>
/// List of attribute code changes of the accessor.
/// </summary>
Expand All @@ -39,60 +32,6 @@ public bool MarshalNativeExceptions
/// </summary>
public ImmutableArray<SyntaxToken> Modifiers { get; }

/// <summary>
/// Create a new code change in a property accessor.
/// </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,
ExportData<ObjCBindings.Property>? exportPropertyData,
ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers)
{
Kind = accessorKind;
SymbolAvailability = symbolAvailability;
ExportPropertyData = exportPropertyData;
Attributes = attributes;
Modifiers = modifiers;
}

/// <summary>
/// Retrieve the selector to be used with the associated property.
/// </summary>
/// <param name="associatedProperty">The property associated with the accessor.</param>
/// <returns>The selector to use for the accessor.</returns>
public string? GetSelector (in Property associatedProperty)
{
// this is not a property but a field, we cannot retrieve a selector.
if (!associatedProperty.IsProperty)
return null;

// There are two possible cases, the current accessor has an export attribute, if that
// is the case, we will use the selector in that attribute. Otherwise, we have:
//
// * getter: return the property selector.
// * setter: use the registrar code (it has the right logic) to get the setter.
if (ExportPropertyData is null) {
return Kind == AccessorKind.Getter
? associatedProperty.ExportPropertyData.Value.Selector
: Registrar.Registrar.CreateSetterSelector (associatedProperty.ExportPropertyData.Value.Selector);
}

return ExportPropertyData.Value.Selector;
}

/// <summary>
/// Returns if the accessor should marshal native exceptions with the associated property.
/// </summary>
/// <param name="property">The property associated with the accessor.</param>
/// <returns>True if either the accessor or the property were marked with the MarshalNativeExceptions flag.</returns>
public bool ShouldMarshalNativeExceptions (in Property property)
=> MarshalNativeExceptions || property.MarshalNativeExceptions;

/// <inheritdoc />
public bool Equals (Accessor other)
{
Expand Down
Loading

0 comments on commit 05a3831

Please sign in to comment.