Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rgen] Add extra data about the return type of a method. #21901

Merged
merged 7 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace Microsoft.Macios.Generator.DataModel;
/// <summary>
/// Method return type.
/// </summary>
public string ReturnType { get; }
public MethodReturnType ReturnType { get; }

/// <summary>
/// The platform availability of the method.
Expand All @@ -54,7 +54,7 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
public ImmutableArray<Parameter> Parameters { get; } = [];

public Method (string type, string name, string returnType,
public Method (string type, string name, MethodReturnType returnType,
SymbolAvailability symbolAvailability,
ExportData<ObjCBindings.Method> exportMethodData,
ImmutableArray<AttributeCodeChange> attributes,
Expand Down Expand Up @@ -97,7 +97,7 @@ public static bool TryCreate (MethodDeclarationSyntax declaration, SemanticModel
change = new (
type: method.ContainingSymbol.ToDisplayString ().Trim (), // we want the full name
name: method.Name,
returnType: method.ReturnType.ToDisplayString ().Trim (),
returnType: new (method.ReturnType),
symbolAvailability: method.GetSupportedPlatforms (),
exportMethodData: exportData,
attributes: attributes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Microsoft.Macios.Generator.DataModel;

class MethodComparer : IComparer<Method> {

/// <inheritdoc/>
public int Compare (Method x, Method y)
{
var typeComparison = String.Compare (x.Type, y.Type, StringComparison.Ordinal);
Expand All @@ -14,7 +15,8 @@ public int Compare (Method x, Method y)
var nameComparison = String.Compare (x.Name, y.Name, StringComparison.Ordinal);
if (nameComparison != 0)
return nameComparison;
var returnTypeComparison = String.Compare (x.ReturnType, y.ReturnType, StringComparison.Ordinal);
var returnTypeComparer = new MethodReturnTypeComparer ();
var returnTypeComparison = returnTypeComparer.Compare (x.ReturnType, y.ReturnType);
if (returnTypeComparison != 0)
return returnTypeComparison;
var modifiersLengthCompare = x.Modifiers.Length.CompareTo (y.Modifiers.Length);
Expand Down
133 changes: 133 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/MethodReturnType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs copyright notice

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Extensions;

namespace Microsoft.Macios.Generator.DataModel;

/// <summary>
/// Readonly structure that represents a change in a method return type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what is meant by "a change in"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md

We get an event every time we get a code change. We calculate the data model and use that model to represent a code change. Use a comparer to invalidate the cache and move to generate if needed.

In this case, this is the data model to represent a change in the method return type.

/// </summary>
readonly struct MethodReturnType : IEquatable<MethodReturnType> {

/// <summary>
/// Type of the parameter.
/// </summary>
public string Type { get; }

/// <summary>
/// True if the parameter is nullable.:w
mandel-macaque marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public bool IsNullable { get; }

/// <summary>
/// True if the parameter type is blittable.
/// </summary>
public bool IsBlittable { get; }

/// <summary>
/// Returns if the return type is a smart enum.
/// </summary>
public bool IsSmartEnum { get; }

/// <summary>
/// Returns if the return type is an array type.
/// </summary>
public bool IsArray { get; }

/// <summary>
/// Returns if the return type is a reference type.
/// </summary>
public bool IsReferenceType { get; }

/// <summary>
/// Returns if the return type is void.
/// </summary>
public bool IsVoid { get; }

internal MethodReturnType (string type)
{
Type = type;
IsVoid = type == "void";
}

internal MethodReturnType (string type, bool isNullable, bool isBlittable, bool isSmartEnum, bool isArray,
bool isReferenceType) : this (type)
{
IsNullable = isNullable;
IsBlittable = isBlittable;
IsSmartEnum = isSmartEnum;
IsArray = isArray;
IsReferenceType = isReferenceType;
}

internal MethodReturnType (ITypeSymbol symbol) :
this (
symbol is IArrayTypeSymbol arrayTypeSymbol
? arrayTypeSymbol.ElementType.ToDisplayString ()
: symbol.ToDisplayString ().Trim ('?', '[', ']'))
{
IsNullable = symbol.NullableAnnotation == NullableAnnotation.Annotated;
IsBlittable = symbol.IsBlittable ();
IsSmartEnum = symbol.IsSmartEnum ();
IsArray = symbol is IArrayTypeSymbol;
IsReferenceType = symbol.IsReferenceType;
}

/// <inheritdoc/>
public bool Equals (MethodReturnType other)
{
if (Type != other.Type)
return false;
if (IsNullable != other.IsNullable)
return false;
if (IsBlittable != other.IsBlittable)
return false;
if (IsSmartEnum != other.IsSmartEnum)
return false;
if (IsArray != other.IsArray)
return false;
if (IsReferenceType != other.IsReferenceType)
return false;
if (IsVoid != other.IsVoid)
return false;

return true;
}

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

/// <inheritdoc/>
public override int GetHashCode ()
{
return HashCode.Combine (Type, IsNullable, IsBlittable, IsSmartEnum, IsArray, IsReferenceType, IsVoid);
}

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

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

/// <inheritdoc/>
public override string ToString ()
{
var sb = new StringBuilder ("{");
sb.Append ($"Type: {Type}, ");
sb.Append ($"IsNullable: {IsNullable}, ");
sb.Append ($"IsBlittable: {IsBlittable}, ");
sb.Append ($"IsSmartEnum: {IsSmartEnum}, ");
sb.Append ($"IsArray: {IsArray}, ");
sb.Append ($"IsReferenceType: {IsReferenceType}, ");
sb.Append ($"IsVoid : {IsVoid} }}");
return sb.ToString ();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs copyright notice

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using System.Collections.Generic;

namespace Microsoft.Macios.Generator.DataModel;

class MethodReturnTypeComparer : IComparer<MethodReturnType> {

/// <inheritdoc/>
public int Compare (MethodReturnType x, MethodReturnType y)
{
var returnTypeComparison = String.Compare (x.Type, y.Type, StringComparison.Ordinal);
if (returnTypeComparison != 0)
return returnTypeComparison;
var isNullableComparison = x.IsNullable.CompareTo (y.IsNullable);
if (isNullableComparison != 0)
return isNullableComparison;
var isBlittableComparison = x.IsBlittable.CompareTo (y.IsBlittable);
if (isBlittableComparison != 0)
return isBlittableComparison;
var isSmartEnumComparison = x.IsSmartEnum.CompareTo (y.IsSmartEnum);
if (isSmartEnumComparison != 0)
return isSmartEnumComparison;
var isArrayComparison = x.IsArray.CompareTo (y.IsArray);
if (isArrayComparison != 0)
return isArrayComparison;
var isReferenceTypeComparison = x.IsReferenceType.CompareTo (y.IsReferenceType);
if (isReferenceTypeComparison != 0)
return isReferenceTypeComparison;
return x.IsVoid.CompareTo (y.IsVoid);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public override bool Equals (ImmutableArray<Method> x, ImmutableArray<Method> y)
// create the dictionary comparer that will do the based comparison and relay on a list comparer for the
// diff methods
var dictionaryComparer =
new DictionaryComparer<(string ReturnType, string Name, int ParameterCount), List<Method>> (
new DictionaryComparer<(MethodReturnType ReturnType, string Name, int ParameterCount), List<Method>> (
new CollectionComparer<Method> (new MethodComparer ()));
return dictionaryComparer.Equals (xMethods, yMethods);
}
Expand Down
1 change: 1 addition & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Parameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public override bool Equals (object? obj)
return obj is Parameter other && Equals (other);
}

/// <inheritdoc/>
public override int GetHashCode ()
{
var hashCode = new HashCode ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ public static BindingTypeData<T> GetBindingData<T> (this ISymbol symbol) where T
/// <seealso cref="https://learn.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types"/>
public static bool IsBlittable (this ITypeSymbol symbol)
{
if (symbol.NullableAnnotation == NullableAnnotation.Annotated)
return false;

while (true) {
// per the documentation, the following system types are blittable
switch (symbol.SpecialType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@
namespace Microsoft.Macios.Generator.Formatters;

static class MethodFormatter {

static TypeSyntax GetIdentifierSyntax (this in MethodReturnType returnType)
{
if (returnType.IsArray) {
// could be a params array or simply an array
var arrayType = ArrayType (IdentifierName (returnType.Type))
.WithRankSpecifiers (SingletonList (
ArrayRankSpecifier (
SingletonSeparatedList<ExpressionSyntax> (OmittedArraySizeExpression ()))));
return returnType.IsNullable
? NullableType (arrayType)
: arrayType;
}

// dealing with a non-array type
return returnType.IsNullable
? NullableType (IdentifierName (returnType.Type))
: IdentifierName (returnType.Type);
}

public static CompilationUnitSyntax? ToDeclaration (this in Method? method)
{
if (method is null)
Expand All @@ -13,7 +33,7 @@ static class MethodFormatter {
.WithMembers (
SingletonList<MemberDeclarationSyntax> (
MethodDeclaration (
returnType: IdentifierName (method.Value.ReturnType),
returnType: method.Value.ReturnType.GetIdentifierSyntax (),
identifier: Identifier (method.Value.Name)
.WithLeadingTrivia (Space)
.WithTrailingTrivia (Space)) // adding the spaces manually to follow the mono style
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ public partial class MyClass {
new (
type: "NS.MyClass",
name: "SetName",
returnType: "void",
returnType: new ("void"),
symbolAvailability: new (),
exportMethodData: new ("withName:"),
attributes: [
Expand Down Expand Up @@ -838,7 +838,7 @@ public void SetSurname (string inSurname) {}
new (
type: "NS.MyClass",
name: "SetName",
returnType: "void",
returnType: new ("void"),
symbolAvailability: new (),
exportMethodData: new ("withName:"),
attributes: [
Expand Down Expand Up @@ -894,7 +894,7 @@ public partial class MyClass {
new (
type: "NS.MyClass",
name: "SetName",
returnType: "void",
returnType: new ("void"),
symbolAvailability: new (),
exportMethodData: new ("withName:"),
attributes: [
Expand All @@ -911,7 +911,7 @@ public partial class MyClass {
new (
type: "NS.MyClass",
name: "SetSurname",
returnType: "void",
returnType: new ("void"),
symbolAvailability: new (),
exportMethodData: new ("withSurname:"),
attributes: [
Expand Down
Loading
Loading