Skip to content

Commit 81ecd0e

Browse files
authored
Merge pull request #171 from FmgLib/feature/net10.0
Feature/net10.0
2 parents 3802db0 + 4ac0f80 commit 81ecd0e

25 files changed

+915
-378
lines changed

src/FmgLib.MauiMarkup.Generator/Extensions/ExtensionGenerator.BindingBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void GenerateExtensionMethod_BindablePropertyBuilder_Sealed(AttachedFieldInfo in
4949
builder.Append($@"
5050
public static {info.DeclaringTypeName} {info.propertyName}(this {info.DeclaringTypeName} self, Func<PropertyContext<{info.ReturnTypeName}>, IPropertyBuilder<{info.ReturnTypeName}>> configure)
5151
{{
52-
var context = new PropertyContext<{info.propertyTypeName}>(self, {info.BindablePropertyName});
52+
var context = new PropertyContext<{info.ReturnTypeName}>(self, {info.BindablePropertyName});
5353
configure(context).Build();
5454
return self;
5555
}}
@@ -68,4 +68,4 @@ void GenerateExtensionMethod_BindablePropertyBuilder_Normal(AttachedFieldInfo in
6868
}}
6969
");
7070
}
71-
}
71+
}

src/FmgLib.MauiMarkup.Generator/Extensions/ExtensionGenerator.Events.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ public partial class ExtensionGenerator
99
void GenerateEventMethod(ISymbol @event)
1010
{
1111
var eventSymbol = (IEventSymbol)@event;
12-
var eventHandler = eventSymbol.AddMethod.Parameters.First();
13-
var eventHandlerType = ((INamedTypeSymbol)eventHandler.Type);
1412

1513
var existInBases = false;
14+
if (mainSymbol.BaseType is null)
15+
{
16+
return;
17+
}
18+
1619
Helpers.LoopDownToObject(mainSymbol.BaseType, type =>
1720
{
1821
existInBases = (type
@@ -67,7 +70,8 @@ void GenerateEventMethodHandler_Normal(IEventSymbol eventSymbol)
6770

6871
void GenerateEventMethodNoArgs_Sealed(IEventSymbol eventSymbol)
6972
{
70-
var parameterCount = ((INamedTypeSymbol)eventSymbol.Type).DelegateInvokeMethod.Parameters.Length;
73+
var invokeMethod = ((INamedTypeSymbol)eventSymbol.Type).DelegateInvokeMethod;
74+
var parameterCount = invokeMethod?.Parameters.Length ?? 0;
7175
if (parameterCount <= 2)
7276
builder.Append($@"
7377
public static {mainSymbol.ToDisplayString()} On{eventSymbol.Name}(this {mainSymbol.ToDisplayString()} self, System.Action<{mainSymbol.ToDisplayString()}> action)
@@ -80,7 +84,8 @@ void GenerateEventMethodNoArgs_Sealed(IEventSymbol eventSymbol)
8084

8185
void GenerateEventMethodNoArgs_Normal(IEventSymbol eventSymbol)
8286
{
83-
var parameterCount = ((INamedTypeSymbol)eventSymbol.Type).DelegateInvokeMethod.Parameters.Length;
87+
var invokeMethod = ((INamedTypeSymbol)eventSymbol.Type).DelegateInvokeMethod;
88+
var parameterCount = invokeMethod?.Parameters.Length ?? 0;
8489
if (parameterCount <= 2)
8590
builder.Append($@"
8691
public static T On{eventSymbol.Name}<T>(this T self, System.Action<T> action)
@@ -91,4 +96,4 @@ void GenerateEventMethodNoArgs_Normal(IEventSymbol eventSymbol)
9196
}}
9297
");
9398
}
94-
}
99+
}

src/FmgLib.MauiMarkup.Generator/Extensions/ExtensionGenerator.cs

Lines changed: 131 additions & 123 deletions
Large diffs are not rendered by default.

src/FmgLib.MauiMarkup.Generator/FmgLib.MauiMarkup.Generator.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
5-
<LangVersion>13.0</LangVersion>
5+
<LangVersion>14.0</LangVersion>
6+
<Nullable>enable</Nullable>
67
<BuildOutputTargetFolder>analyzers</BuildOutputTargetFolder>
78
<IsRoslynComponent>True</IsRoslynComponent>
89
<EnforceExtendedAnalyzerRules>True</EnforceExtendedAnalyzerRules>
@@ -21,7 +22,7 @@
2122

2223

2324
<ItemGroup>
24-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" />
25+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" PrivateAssets="all" />
2526
<PackageReference Include="PolySharp" Version="1.15.0" PrivateAssets="all" IncludeAssets="build; analyzers" />
2627
</ItemGroup>
2728

src/FmgLib.MauiMarkup.Generator/Helpers/AttachedFieldInfo.cs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,35 @@
22
using System;
33
using System.Linq;
44

5-
namespace FmgLib.MauiMarkup.Generator.Extensions
5+
namespace FmgLib.MauiMarkup.Generator.Extensions;
6+
7+
/// <summary>
8+
/// Stores attached property metadata required during code generation.
9+
/// </summary>
10+
public sealed class AttachedFieldInfo
611
{
7-
partial class AttachedFieldInfo
8-
{
9-
public INamedTypeSymbol MainSymbol { get; set; }
10-
public IFieldSymbol FiledSymbol { get; set; }
11-
public string BindablePropertyName { get; set; }
12-
public string PropertyName { get; set; }
13-
public string ReturnTypeName { get; set; }
14-
public string DeclaringTypeName { get; set; }
12+
public INamedTypeSymbol MainSymbol { get; set; } = null!;
13+
public IFieldSymbol FieldSymbol { get; set; } = null!;
14+
public string BindablePropertyName { get; set; } = null!;
15+
public string PropertyName { get; set; } = null!;
16+
public string ReturnTypeName { get; set; } = null!;
17+
public string DeclaringTypeName { get; set; } = null!;
1518

16-
public string propertyName;
17-
public string propertyTypeName;
18-
public string camelCaseName;
19-
public string symbolTypeName;
20-
public string valueAssignmentString;
21-
public string dataTemplateAssignmentString;
19+
public string propertyName = null!;
20+
public string propertyTypeName = null!;
21+
public string camelCaseName = null!;
22+
public string symbolTypeName = null!;
23+
public string valueAssignmentString = null!;
24+
public string dataTemplateAssignmentString = null!;
2225

23-
public void Build()
24-
{
25-
FiledSymbol = MainSymbol.GetMembers(PropertyName).OfType<IFieldSymbol>().FirstOrDefault();
26-
symbolTypeName = $"{MainSymbol.ToDisplayString()}";
27-
propertyName = BindablePropertyName.Split(new[] { "." }, StringSplitOptions.None)[^2] + PropertyName.Replace("Property", "");
28-
propertyTypeName = FiledSymbol.Type.ToDisplayString();
29-
camelCaseName = Helpers.ToCamelCase(propertyName);
30-
valueAssignmentString = $@"self.SetValue({BindablePropertyName}, {camelCaseName});";
31-
dataTemplateAssignmentString = $@"self.SetValue({BindablePropertyName}, new DataTemplate(loadTemplate));";
32-
}
26+
public void Build()
27+
{
28+
FieldSymbol = MainSymbol.GetMembers(PropertyName).OfType<IFieldSymbol>().FirstOrDefault();
29+
symbolTypeName = $"{MainSymbol.ToDisplayString()}";
30+
propertyName = BindablePropertyName.Split(new[] { "." }, StringSplitOptions.None)[^2] + PropertyName.Replace("Property", "");
31+
propertyTypeName = ReturnTypeName;
32+
camelCaseName = Helpers.ToCamelCase(propertyName);
33+
valueAssignmentString = $@"self.SetValue({BindablePropertyName}, {camelCaseName});";
34+
dataTemplateAssignmentString = $@"self.SetValue({BindablePropertyName}, new DataTemplate(loadTemplate));";
3335
}
3436
}

src/FmgLib.MauiMarkup.Generator/Helpers/AttachedModel.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
namespace FmgLib.MauiMarkup.Generator.Extensions;
44

5-
public class AttachedModel
5+
/// <summary>
6+
/// Represents the attached property metadata supplied through <c>MauiMarkupAttachedProp</c>.
7+
/// </summary>
8+
public sealed class AttachedModel
69
{
7-
public INamedTypeSymbol MainSymbol { get; set; }
8-
public IFieldSymbol FieldSymbol { get; set; }
9-
public string PropertyName { get; set; }
10-
public string ReturnTypeName { get; set; }
11-
public string DeclaringTypeName { get; set; }
10+
public INamedTypeSymbol MainSymbol { get; set; } = null!;
11+
public IFieldSymbol FieldSymbol { get; set; } = null!;
12+
public string PropertyName { get; set; } = null!;
13+
public string ReturnTypeName { get; set; } = null!;
14+
public string DeclaringTypeName { get; set; } = null!;
1215
}

src/FmgLib.MauiMarkup.Generator/Helpers/Helpers.cs

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66

77
namespace FmgLib.MauiMarkup;
88

9+
/// <summary>
10+
/// Shared helper utilities used by the source generator.
11+
/// </summary>
912
public static class Helpers
1013
{
11-
public static List<string> NotGenerateList = new() { "this[]", "Handler", "LogicalChildren" };
12-
14+
public static readonly HashSet<string> NotGenerateList = new(StringComparer.Ordinal) { "this[]", "Handler", "LogicalChildren" };
1315

1416
public static string ToCamelCase(this string text)
1517
{
1618
if (string.IsNullOrWhiteSpace(text))
1719
return text;
1820

19-
return char.ToLowerInvariant(text[0]) + text.Substring(1);
21+
return char.ToLowerInvariant(text[0]) + text[1..];
2022
}
2123

2224
public static INamedTypeSymbol? FindNamedType(this Compilation compilation, string typeMetadataName)
@@ -27,7 +29,7 @@ public static string ToCamelCase(this string text)
2729
.Select(compilation.GetAssemblyOrModuleSymbol)
2830
.OfType<IAssemblySymbol>()
2931
.Select(assemblySymbol => assemblySymbol.GetTypeByMetadataName(typeMetadataName))
30-
.FirstOrDefault(_ => _ != null);
32+
.FirstOrDefault(static symbol => symbol is not null);
3133

3234
return typeToMauiMarkup;
3335
}
@@ -38,85 +40,70 @@ public static string GetFullyQualifiedName(this ISymbol typeSymbol)
3840
}
3941

4042
public static T EnsureNotNull<T>(this T? value)
41-
=> value ?? throw new InvalidOperationException();
43+
=> value ?? throw new InvalidOperationException();
4244

43-
public static void LoopDownToObject(INamedTypeSymbol symbol, Func<INamedTypeSymbol, bool> func)
45+
public static bool IsVisualElement(INamedTypeSymbol symbol)
4446
{
45-
var type = symbol;
46-
var endLoop = false;
47-
while (!endLoop && type != null && !type.Name.Equals("Object", StringComparison.Ordinal))
48-
{
49-
endLoop = func(type);
50-
type = type.BaseType;
51-
}
47+
return IsDerivedFrom(symbol, "Microsoft.Maui.Controls.VisualElement");
5248
}
5349

54-
public static bool IsVisualElement(INamedTypeSymbol symbol)
50+
public static bool IsBindableObject(INamedTypeSymbol symbol)
5551
{
56-
var isNavigableElement = false;
52+
return IsDerivedFrom(symbol, "Microsoft.Maui.Controls.BindableObject");
53+
}
5754

58-
LoopDownToObject(symbol, type =>
55+
public static void LoopDownToObject(INamedTypeSymbol symbol, Func<INamedTypeSymbol, bool> func)
56+
{
57+
for (var type = symbol; type != null && type.SpecialType != SpecialType.System_Object; type = type.BaseType)
5958
{
60-
if (type.ToDisplayString().Equals("Microsoft.Maui.Controls.VisualElement")) isNavigableElement = true;
61-
return isNavigableElement;
62-
});
63-
64-
return isNavigableElement;
59+
if (func(type))
60+
{
61+
break;
62+
}
63+
}
6564
}
6665

6766
public static bool IsBaseImplementationOfInterface(INamedTypeSymbol symbol, string name)
6867
{
6968
var count = 0;
70-
LoopDownToObject(symbol, type =>
69+
for (var type = symbol; type != null && type.SpecialType != SpecialType.System_Object; type = type.BaseType)
7170
{
72-
if (type.Interfaces.Any(e => e.Name.Equals(name))) count++;
73-
return false;
74-
});
71+
if (type.Interfaces.Any(interfaceSymbol => interfaceSymbol.Name.Equals(name, StringComparison.Ordinal)))
72+
{
73+
count++;
74+
}
75+
}
7576

7677
return count == 1;
7778
}
7879

7980
public static string GetNormalizedFileName(INamedTypeSymbol type)
8081
{
81-
var tail = type.IsGenericType ? $".{type.TypeArguments.FirstOrDefault().Name}" : "";
82+
var tail = type.IsGenericType ? $".{type.TypeArguments.FirstOrDefault()?.Name}" : string.Empty;
8283
return $"{type.Name}{tail}";
8384
}
8485

8586
public static string GetNormalizedClassName(INamedTypeSymbol type)
8687
{
87-
var tail = type.IsGenericType ? $"Of{type.TypeArguments.FirstOrDefault().Name}" : "";
88-
var prefix = type.ToDisplayString().Contains(".Shapes.") ? "Shapes" : "";
89-
prefix += type.ToDisplayString().Contains(".Compatibility.") ? "Compatibility" : "";
88+
var tail = type.IsGenericType ? $"Of{type.TypeArguments.FirstOrDefault()?.Name}" : string.Empty;
89+
var fullName = type.ToDisplayString();
90+
var prefix = fullName.IndexOf(".Shapes.", StringComparison.Ordinal) >= 0 ? "Shapes" : string.Empty;
91+
prefix += fullName.IndexOf(".Compatibility.", StringComparison.Ordinal) >= 0 ? "Compatibility" : string.Empty;
9092
return $"{prefix}{type.Name}{tail}";
9193
}
9294

93-
public static bool IsBindableObject(INamedTypeSymbol symbol)
94-
{
95-
var isBindable = false;
96-
97-
LoopDownToObject(symbol, type =>
98-
{
99-
if (type.ToDisplayString().Equals("Microsoft.Maui.Controls.BindableObject", StringComparison.Ordinal)) isBindable = true;
100-
return isBindable;
101-
});
102-
103-
return isBindable;
104-
}
105-
10695
public static string? GetFullyQualifiedName(this ClassDeclarationSyntax classDeclarationSyntax)
10796
{
10897
if (!TryGetNamespace(classDeclarationSyntax, out string? namespaceName))
10998
{
110-
return null; // or whatever you want to do in this scenario
99+
return null;
111100
}
112101

113-
//var namespaceName = namespaceDeclarationSyntax!.Name.ToString();
114-
return namespaceName + "." + classDeclarationSyntax.Identifier.ToString();
102+
return namespaceName + "." + classDeclarationSyntax.Identifier;
115103
}
116104

117105
public static bool TryGetNamespace(SyntaxNode? syntaxNode, out string? result)
118106
{
119-
// set defaults
120107
result = null;
121108

122109
if (syntaxNode == null)
@@ -152,4 +139,17 @@ public static bool TryGetNamespace(SyntaxNode? syntaxNode, out string? result)
152139
return false;
153140
}
154141
}
142+
143+
static bool IsDerivedFrom(INamedTypeSymbol symbol, string fullyQualifiedMetadataName)
144+
{
145+
for (var type = symbol; type != null && type.SpecialType != SpecialType.System_Object; type = type.BaseType)
146+
{
147+
if (type.GetFullyQualifiedName().Equals(fullyQualifiedMetadataName, StringComparison.Ordinal))
148+
{
149+
return true;
150+
}
151+
}
152+
153+
return false;
154+
}
155155
}

