Skip to content

Commit 857de64

Browse files
authored
Merge pull request #1019 from CommunityToolkit/dev/generated-bcp-constructors
Refine filtering logic for [GeneratedBindableCustomProperty] analyzers
2 parents 9702e2d + 1bfc5a4 commit 857de64

File tree

5 files changed

+433
-24
lines changed

5 files changed

+433
-24
lines changed

Diff for: src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer.cs

+23-13
Original file line numberDiff line numberDiff line change
@@ -60,25 +60,35 @@ public override void Initialize(AnalysisContext context)
6060
return;
6161
}
6262

63-
// Warn on all [ObservableProperty] fields
63+
// Warn on all [ObservableProperty] fields that would be included
6464
foreach (IFieldSymbol fieldSymbol in FindObservablePropertyFields(typeSymbol, observablePropertySymbol))
6565
{
66-
context.ReportDiagnostic(Diagnostic.Create(
67-
WinRTGeneratedBindableCustomPropertyWithBaseObservablePropertyOnField,
68-
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
69-
typeSymbol,
70-
fieldSymbol.ContainingType,
71-
fieldSymbol.Name));
66+
string propertyName = ObservablePropertyGenerator.Execute.GetGeneratedPropertyName(fieldSymbol);
67+
68+
if (WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.DoesGeneratedBindableCustomPropertyAttributeIncludePropertyName(generatedBindableCustomPropertyAttribute, propertyName))
69+
{
70+
context.ReportDiagnostic(Diagnostic.Create(
71+
WinRTGeneratedBindableCustomPropertyWithBaseObservablePropertyOnField,
72+
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
73+
typeSymbol,
74+
fieldSymbol.ContainingType,
75+
fieldSymbol.Name));
76+
}
7277
}
7378

74-
// Warn on all [RelayCommand] methods
79+
// Warn on all [RelayCommand] methods that would be included
7580
foreach (IMethodSymbol methodSymbol in FindRelayCommandMethods(typeSymbol, relayCommandSymbol))
7681
{
77-
context.ReportDiagnostic(Diagnostic.Create(
78-
WinRTGeneratedBindableCustomPropertyWithBaseRelayCommand,
79-
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
80-
typeSymbol,
81-
methodSymbol));
82+
(_, string propertyName) = RelayCommandGenerator.Execute.GetGeneratedFieldAndPropertyNames(methodSymbol);
83+
84+
if (WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.DoesGeneratedBindableCustomPropertyAttributeIncludePropertyName(generatedBindableCustomPropertyAttribute, propertyName))
85+
{
86+
context.ReportDiagnostic(Diagnostic.Create(
87+
WinRTGeneratedBindableCustomPropertyWithBaseRelayCommand,
88+
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
89+
typeSymbol,
90+
methodSymbol));
91+
}
8292
}
8393
}, SymbolKind.NamedType);
8494
});

Diff for: src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs

+38-2
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,17 @@ public override void Initialize(AnalysisContext context)
5454
return;
5555
}
5656

57-
// If the containing type is using [GeneratedBindableCustomProperty], emit a warning
58-
if (typeSymbol.HasAttributeWithType(generatedBindableCustomPropertySymbol))
57+
// If the containing type is not using [GeneratedBindableCustomProperty], we can also skip it
58+
if (!typeSymbol.TryGetAttributeWithType(generatedBindableCustomPropertySymbol, out AttributeData? generatedBindableCustomPropertyAttribute))
5959
{
60+
return;
61+
}
62+
63+
(_, string propertyName) = RelayCommandGenerator.Execute.GetGeneratedFieldAndPropertyNames(methodSymbol);
64+
65+
if (DoesGeneratedBindableCustomPropertyAttributeIncludePropertyName(generatedBindableCustomPropertyAttribute, propertyName))
66+
{
67+
// Actually warn if the generated command would've been included by the generator
6068
context.ReportDiagnostic(Diagnostic.Create(
6169
WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible,
6270
methodSymbol.GetLocationFromAttributeDataOrDefault(relayCommandAttribute),
@@ -65,4 +73,32 @@ public override void Initialize(AnalysisContext context)
6573
}, SymbolKind.Method);
6674
});
6775
}
76+
77+
/// <summary>
78+
/// Checks whether a generated property with a given name would be included by the [GeneratedBindableCustomProperty] generator.
79+
/// </summary>
80+
/// <param name="attributeData">The input <see cref="AttributeData"/> value for the [GeneratedBindableCustomProperty] attribute.</param>
81+
/// <param name="propertyName">The target generated property name to check.</param>
82+
/// <returns>Whether <paramref name="propertyName"/> would be included by the [GeneratedBindableCustomProperty] generator.</returns>
83+
internal static bool DoesGeneratedBindableCustomPropertyAttributeIncludePropertyName(AttributeData attributeData, string propertyName)
84+
{
85+
// Make sure we have a valid list of property names to explicitly include.
86+
// If that is not the case, we consider all properties as included by default.
87+
if (attributeData.ConstructorArguments is not [{ IsNull: false, Kind: TypedConstantKind.Array, Type: IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_String }, Values: var names }, ..])
88+
{
89+
return true;
90+
}
91+
92+
// Simply match the input collection of target property names
93+
foreach (TypedConstant propertyValue in names)
94+
{
95+
if (propertyValue is { IsNull: false, Type.SpecialType: SpecialType.System_String, Value: string targetName } && targetName == propertyName)
96+
{
97+
return true;
98+
}
99+
}
100+
101+
// No matches, we can consider the property as not included
102+
return false;
103+
}
68104
}

Diff for: src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs

