Skip to content

Commit eb41e28

Browse files
committed
Add support for more modifiers, bug fixes
1 parent 9439f37 commit eb41e28

File tree

4 files changed

+55
-50
lines changed

4 files changed

+55
-50
lines changed

components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/DependencyPropertyGenerator.Execute.cs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Collections.Immutable;
67
using System.IO;
78
using System.Linq;
89
using System.Reflection;
@@ -147,6 +148,37 @@ public static bool IsCandidateSymbolValid(IPropertySymbol propertySymbol, bool u
147148
return true;
148149
}
149150

151+
/// <summary>
152+
/// Gathers all allowed property modifiers that should be forwarded to the generated property.
153+
/// </summary>
154+
/// <param name="node">The input <see cref="PropertyDeclarationSyntax"/> node.</param>
155+
/// <returns>The returned set of property modifiers, if any.</returns>
156+
public static ImmutableArray<SyntaxKind> GetPropertyModifiers(PropertyDeclarationSyntax node)
157+
{
158+
// We only allow a subset of all possible modifiers (aside from the accessibility modifiers)
159+
ReadOnlySpan<SyntaxKind> candidateKinds =
160+
[
161+
SyntaxKind.NewKeyword,
162+
SyntaxKind.VirtualKeyword,
163+
SyntaxKind.SealedKeyword,
164+
SyntaxKind.OverrideKeyword,
165+
SyntaxKind.RequiredKeyword
166+
];
167+
168+
using ImmutableArrayBuilder<SyntaxKind> builder = new();
169+
170+
// Track all modifiers from the allowed set on the input property declaration
171+
foreach (SyntaxKind kind in candidateKinds)
172+
{
173+
if (node.Modifiers.Any(kind))
174+
{
175+
builder.Add(kind);
176+
}
177+
}
178+
179+
return builder.ToImmutable();
180+
}
181+
150182
/// <summary>
151183
/// Tries to get the accessibility of the property and accessors, if possible.
152184
/// </summary>
@@ -331,16 +363,6 @@ public static bool IsSharedPropertyChangedCallbackImplemented(IPropertySymbol pr
331363
return false;
332364
}
333365