src/FmgLib.MauiMarkup.Generator/Helpers/PropInfo.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,25 @@
55

66
namespace FmgLib.MauiMarkup;
77

8+
/// <summary>
9+
/// Describes property metadata needed to generate fluent extension methods.
10+
/// </summary>
811
public class PropInfo
912
{
10-
public string MainSymbolName { get; set; }
11-
public IPropertySymbol PropertySymbol { get; set; }
13+
public string MainSymbolName { get; set; } = null!;
14+
public IPropertySymbol PropertySymbol { get; set; } = null!;
1215
public bool IsBindableProperty { get; set; }
13-
public string BindablePropertyName { get; set; }
16+
public string BindablePropertyName { get; set; } = null!;
1417

15-
public string propertyName;
16-
public string methodName;
17-
public string propertyTypeName;
18-
public string accessedWith;
19-
public string camelCaseName;
20-
public string valueAssignmentString;
21-
public string dataTemplateAssignmentString;
18+
public string propertyName = null!;
19+
public string methodName = null!;
20+
public string propertyTypeName = null!;
21+
public string accessedWith = null!;
22+
public string camelCaseName = null!;
23+
public string valueAssignmentString = null!;
24+
public string dataTemplateAssignmentString = null!;
2225

23-
public void Build(List<string> redefinedProperties = null)
26+
public void Build(List<string>? redefinedProperties = null)
2427
{
2528
propertyName = PropertySymbol.Name.Split(new[] { "." }, StringSplitOptions.None).Last();
2629
propertyName = propertyName.Equals("class", StringComparison.Ordinal) ? "@class" : propertyName;
@@ -42,6 +45,6 @@ public void Build(List<string> redefinedProperties = null)
4245
$@"self.SetValue({BindablePropertyName}, new DataTemplate(loadTemplate));" :
4346
$@"{accessedWith}.{propertyName} = new DataTemplate(loadTemplate);";
4447

45-
methodName = redefinedProperties == null || redefinedProperties.Count <= 0 || !redefinedProperties.Any(e => e == propertyName) ? propertyName : propertyName + "New";
48+
methodName = redefinedProperties == null || redefinedProperties.Count == 0 || !redefinedProperties.Any(e => e == propertyName) ? propertyName : propertyName + "New";
4649
}
4750
}

0 commit comments

Comments
 (0)