Skip to content

Commit

Permalink
[Binding SG] Removed deprecated InterceptsLocationAttribute (#27145)
Browse files Browse the repository at this point in the history
* [Binding SG] Updated InterceptsLocationAttribute

* Added System.Diagnostics.Conditional attribute
  • Loading branch information
jkurdek authored Jan 24, 2025
1 parent 0737be9 commit 58f7227
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 256 deletions.
18 changes: 7 additions & 11 deletions src/Controls/src/BindingSourceGen/BindingCodeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,15 @@ namespace System.Runtime.CompilerServices
using System.CodeDom.Compiler;
{{GeneratedCodeAttribute}}
[global::System.Diagnostics.Conditional("DEBUG")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
public InterceptsLocationAttribute(int version, string data)
{
FilePath = filePath;
Line = line;
Column = column;
_ = version;
_ = data;
}
public string FilePath { get; }
public int Line { get; }
public int Column { get; }
}
}
Expand Down Expand Up @@ -177,7 +173,7 @@ public BindingInterceptorCodeBuilder(int indent = 0)
public void AppendSetBindingInterceptor(uint id, BindingInvocationDescription binding)
{
AppendLine(GeneratedCodeAttribute);
AppendInterceptorAttribute(binding.Location);
AppendInterceptorAttribute(binding.InterceptableLocation);
AppendMethodName(binding, id);
if (binding.SourceType.IsGenericParameter && binding.PropertyType.IsGenericParameter)
{
Expand Down Expand Up @@ -310,9 +306,9 @@ private void AppendMethodName(BindingInvocationDescription binding, uint id)
});
}

private void AppendInterceptorAttribute(InterceptorLocation location)
private void AppendInterceptorAttribute(InterceptableLocationRecord location)
{
AppendLine($"[InterceptsLocationAttribute(@\"{location.FilePath}\", {location.Line}, {location.Column})]");
AppendLine($"[InterceptsLocationAttribute({location.Version}, @\"{location.Data}\")]");
}

private void AppendSetterAction(BindingInvocationDescription binding, uint id, string sourceVariableName = "source", string valueVariableName = "value")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
namespace Microsoft.Maui.Controls.BindingSourceGen;

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


public sealed record InterceptableLocationRecord(int Version, string Data);

public sealed record SourceCodeLocation(string FilePath, TextSpan TextSpan, LinePositionSpan LineSpan)
{
public static SourceCodeLocation? CreateFrom(Location location)
Expand All @@ -24,13 +28,13 @@ public Location ToLocation()
return Location.Create(FilePath, TextSpan, LineSpan);
}

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

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

public sealed record TypeDescription(
string GlobalName,
Expand Down
16 changes: 12 additions & 4 deletions src/Controls/src/BindingSourceGen/BindingSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

context.RegisterImplementationSourceOutput(bindings, (spc, binding) =>
{
var fileName = $"{binding.Location.FilePath}-GeneratedBindingInterceptors-{binding.Location.Line}-{binding.Location.Column}.g.cs";
var location = binding.SimpleLocation;
var fileName = $"{location.FilePath}-GeneratedBindingInterceptors-{location.Line}-{location.Column}.g.cs";
var sanitizedFileName = fileName.Replace('/', '-').Replace('\\', '-').Replace(':', '-');
var code = BindingCodeWriter.GenerateBinding(binding, (uint)Math.Abs(binding.Location.GetHashCode()));
var code = BindingCodeWriter.GenerateBinding(binding, (uint)Math.Abs(location.GetHashCode()));
spc.AddSource(sanitizedFileName, code);
});
}
Expand Down Expand Up @@ -83,8 +84,14 @@ private static Result<BindingInvocationDescription> GetBindingForGeneration(Gene
return Result<BindingInvocationDescription>.Failure(interceptedMethodTypeResult.Diagnostics);
}

#pragma warning disable RSEXPERIMENTAL002
var interceptableLocation = context.SemanticModel.GetInterceptableLocation(invocation, t);
#pragma warning restore RSEXPERIMENTAL002

var sourceCodeLocation = SourceCodeLocation.CreateFrom(method.Name.GetLocation());
if (sourceCodeLocation == null)


if (interceptableLocation == null || sourceCodeLocation == null)
{
return Result<BindingInvocationDescription>.Failure(DiagnosticsFactory.UnableToResolvePath(invocation.GetLocation()));
}
Expand Down Expand Up @@ -115,7 +122,8 @@ private static Result<BindingInvocationDescription> GetBindingForGeneration(Gene
}

