Skip to content

Commit

Permalink
[Rgen] Update data model to take into account changes on events. (#21700
Browse files Browse the repository at this point in the history
)

Co-authored-by: GitHub Actions Autoformatter <[email protected]>
Co-authored-by: Alex Soto <[email protected]>
  • Loading branch information
3 people authored Nov 26, 2024
1 parent 23c7103 commit d8fba3b
Show file tree
Hide file tree
Showing 13 changed files with 831 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

namespace Microsoft.Macios.Generator.DataModel;

readonly struct PropertyAccessor : IEquatable<PropertyAccessor> {
readonly struct Accessor : IEquatable<Accessor> {
/// <summary>
/// The kind of accessor.
/// </summary>
public AccessorKind Kind { get; }

/// <summary>
/// List of attribute code changes of the accesor.
/// List of attribute code changes of the accessor.
/// </summary>
public ImmutableArray<AttributeCodeChange> Attributes { get; }

Expand All @@ -27,8 +27,8 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
/// <param name="accessorKind">The kind of accessor.</param>
/// <param name="attributes">The list of attributes attached to the accessor.</param>
/// <param name="modifiers">The list of visibility modifiers of the accesor.</param>
public PropertyAccessor (AccessorKind accessorKind, ImmutableArray<AttributeCodeChange> attributes,
/// <param name="modifiers">The list of visibility modifiers of the accessor.</param>
public Accessor (AccessorKind accessorKind, ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers)
{
Kind = accessorKind;
Expand All @@ -37,7 +37,7 @@ public PropertyAccessor (AccessorKind accessorKind, ImmutableArray<AttributeCode
}

/// <inheritdoc />
public bool Equals (PropertyAccessor other)
public bool Equals (Accessor other)
{
if (Kind != other.Kind)
return false;
Expand All @@ -51,7 +51,7 @@ public bool Equals (PropertyAccessor other)
/// <inheritdoc />
public override bool Equals (object? obj)
{
return obj is PropertyAccessor other && Equals (other);
return obj is Accessor other && Equals (other);
}

/// <inheritdoc />
Expand All @@ -60,12 +60,12 @@ public override int GetHashCode ()
return HashCode.Combine ((int) Kind, Attributes, Modifiers);
}

public static bool operator == (PropertyAccessor left, PropertyAccessor right)
public static bool operator == (Accessor left, Accessor right)
{
return left.Equals (right);
}

public static bool operator != (PropertyAccessor left, PropertyAccessor right)
public static bool operator != (Accessor left, Accessor right)
{
return !left.Equals (right);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@

namespace Microsoft.Macios.Generator.DataModel;

class PropertyAccessorsEqualityComparer : IEqualityComparer<ImmutableArray<PropertyAccessor>> {
public bool Equals (ImmutableArray<PropertyAccessor> x, ImmutableArray<PropertyAccessor> y)
class AccessorsEqualityComparer : IEqualityComparer<ImmutableArray<Accessor>> {
public bool Equals (ImmutableArray<Accessor> x, ImmutableArray<Accessor> y)
{
// property accessor kinds cannot be duplicated due to the definition of the language, create two dictionaries
// using the kind as a key and then re-use our dictionary comparer
var xDictionary = Enumerable.ToDictionary (x, accessor => accessor.Kind);
var yDictionary = Enumerable.ToDictionary (y, accessor => accessor.Kind);
var comparer = new DictionaryComparer<AccessorKind, PropertyAccessor> ();
var comparer = new DictionaryComparer<AccessorKind, Accessor> ();
return comparer.Equals (xDictionary, yDictionary);
}

public int GetHashCode (ImmutableArray<PropertyAccessor> obj)
public int GetHashCode (ImmutableArray<Accessor> obj)
{
var hashCode = new HashCode ();
foreach (var accessor in obj) {
Expand Down
21 changes: 21 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ readonly struct CodeChanges {
/// </summary>
public ImmutableArray<Constructor> Constructors { get; init; } = [];

/// <summary>
/// Changes to the events of the symbol.
/// </summary>
public ImmutableArray<Event> Events { get; init; } = [];

/// <summary>
/// Decide if an enum value should be ignored as a change.
/// </summary>
Expand Down Expand Up @@ -86,6 +91,12 @@ internal static bool Skip (ConstructorDeclarationSyntax constructorDeclarationSy
return false;
}

internal static bool Skip (EventDeclarationSyntax eventDeclarationSyntax, SemanticModel semanticModel)
{
// TODO: we need to confirm this when we have support from the roslyn team.
return false;
}

/// <summary>
/// Internal constructor added for testing purposes.
/// </summary>
Expand Down Expand Up @@ -155,6 +166,16 @@ internal CodeChanges (BindingType bindingType, string fullyQualifiedSymbol, Base
constructors.Add (change.Value);
}
Constructors = constructors.ToImmutable ();

var events = ImmutableArray.CreateBuilder<Event> ();
var eventDeclarations = classDeclaration.Members.OfType<EventDeclarationSyntax> ();
foreach (var declaration in eventDeclarations) {
if (Skip (declaration, semanticModel))
continue;
if (Event.TryCreate (declaration, semanticModel, out var change))
events.Add (change.Value);
}
Events = events.ToImmutable ();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ public bool Equals (CodeChanges x, CodeChanges y)

// compare constructors
var constructorComparer = new ConstructorsEqualityComparer ();
return constructorComparer.Equals (x.Constructors, y.Constructors);
if (!constructorComparer.Equals (x.Constructors, y.Constructors))
return false;

// compare events
var eventComparer = new EventEqualityComparer ();
return eventComparer.Equals (x.Events, y.Events);
}

/// <inheritdoc />
Expand Down
132 changes: 132 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Event.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Macios.Generator.Extensions;

namespace Microsoft.Macios.Generator.DataModel;

readonly struct Event : IEquatable<Event> {

/// <summary>
/// Name of the property.
/// </summary>
public string Name { get; } = string.Empty;

/// <summary>
/// String representation of the event type.
/// </summary>
public string Type { get; } = string.Empty;

/// <summary>
/// Get the attributes added to the member.
/// </summary>
public ImmutableArray<AttributeCodeChange> Attributes { get; } = [];

/// <summary>
/// Get the modifiers of the event.
/// </summary>
public ImmutableArray<SyntaxToken> Modifiers { get; } = [];

/// <summary>
/// Get the list of accessor changes of the event.
/// </summary>
public ImmutableArray<Accessor> Accessors { get; } = [];

internal Event (string name, string type, ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers, ImmutableArray<Accessor> accessors)
{
Name = name;
Type = type;
Attributes = attributes;
Modifiers = modifiers;
Accessors = accessors;
}

/// <inheritdoc />
public bool Equals (Event other)
{
// this could be a large && but ifs are more readable
if (Name != other.Name)
return false;
if (Type != other.Type)
return false;
var attrsComparer = new AttributesEqualityComparer ();
if (!attrsComparer.Equals (Attributes, other.Attributes))
return false;

var modifiersComparer = new ModifiersComparer ();
if (!modifiersComparer.Equals (Modifiers, other.Modifiers))
return false;

var accessorComparer = new AccessorsEqualityComparer ();
return accessorComparer.Equals (Accessors, other.Accessors);
}

/// <inheritdoc />
public override bool Equals (object? obj)
{
return obj is Event other && Equals (other);
}

/// <inheritdoc />
public override int GetHashCode ()
{
return HashCode.Combine (Name, Type, Attributes, Modifiers, Accessors);
}

public static bool operator == (Event left, Event right)
{
return left.Equals (right);
}

public static bool operator != (Event left, Event right)
{
return !left.Equals (right);
}

public static bool TryCreate (EventDeclarationSyntax declaration, SemanticModel semanticModel,
[NotNullWhen (true)] out Event? change)
{
var memberName = declaration.Identifier.ToFullString ().Trim ();
// get the symbol from the property declaration
if (semanticModel.GetDeclaredSymbol (declaration) is not IEventSymbol eventSymbol) {
change = null;
return false;
}

var type = eventSymbol.Type.ToDisplayString ().Trim ();
var attributes = declaration.GetAttributeCodeChanges (semanticModel);
ImmutableArray<Accessor> accessorCodeChanges = [];
if (declaration.AccessorList is not null && declaration.AccessorList.Accessors.Count > 0) {
// calculate any possible changes in the accessors of the property
var accessorsBucket = ImmutableArray.CreateBuilder<Accessor> ();
foreach (var accessor in declaration.AccessorList.Accessors) {
var kind = accessor.Kind ().ToAccessorKind ();
var accessorAttributeChanges = accessor.GetAttributeCodeChanges (semanticModel);
accessorsBucket.Add (new (kind, accessorAttributeChanges, [.. accessor.Modifiers]));
}

accessorCodeChanges = accessorsBucket.ToImmutable ();
}

change = new (memberName, type, attributes, [.. declaration.Modifiers], accessorCodeChanges);
return true;
}

/// <inheritdoc />
public override string ToString ()
{
var sb = new StringBuilder ($"Name: {Name}, Type: {Type}, Attributes: [");
sb.AppendJoin (",", Attributes);
sb.Append ("], Modifiers: [");
sb.AppendJoin (",", Modifiers.Select (x => x.Text));
sb.Append ("], Accessors: [");
sb.AppendJoin (",", Accessors);
sb.Append (']');
return sb.ToString ();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace Microsoft.Macios.Generator.DataModel;

class EventEqualityComparer : IEqualityComparer<ImmutableArray<Event>> {

public bool Equals (ImmutableArray<Event> x, ImmutableArray<Event> y)
{
// properties are unique by their name, that means that we can build two dicts and comparethem
var xDictionary = Enumerable.ToDictionary (x, property => property.Name);
var yDictionary = Enumerable.ToDictionary (y, property => property.Name);

var comparer = new DictionaryComparer<string, Event> ();
return comparer.Equals (xDictionary, yDictionary);
}

public int GetHashCode (ImmutableArray<Event> obj)
{
var hash = new HashCode ();
foreach (var property in obj) {
hash.Add (property);
}
return hash.ToHashCode ();
}
}
18 changes: 9 additions & 9 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,30 @@ namespace Microsoft.Macios.Generator.DataModel;
/// <summary>
/// Name of the property.
/// </summary>
public string Name { get; }
public string Name { get; } = string.Empty;

/// <summary>
/// String representation of the property type.
/// </summary>
public string Type { get; }
public string Type { get; } = string.Empty;

/// <summary>
/// Get the attributes added to the member.
/// </summary>
public ImmutableArray<AttributeCodeChange> Attributes { get; }
public ImmutableArray<AttributeCodeChange> Attributes { get; } = [];

/// <summary>
/// Get the modifiers of the property.
/// </summary>
public ImmutableArray<SyntaxToken> Modifiers { get; }
public ImmutableArray<SyntaxToken> Modifiers { get; } = [];

/// <summary>
/// Get the list of accessor changes of the property.
/// </summary>
public ImmutableArray<PropertyAccessor> Accessors { get; } = [];
public ImmutableArray<Accessor> Accessors { get; } = [];

internal Property (string name, string type, ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers, ImmutableArray<PropertyAccessor> accessors)
ImmutableArray<SyntaxToken> modifiers, ImmutableArray<Accessor> accessors)
{
Name = name;
Type = type;
Expand All @@ -64,7 +64,7 @@ public bool Equals (Property other)
if (!modifiersComparer.Equals (Modifiers, other.Modifiers))
return false;

var accessorComparer = new PropertyAccessorsEqualityComparer ();
var accessorComparer = new AccessorsEqualityComparer ();
return accessorComparer.Equals (Accessors, other.Accessors);
}

Expand Down Expand Up @@ -102,10 +102,10 @@ public static bool TryCreate (PropertyDeclarationSyntax declaration, SemanticMod

var type = propertySymbol.Type.ToDisplayString ().Trim ();
var attributes = declaration.GetAttributeCodeChanges (semanticModel);
ImmutableArray<PropertyAccessor> accessorCodeChanges = [];
ImmutableArray<Accessor> accessorCodeChanges = [];
if (declaration.AccessorList is not null && declaration.AccessorList.Accessors.Count > 0) {
// calculate any possible changes in the accessors of the property
var accessorsBucket = ImmutableArray.CreateBuilder<PropertyAccessor> ();
var accessorsBucket = ImmutableArray.CreateBuilder<Accessor> ();
foreach (var accessor in declaration.AccessorList.Accessors) {
var kind = accessor.Kind ().ToAccessorKind ();
var accessorAttributeChanges = accessor.GetAttributeCodeChanges (semanticModel);
Expand Down
Loading

6 comments on commit d8fba3b

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.