+9-9
Original file line numberDiff line numberDiff line change
@@ -766,49 +766,49 @@ internal static class DiagnosticDescriptors
766766
/// <summary>
767767
/// Gets a <see cref="DiagnosticDescriptor"/> for when <c>[RelayCommand]</c> is used on a method in types where <c>[GeneratedBindableCustomProperty]</c> is used.
768768
/// <para>
769-
/// Format: <c>"The method {0} using [RelayCommand] within a type also using [GeneratedBindableCustomProperty], which is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator)"</c>.
769+
/// Format: <c>"The method {0} using [RelayCommand] within a type also using [GeneratedBindableCustomProperty] and including the generated property, which is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator)"</c>.
770770
/// </para>
771771
/// </summary>
772772
public static readonly DiagnosticDescriptor WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible = new DiagnosticDescriptor(
773773
id: "MVVMTK0046",
774774
title: "Using [RelayCommand] is not compatible with [GeneratedBindableCustomProperty]",
775-
messageFormat: """The method {0} using [RelayCommand] within a type also using [GeneratedBindableCustomProperty], which is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator)""",
775+
messageFormat: """The method {0} using [RelayCommand] within a type also using [GeneratedBindableCustomProperty] and including the generated property, which is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator)""",
776776
category: typeof(RelayCommandGenerator).FullName,
777777
defaultSeverity: DiagnosticSeverity.Warning,
778778
isEnabledByDefault: true,
779-
description: "Using [RelayCommand] on methods within a type also using [GeneratedBindableCustomProperty] is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator).",
779+
description: "Using [RelayCommand] on methods within a type also using [GeneratedBindableCustomProperty] and including the generated property is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated command property that is produced by the MVVM Toolkit generator).",
780780
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0046");
781781

782782
/// <summary>
783783
/// Gets a <see cref="DiagnosticDescriptor"/> for when <c>[GeneratedBindableCustomProperty]</c> is used on a type that also uses <c>[ObservableProperty]</c> on any declared or inherited fields.
784784
/// <para>
785-
/// Format: <c>"The type {0} using [GeneratedBindableCustomProperty] is also using [ObservableProperty] on its declared (or inherited) field {1}.{2}: combining the two generators is not supported, and partial properties should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)"</c>.
785+
/// Format: <c>"The type {0} using [GeneratedBindableCustomProperty] is also using [ObservableProperty] on its declared (or inherited) field {1}.{2}, and including the generated property: combining the two generators is not supported, and partial properties should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)"</c>.
786786
/// </para>
787787
/// </summary>
788788
public static readonly DiagnosticDescriptor WinRTGeneratedBindableCustomPropertyWithBaseObservablePropertyOnField = new DiagnosticDescriptor(
789789
id: "MVVMTK0047",
790790
title: "Using [GeneratedBindableCustomProperty] is not compatible with [ObservableProperty] on fields",
791-
messageFormat: """The type {0} using [GeneratedBindableCustomProperty] is also using [ObservableProperty] on its declared (or inherited) field {1}.{2}: combining the two generators is not supported, and partial properties should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)""",
791+
messageFormat: """The type {0} using [GeneratedBindableCustomProperty] is also using [ObservableProperty] on its declared (or inherited) field {1}.{2}, and including the generated property: combining the two generators is not supported, and partial properties should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)""",
792792
category: typeof(ObservablePropertyGenerator).FullName,
793793
defaultSeverity: DiagnosticSeverity.Warning,
794794
isEnabledByDefault: true,
795-
description: "Using [GeneratedBindableCustomProperty] on types that also use [ObservableProperty] on any declared (or inherited) fields is not supported, and partial properties should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator).",
795+
description: "Using [GeneratedBindableCustomProperty] on types that also use [ObservableProperty] on any declared (or inherited) fields and including the generated property is not supported, and partial properties should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator).",
796796
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0047");
797797

798798
/// <summary>
799799
/// Gets a <see cref="DiagnosticDescriptor"/> for when <c>[GeneratedBindableCustomProperty]</c> is used on a type that also uses <c>[RelayCommand]</c> on any declared or inherited methods.
800800
/// <para>
801-
/// Format: <c>"The type {0} using [GeneratedBindableCustomProperty] is also using [RelayCommand] on its inherited method {1}: combining the two generators is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)"</c>.
801+
/// Format: <c>"The type {0} using [GeneratedBindableCustomProperty] is also using [RelayCommand] on its inherited method {1} and including the generated property: combining the two generators is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)"</c>.
802802
/// </para>
803803
/// </summary>
804804
public static readonly DiagnosticDescriptor WinRTGeneratedBindableCustomPropertyWithBaseRelayCommand = new DiagnosticDescriptor(
805805
id: "MVVMTK0048",
806806
title: "Using [GeneratedBindableCustomProperty] is not compatible with [RelayCommand]",
807-
messageFormat: """The type {0} using [GeneratedBindableCustomProperty] is also using [RelayCommand] on its inherited method {1}: combining the two generators is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)""",
807+
messageFormat: """The type {0} using [GeneratedBindableCustomProperty] is also using [RelayCommand] on its inherited method {1} and including the generated property: combining the two generators is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator)""",
808808
category: typeof(RelayCommandGenerator).FullName,
809809
defaultSeverity: DiagnosticSeverity.Warning,
810810
isEnabledByDefault: true,
811-
description: "Using [GeneratedBindableCustomProperty] on types that also use [RelayCommand] on any inherited methods is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator).",
811+
description: "Using [GeneratedBindableCustomProperty] on types that also use [RelayCommand] on any inherited methods and including the generated property is not supported, and a manually declared command property should be used instead (the [GeneratedBindableCustomProperty] generator cannot see the generated property that is produced by the MVVM Toolkit generator).",
812812
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0048");
813813

814814
/// <summary>

0 commit comments

Comments
 (0)