var binding = new BindingInvocationDescription(
Location: sourceCodeLocation.ToInterceptorLocation(),
InterceptableLocation: new InterceptableLocationRecord(interceptableLocation.Version, interceptableLocation.Data),
SimpleLocation: sourceCodeLocation.ToSimpleLocation(),
SourceType: lambdaParamTypeResult.Value.CreateTypeDescription(enabledNullable),
PropertyType: lambdaReturnTypeResult.Value.CreateTypeDescription(enabledNullable),
Path: new EquatableArray<IPathPart>([.. pathParseResult.Value]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>

Expand All @@ -29,4 +29,4 @@
</ItemGroup>
<Copy SourceFiles="@(_CopyItems)" DestinationFolder="$(_MauiBuildTasksLocation)" ContinueOnError="true" Retries="0" />
</Target>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ internal static void BindingsAreEqual(BindingInvocationDescription expectedBindi
AssertNoDiagnostics(codeGeneratorResult);
Assert.NotNull(codeGeneratorResult.Binding);

//TODO: Change arrays to custom collections implementing IEquatable
// Skip interceptable location
Assert.Equal(expectedBinding.SimpleLocation, codeGeneratorResult.Binding.SimpleLocation);
Assert.Equal(expectedBinding.SourceType, codeGeneratorResult.Binding.SourceType);
Assert.Equal(expectedBinding.PropertyType, codeGeneratorResult.Binding.PropertyType);
Assert.Equal(expectedBinding.Path, codeGeneratorResult.Binding.Path);
Assert.Equal(expectedBinding, codeGeneratorResult.Binding);
Assert.Equal(expectedBinding.SetterOptions, codeGeneratorResult.Binding.SetterOptions);
Assert.Equal(expectedBinding.NullableContextEnabled, codeGeneratorResult.Binding.NullableContextEnabled);
Assert.Equal(expectedBinding.MethodType, codeGeneratorResult.Binding.MethodType);

}

private static IEnumerable<string> SplitCode(string code)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ private static bool ShouldUseSetter(BindingMode mode)
public void BuildsWholeBinding()
{
var code = BindingCodeWriter.GenerateBinding(new BindingInvocationDescription(
Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
InterceptableLocation: new InterceptableLocationRecord(Version: 1, Data: "serializedData"),
SimpleLocation: new SimpleLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
Path: new EquatableArray<IPathPart>([
Expand Down Expand Up @@ -80,19 +81,15 @@ namespace System.Runtime.CompilerServices
using System.CodeDom.Compiler;
{{BindingCodeWriter.GeneratedCodeAttribute}}
[global::System.Diagnostics.Conditional("DEBUG")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
public InterceptsLocationAttribute(int version, string data)
{
FilePath = filePath;
Line = line;
Column = column;
_ = version;
_ = data;
}
public string FilePath { get; }
public int Line { get; }
public int Column { get; }
}
}
Expand All @@ -107,7 +104,7 @@ internal static partial class GeneratedBindingInterceptors
{
{{BindingCodeWriter.GeneratedCodeAttribute}}
[InterceptsLocationAttribute(@"Path\To\Program.cs", 20, 30)]
[InterceptsLocationAttribute(1, @"serializedData")]
public static void SetBinding1(
this BindableObject bindableObject,
BindableProperty bindableProperty,
Expand Down Expand Up @@ -164,8 +161,8 @@ public void CorrectlyFormatsSimpleBinding()
{
var codeBuilder = new BindingCodeWriter.BindingInterceptorCodeBuilder();
codeBuilder.AppendSetBindingInterceptor(id: 1, new BindingInvocationDescription(
Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
InterceptableLocation: new InterceptableLocationRecord(Version: 1, Data: "serializedData"),
SimpleLocation: new SimpleLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
Path: new EquatableArray<IPathPart>([
new MemberAccess("A"),
Expand All @@ -180,7 +177,7 @@ public void CorrectlyFormatsSimpleBinding()
AssertExtensions.CodeIsEqual(
$$"""
{{BindingCodeWriter.GeneratedCodeAttribute}}
[InterceptsLocationAttribute(@"Path\To\Program.cs", 20, 30)]
[InterceptsLocationAttribute(1, @"serializedData")]
public static void SetBinding1(
this BindableObject bindableObject,
BindableProperty bindableProperty,
Expand Down Expand Up @@ -236,8 +233,8 @@ public void CorrectlyFormatsBindingWithoutAnyNullablesInPath()
{
var codeBuilder = new BindingCodeWriter.BindingInterceptorCodeBuilder();
codeBuilder.AppendSetBindingInterceptor(id: 1, new BindingInvocationDescription(
Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
InterceptableLocation: new InterceptableLocationRecord(Version: 1, Data: "serializedData"),
SimpleLocation: new SimpleLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsValueType: false, IsNullable: false, IsGenericParameter: false),
Path: new EquatableArray<IPathPart>([
new MemberAccess("A"),
Expand All @@ -252,7 +249,7 @@ public void CorrectlyFormatsBindingWithoutAnyNullablesInPath()
AssertExtensions.CodeIsEqual(
$$"""
{{BindingCodeWriter.GeneratedCodeAttribute}}
[InterceptsLocationAttribute(@"Path\To\Program.cs", 20, 30)]
[InterceptsLocationAttribute(1, @"serializedData")]
public static void SetBinding1(
this BindableObject bindableObject,
BindableProperty bindableProperty,
Expand Down Expand Up @@ -304,8 +301,8 @@ public void CorrectlyFormatsBindingWithoutSetter()
{
var codeBuilder = new BindingCodeWriter.BindingInterceptorCodeBuilder();
codeBuilder.AppendSetBindingInterceptor(id: 1, new BindingInvocationDescription(
Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsNullable: false, IsGenericParameter: false, IsValueType: false),
InterceptableLocation: new InterceptableLocationRecord(Version: 1, Data: "serializedData"),
SimpleLocation: new SimpleLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsNullable: false, IsGenericParameter: false, IsValueType: false),
PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsNullable: false, IsGenericParameter: false, IsValueType: false),
Path: new EquatableArray<IPathPart>([
new MemberAccess("A"),
Expand All @@ -320,7 +317,7 @@ public void CorrectlyFormatsBindingWithoutSetter()
AssertExtensions.CodeIsEqual(
$$"""
{{BindingCodeWriter.GeneratedCodeAttribute}}
[InterceptsLocationAttribute(@"Path\To\Program.cs", 20, 30)]
[InterceptsLocationAttribute(1, @"serializedData")]
public static void SetBinding1(
this BindableObject bindableObject,
BindableProperty bindableProperty,
Expand Down Expand Up @@ -369,8 +366,8 @@ public void CorrectlyFormatsBindingWithIndexers()
{
var codeBuilder = new BindingCodeWriter.BindingInterceptorCodeBuilder();
codeBuilder.AppendSetBindingInterceptor(id: 1, new BindingInvocationDescription(
Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsNullable: false, IsGenericParameter: false),
InterceptableLocation: new InterceptableLocationRecord(Version: 1, Data: "serializedData"),
SimpleLocation: new SimpleLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsNullable: false, IsGenericParameter: false),
PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsNullable: true, IsGenericParameter: false),
Path: new EquatableArray<IPathPart>([
new IndexAccess("Item", 12),
Expand All @@ -385,7 +382,7 @@ public void CorrectlyFormatsBindingWithIndexers()
AssertExtensions.CodeIsEqual(
$$"""
{{BindingCodeWriter.GeneratedCodeAttribute}}
[InterceptsLocationAttribute(@"Path\To\Program.cs", 20, 30)]
[InterceptsLocationAttribute(1, @"serializedData")]
public static void SetBinding1(
this BindableObject bindableObject,
BindableProperty bindableProperty,
Expand Down Expand Up @@ -448,8 +445,8 @@ public void CorrectlyFormatsBindingWithCasts()
{
var codeBuilder = new BindingCodeWriter.BindingInterceptorCodeBuilder();
codeBuilder.AppendSetBindingInterceptor(id: 1, new BindingInvocationDescription(
Location: new InterceptorLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30),
SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsNullable: false, IsGenericParameter: false),
InterceptableLocation: new InterceptableLocationRecord(Version: 1, Data: "serializedData"),
SimpleLocation: new SimpleLocation(FilePath: @"Path\To\Program.cs", Line: 20, Column: 30), SourceType: new TypeDescription("global::MyNamespace.MySourceClass", IsNullable: false, IsGenericParameter: false),
PropertyType: new TypeDescription("global::MyNamespace.MyPropertyClass", IsNullable: false, IsGenericParameter: false),
Path: new EquatableArray<IPathPart>([
new MemberAccess("A"),
Expand All @@ -469,7 +466,7 @@ public void CorrectlyFormatsBindingWithCasts()
AssertExtensions.CodeIsEqual(
$$"""
{{BindingCodeWriter.GeneratedCodeAttribute}}
[InterceptsLocationAttribute(@"Path\To\Program.cs", 20, 30)]
[InterceptsLocationAttribute(1, @"serializedData")]
public static void SetBinding1(
this BindableObject bindableObject,
BindableProperty bindableProperty,
Expand Down
Loading

0 comments on commit 58f7227

Please sign in to comment.