334-
/// <summary>
335-
/// Checks whether an input property is required.
336-
/// </summary>
337-
/// <param name="propertySymbol">The input <see cref="IPropertySymbol"/> instance to process.</param>
338-
/// <returns>Whether <paramref name="propertySymbol"/> is required.</returns>
339-
public static bool IsRequiredProperty(IPropertySymbol propertySymbol)
340-
{
341-
return propertySymbol.IsRequired;
342-
}
343-
344366
/// <summary>
345367
/// Writes all implementations of partial dependency property declarations.
346368
/// </summary>
@@ -367,7 +389,7 @@ static string GetOldValueTypeNameAsNullable(DependencyPropertyInfo propertyInfo)
367389
// Helper to get the accessibility with a trailing space
368390
static string GetExpressionWithTrailingSpace(Accessibility accessibility)
369391
{
370-
return accessibility.GetExpression() switch
392+
return SyntaxFacts.GetText(accessibility) switch
371393
{
372394
{ Length: > 0 } expression => expression + " ",
373395
_ => ""
@@ -428,11 +450,20 @@ static string GetExpressionWithTrailingSpace(Accessibility accessibility)
428450
{
429451
string oldValueTypeNameAsNullable = GetOldValueTypeNameAsNullable(propertyInfo);
430452

453+
// Declare the property
431454
writer.WriteLine(skipIfPresent: true);
432455
writer.WriteLine("/// <inheritdoc/>");
433456
writer.WriteGeneratedAttributes(GeneratorName);
434457
writer.Write(GetExpressionWithTrailingSpace(propertyInfo.DeclaredAccessibility));
435-
writer.WriteIf(propertyInfo.IsRequired, "required ");
458+
459+
// Add all gathered modifiers
460+
foreach (SyntaxKind modifier in propertyInfo.PropertyModifiers.AsImmutableArray().AsSyntaxKindArray())
461+
{
462+
writer.Write($"{SyntaxFacts.GetText(modifier)} ");
463+
}
464+
465+
// The 'partial' modifier always goes last, right before the property type and the property name.
466+
// We will never have the 'partial' modifier in the set of property modifiers processed above.
436467
writer.WriteLine($"partial {propertyInfo.TypeNameWithNullabilityAnnotations} {propertyInfo.PropertyName}");
437468

438469
using (writer.WriteBlock())
@@ -653,7 +684,7 @@ static string GetExpressionWithTrailingSpace(Accessibility accessibility)
653684
/// <remarks>This method is invoked by the <see cref="global::{WellKnownTypeNames.DependencyProperty(propertyInfo.UseWindowsUIXaml)}"/> infrastructure, after the value of <see cref="{propertyInfo.PropertyName}"/> is changed.</remarks>
654685
""", isMultiline: true);
655686
writer.WriteGeneratedAttributes(GeneratorName, includeNonUserCodeAttributes: false);
656-
writer.WriteLine($"partial void On{propertyInfo.PropertyName}PropertyChanged(global::{WellKnownTypeNames.DependencyPropertyChangedEventArgs} e);");
687+
writer.WriteLine($"partial void On{propertyInfo.PropertyName}PropertyChanged(global::{WellKnownTypeNames.DependencyPropertyChangedEventArgs(propertyInfo.UseWindowsUIXaml)} e);");
657688
}
658689

659690
// OnPropertyChanged, for the shared property metadata callback
@@ -664,7 +695,7 @@ static string GetExpressionWithTrailingSpace(Accessibility accessibility)
664695
/// <remarks>This method is invoked by the <see cref="global::{WellKnownTypeNames.DependencyProperty(propertyInfos[0].UseWindowsUIXaml)}"/> infrastructure, after the value of any dependency property has just changed.</remarks>
665696
""", isMultiline: true);
666697
writer.WriteGeneratedAttributes(GeneratorName, includeNonUserCodeAttributes: false);
667-
writer.WriteLine($"partial void OnPropertyChanged(global::{WellKnownTypeNames.DependencyPropertyChangedEventArgs} e);");
698+
writer.WriteLine($"partial void OnPropertyChanged(global::{WellKnownTypeNames.DependencyPropertyChangedEventArgs(propertyInfos[0].UseWindowsUIXaml)} e);");
668699
}
669700

670701
/// <summary>

components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/DependencyPropertyGenerator.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Collections.Immutable;
56
using CommunityToolkit.GeneratedDependencyProperty.Constants;
67
using CommunityToolkit.GeneratedDependencyProperty.Extensions;
78
using CommunityToolkit.GeneratedDependencyProperty.Helpers;
@@ -70,6 +71,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7071

7172
token.ThrowIfCancellationRequested();
7273

74+
// Get all additional modifiers for the property
75+
ImmutableArray<SyntaxKind> propertyModifiers = Execute.GetPropertyModifiers((PropertyDeclarationSyntax)context.TargetNode);
76+
77+
token.ThrowIfCancellationRequested();
78+
7379
// Get the accessibility values, if the property is valid
7480
if (!Execute.TryGetAccessibilityModifiers(
7581
node: (PropertyDeclarationSyntax)context.TargetNode,
@@ -88,7 +94,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8894

8995
token.ThrowIfCancellationRequested();
9096

91-
bool isRequired = Execute.IsRequiredProperty(propertySymbol);
9297
bool isPropertyChangedCallbackImplemented = Execute.IsPropertyChangedCallbackImplemented(propertySymbol, useWindowsUIXaml);
9398
bool isSharedPropertyChangedCallbackImplemented = Execute.IsSharedPropertyChangedCallbackImplemented(propertySymbol, useWindowsUIXaml);
9499
bool isNet8OrGreater = !context.SemanticModel.Compilation.IsWindowsRuntimeApplication();
@@ -124,14 +129,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
124129
return new DependencyPropertyInfo(
125130
Hierarchy: hierarchyInfo,
126131
PropertyName: propertySymbol.Name,
132+
PropertyModifiers: propertyModifiers.AsUnderlyingType(),
127133
DeclaredAccessibility: declaredAccessibility,
128134
GetterAccessibility: getterAccessibility,
129135
SetterAccessibility: setterAccessibility,
130136
TypeName: typeName,
131137
TypeNameWithNullabilityAnnotations: typeNameWithNullabilityAnnotations,
132138
DefaultValue: defaultValue,
133139
IsReferenceTypeOrUnconstraindTypeParameter: isReferenceTypeOrUnconstraindTypeParameter,
134-
IsRequired: isRequired,
135140
IsLocalCachingEnabled: isLocalCachingEnabled,
136141
IsPropertyChangedCallbackImplemented: isPropertyChangedCallbackImplemented,
137142
IsSharedPropertyChangedCallbackImplemented: isSharedPropertyChangedCallbackImplemented,

components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/Extensions/AccessibilityExtensions.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.

components/DependencyPropertyGenerator/CommunityToolkit.DependencyPropertyGenerator.SourceGenerators/Models/DependencyPropertyInfo.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using CommunityToolkit.GeneratedDependencyProperty.Helpers;
56
using Microsoft.CodeAnalysis;
67

78
namespace CommunityToolkit.GeneratedDependencyProperty.Models;
@@ -11,14 +12,14 @@ namespace CommunityToolkit.GeneratedDependencyProperty.Models;
1112
/// </summary>
1213
/// <param name="Hierarchy">The hierarchy info for the containing type.</param>
1314
/// <param name="PropertyName">The property name.</param>
15+
/// <param name="PropertyModifiers">The list of additional modifiers for the property (they are <see cref="SyntaxKind"/> values).</param>
1416
/// <param name="DeclaredAccessibility">The accessibility of the property, if available.</param>
1517
/// <param name="GetterAccessibility">The accessibility of the <see langword="get"/> accessor, if available.</param>
1618
/// <param name="SetterAccessibility">The accessibility of the <see langword="set"/> accessor, if available.</param>
1719
/// <param name="TypeName">The type name for the generated property (without nullability annotations).</param>
1820
/// <param name="TypeNameWithNullabilityAnnotations">The type name for the generated property, including nullability annotations.</param>
1921
/// <param name="DefaultValue">The default value to set the generated property to.</param>
2022
/// <param name="IsReferenceTypeOrUnconstraindTypeParameter">Indicates whether the property is of a reference type or an unconstrained type parameter.</param>
21-
/// <param name="IsRequired">Whether or not the generated property should be marked as required.</param>
2223
/// <param name="IsLocalCachingEnabled">Indicates whether local caching should be used for the property value.</param>
2324
/// <param name="IsPropertyChangedCallbackImplemented">Indicates whether the WinRT-based property changed callback is implemented.</param>
2425
/// <param name="IsSharedPropertyChangedCallbackImplemented">Indicates whether the WinRT-based shared property changed callback is implemented.</param>
@@ -27,14 +28,14 @@ namespace CommunityToolkit.GeneratedDependencyProperty.Models;
2728
internal sealed record DependencyPropertyInfo(
2829
HierarchyInfo Hierarchy,
2930
string PropertyName,
31+
EquatableArray<ushort> PropertyModifiers,
3032
Accessibility DeclaredAccessibility,
3133
Accessibility GetterAccessibility,
3234
Accessibility SetterAccessibility,
3335
string TypeName,
3436
string TypeNameWithNullabilityAnnotations,
3537
TypedConstantInfo DefaultValue,
3638
bool IsReferenceTypeOrUnconstraindTypeParameter,
37-
bool IsRequired,
3839
bool IsLocalCachingEnabled,
3940
bool IsPropertyChangedCallbackImplemented,
4041
bool IsSharedPropertyChangedCallbackImplemented,

0 commit comments

Comments
 (0)