Skip to content

Commit

Permalink
[Binding SG] Refactor data models (#24462)
Browse files Browse the repository at this point in the history
* Extracted PathPart into separate file

* Changed BindingSGUtilities to extension methods

* Split GeneratorDataModels into meaningful parts
  • Loading branch information
jkurdek authored Aug 28, 2024
1 parent add674e commit 2828b05
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 223 deletions.
53 changes: 53 additions & 0 deletions src/Controls/src/BindingSourceGen/BindingInvocationDescription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.Maui.Controls.BindingSourceGen;

public sealed record BindingInvocationDescription(
InterceptorLocation Location,
TypeDescription SourceType,
TypeDescription PropertyType,
EquatableArray<IPathPart> Path,
SetterOptions SetterOptions,
bool NullableContextEnabled,
InterceptedMethodType MethodType);

public sealed record SourceCodeLocation(string FilePath, TextSpan TextSpan, LinePositionSpan LineSpan)
{
public static SourceCodeLocation? CreateFrom(Location location)
=> location.SourceTree is null
? null
: new SourceCodeLocation(location.SourceTree.FilePath, location.SourceSpan, location.GetLineSpan().Span);

public Location ToLocation()
{
return Location.Create(FilePath, TextSpan, LineSpan);
}

public InterceptorLocation ToInterceptorLocation()
{
return new InterceptorLocation(FilePath, LineSpan.Start.Line + 1, LineSpan.Start.Character + 1);
}
}

public sealed record InterceptorLocation(string FilePath, int Line, int Column);

public sealed record TypeDescription(
string GlobalName,
bool IsValueType = false,
bool IsNullable = false,
bool IsGenericParameter = false)
{
public override string ToString()
=> IsNullable
? $"{GlobalName}?"
: GlobalName;
}

public enum InterceptedMethodType
{
SetBinding,
Create
}

public sealed record SetterOptions(bool IsWritable, bool AcceptsNullValue = false);
16 changes: 11 additions & 5 deletions src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

namespace Microsoft.Maui.Controls.BindingSourceGen;

public class TrackingNames
{
public const string BindingsWithDiagnostics = nameof(BindingsWithDiagnostics);
public const string Bindings = nameof(Bindings);
}

[Generator(LanguageNames.CSharp)]
public class BindingSourceGenerator : IIncrementalGenerator
{
Expand Down Expand Up @@ -124,7 +130,7 @@ private static Result<BindingInvocationDescription> GetBindingForGeneration(Gene
return Result<BindingInvocationDescription>.Failure(DiagnosticsFactory.LambdaResultCannotBeResolved(lambdaBodyResult.Value.GetLocation()));
}

if (!BindingGenerationUtilities.IsAccessible(lambdaParamType.DeclaredAccessibility))
if (!lambdaParamType.IsAccessible())
{
return Result<BindingInvocationDescription>.Failure(DiagnosticsFactory.UnaccessibleTypeUsedAsLambdaParameter(lambdaBodyResult.Value.GetLocation()));
}
Expand All @@ -138,8 +144,8 @@ private static Result<BindingInvocationDescription> GetBindingForGeneration(Gene

var binding = new BindingInvocationDescription(
Location: sourceCodeLocation.ToInterceptorLocation(),
SourceType: BindingGenerationUtilities.CreateTypeDescription(lambdaParamType, enabledNullable),
PropertyType: BindingGenerationUtilities.CreateTypeDescription(lambdaResultType, enabledNullable),
SourceType: lambdaParamType.CreateTypeDescription(enabledNullable),
PropertyType: lambdaResultType.CreateTypeDescription(enabledNullable),
Path: new EquatableArray<IPathPart>([.. pathParseResult.Value]),
SetterOptions: DeriveSetterOptions(lambdaBodyResult.Value, context.SemanticModel, enabledNullable),
NullableContextEnabled: enabledNullable,
Expand Down Expand Up @@ -325,8 +331,8 @@ static bool IsWritable(ISymbol? symbol)
static bool AcceptsNullValue(ISymbol? symbol, bool enabledNullable)
=> symbol switch
{
IPropertySymbol propertySymbol => BindingGenerationUtilities.IsTypeNullable(propertySymbol.Type, enabledNullable),
IFieldSymbol fieldSymbol => BindingGenerationUtilities.IsTypeNullable(fieldSymbol.Type, enabledNullable),
IPropertySymbol propertySymbol => propertySymbol.Type.IsTypeNullable(enabledNullable),
IFieldSymbol fieldSymbol => fieldSymbol.Type.IsTypeNullable(enabledNullable),
_ => false,
};
}
Expand Down

This file was deleted.

162 changes: 0 additions & 162 deletions src/Controls/src/BindingSourceGen/GeneratorDataModels.cs

This file was deleted.

70 changes: 70 additions & 0 deletions src/Controls/src/BindingSourceGen/ITypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Microsoft.CodeAnalysis;

namespace Microsoft.Maui.Controls.BindingSourceGen;

internal static class ITypeSymbolExtensions
{
internal static bool IsTypeNullable(this ITypeSymbol typeInfo, bool enabledNullable)
{
if (!enabledNullable && typeInfo.IsReferenceType)
{
return true;
}

return typeInfo.IsNullableValueType() || typeInfo.IsNullableReferenceType();
}

internal static TypeDescription CreateTypeDescription(this ITypeSymbol typeSymbol, bool enabledNullable)
{
var isNullable = IsTypeNullable(typeSymbol, enabledNullable);
return new TypeDescription(
GlobalName: GetGlobalName(typeSymbol, isNullable, typeSymbol.IsValueType),
IsNullable: isNullable,
IsGenericParameter: typeSymbol.Kind == SymbolKind.TypeParameter, //TODO: Add support for generic parameters
IsValueType: typeSymbol.IsValueType);
}

private static bool IsNullableValueType(this ITypeSymbol typeInfo) =>
typeInfo is INamedTypeSymbol namedTypeSymbol
&& namedTypeSymbol.IsGenericType
&& namedTypeSymbol.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T;

private static bool IsNullableReferenceType(this ITypeSymbol typeInfo) =>
typeInfo.IsReferenceType && typeInfo.NullableAnnotation == NullableAnnotation.Annotated;


private static string GetGlobalName(this ITypeSymbol typeSymbol, bool isNullable, bool isValueType)
{
if (isNullable && isValueType)
{
// Strips the "?" from the type name
return ((INamedTypeSymbol)typeSymbol).TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}

return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}
}

internal static class ISymbolExtensions
{
internal static bool IsAccessible(this ISymbol symbol) =>
symbol.DeclaredAccessibility == Accessibility.Public
|| symbol.DeclaredAccessibility == Accessibility.Internal
|| symbol.DeclaredAccessibility == Accessibility.ProtectedOrInternal;

internal static AccessorKind ToAccessorKind(this ISymbol symbol)
{
return symbol switch
{
IFieldSymbol _ => AccessorKind.Field,
IPropertySymbol _ => AccessorKind.Property,
_ => throw new ArgumentException("Symbol is not a field or property.", nameof(symbol))
};
}
}

public enum AccessorKind
{
Field,
Property,
}
Loading

0 comments on commit 2828b05

Please sign in to comment.