mirror of
https://github.com/chylex/.NET-Community-Toolkit.git
synced 2025-06-03 08:34:03 +02:00
Add warning for unnecessary [NotifyRecipients] attribute
This commit is contained in:
parent
4a3f919f71
commit
0594506c2a
CommunityToolkit.Mvvm.SourceGenerators
tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests
@ -35,3 +35,4 @@ ### New Rules
|
|||||||
MVVMTK0026 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
MVVMTK0026 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
||||||
MVVMTK0027 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
MVVMTK0027 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
||||||
MVVMTK0028 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
MVVMTK0028 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
||||||
|
MVVMTK0029 | CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
|
||||||
|
@ -91,6 +91,7 @@ internal static class Execute
|
|||||||
ImmutableArray<AttributeInfo>.Builder forwardedAttributes = ImmutableArray.CreateBuilder<AttributeInfo>();
|
ImmutableArray<AttributeInfo>.Builder forwardedAttributes = ImmutableArray.CreateBuilder<AttributeInfo>();
|
||||||
bool notifyRecipients = false;
|
bool notifyRecipients = false;
|
||||||
bool notifyDataErrorInfo = false;
|
bool notifyDataErrorInfo = false;
|
||||||
|
bool hasOrInheritsClassLevelNotifyRecipients = false;
|
||||||
bool hasAnyValidationAttributes = false;
|
bool hasAnyValidationAttributes = false;
|
||||||
|
|
||||||
// Track the property changing event for the property, if the type supports it
|
// Track the property changing event for the property, if the type supports it
|
||||||
@ -106,6 +107,7 @@ internal static class Execute
|
|||||||
if (TryGetIsNotifyingRecipients(fieldSymbol, out bool isBroadcastTargetValid))
|
if (TryGetIsNotifyingRecipients(fieldSymbol, out bool isBroadcastTargetValid))
|
||||||
{
|
{
|
||||||
notifyRecipients = isBroadcastTargetValid;
|
notifyRecipients = isBroadcastTargetValid;
|
||||||
|
hasOrInheritsClassLevelNotifyRecipients = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the class-level [NotifyDataErrorInfo] setting, if any
|
// Get the class-level [NotifyDataErrorInfo] setting, if any
|
||||||
@ -125,7 +127,7 @@ internal static class Execute
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the property should also notify recipients
|
// Check whether the property should also notify recipients
|
||||||
if (TryGetIsNotifyingRecipients(fieldSymbol, attributeData, builder, out isBroadcastTargetValid))
|
if (TryGetIsNotifyingRecipients(fieldSymbol, attributeData, builder, hasOrInheritsClassLevelNotifyRecipients, out isBroadcastTargetValid))
|
||||||
{
|
{
|
||||||
notifyRecipients = isBroadcastTargetValid;
|
notifyRecipients = isBroadcastTargetValid;
|
||||||
|
|
||||||
@ -452,16 +454,28 @@ private static bool TryGetIsNotifyingRecipients(IFieldSymbol fieldSymbol, out bo
|
|||||||
/// <param name="fieldSymbol">The input <see cref="IFieldSymbol"/> instance to process.</param>
|
/// <param name="fieldSymbol">The input <see cref="IFieldSymbol"/> instance to process.</param>
|
||||||
/// <param name="attributeData">The <see cref="AttributeData"/> instance for <paramref name="fieldSymbol"/>.</param>
|
/// <param name="attributeData">The <see cref="AttributeData"/> instance for <paramref name="fieldSymbol"/>.</param>
|
||||||
/// <param name="diagnostics">The current collection of gathered diagnostics.</param>
|
/// <param name="diagnostics">The current collection of gathered diagnostics.</param>
|
||||||
|
/// <param name="hasOrInheritsClassLevelNotifyRecipients">Indicates wether the containing type of <paramref name="fieldSymbol"/> has or inherits <c>[NotifyRecipients]</c>.</param>
|
||||||
/// <param name="isBroadcastTargetValid">Whether or not the the property is in a valid target that can notify recipients.</param>
|
/// <param name="isBroadcastTargetValid">Whether or not the the property is in a valid target that can notify recipients.</param>
|
||||||
/// <returns>Whether or not the generated property for <paramref name="fieldSymbol"/> used <c>[NotifyRecipients]</c>.</returns>
|
/// <returns>Whether or not the generated property for <paramref name="fieldSymbol"/> used <c>[NotifyRecipients]</c>.</returns>
|
||||||
private static bool TryGetIsNotifyingRecipients(
|
private static bool TryGetIsNotifyingRecipients(
|
||||||
IFieldSymbol fieldSymbol,
|
IFieldSymbol fieldSymbol,
|
||||||
AttributeData attributeData,
|
AttributeData attributeData,
|
||||||
ImmutableArray<Diagnostic>.Builder diagnostics,
|
ImmutableArray<Diagnostic>.Builder diagnostics,
|
||||||
|
bool hasOrInheritsClassLevelNotifyRecipients,
|
||||||
out bool isBroadcastTargetValid)
|
out bool isBroadcastTargetValid)
|
||||||
{
|
{
|
||||||
if (attributeData.AttributeClass?.HasFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.NotifyRecipientsAttribute") == true)
|
if (attributeData.AttributeClass?.HasFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.NotifyRecipientsAttribute") == true)
|
||||||
{
|
{
|
||||||
|
// Emit a diagnostic if the attribute is unnecessary
|
||||||
|
if (hasOrInheritsClassLevelNotifyRecipients)
|
||||||
|
{
|
||||||
|
diagnostics.Add(
|
||||||
|
UnnecessaryNotifyRecipientsAttributeOnFieldWarning,
|
||||||
|
fieldSymbol,
|
||||||
|
fieldSymbol.ContainingType,
|
||||||
|
fieldSymbol.Name);
|
||||||
|
}
|
||||||
|
|
||||||
// If the containing type is valid, track it
|
// If the containing type is valid, track it
|
||||||
if (fieldSymbol.ContainingType.InheritsFromFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableRecipient") ||
|
if (fieldSymbol.ContainingType.InheritsFromFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableRecipient") ||
|
||||||
fieldSymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableRecipientAttribute"))
|
fieldSymbol.ContainingType.HasOrInheritsAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableRecipientAttribute"))
|
||||||
|
@ -459,4 +459,20 @@ internal static class DiagnosticDescriptors
|
|||||||
isEnabledByDefault: true,
|
isEnabledByDefault: true,
|
||||||
description: "Types annotated with [NotifyDataErrorInfo] must inherit from ObservableRecipient.",
|
description: "Types annotated with [NotifyDataErrorInfo] must inherit from ObservableRecipient.",
|
||||||
helpLinkUri: "https://aka.ms/mvvmtoolkit");
|
helpLinkUri: "https://aka.ms/mvvmtoolkit");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="DiagnosticDescriptor"/> indicating when <c>[NotifyRecipients]</c> is applied to a field in a class with <c>[NotifyRecipients]</c> used at the class-level.
|
||||||
|
/// <para>
|
||||||
|
/// Format: <c>"The field {0}.{1} is annotated with [NotifyRecipients], but that is not needed since its containing type already uses or inherits [NotifyRecipients] at the class-level"</c>.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DiagnosticDescriptor UnnecessaryNotifyRecipientsAttributeOnFieldWarning = new DiagnosticDescriptor(
|
||||||
|
id: "MVVMTK0029",
|
||||||
|
title: "Unnecessary [NotifyRecipients] field annotation",
|
||||||
|
messageFormat: "The field {0}.{1} is annotated with [NotifyRecipients], but that is not needed since its containing type already uses or inherits [NotifyRecipients] at the class-level",
|
||||||
|
category: typeof(ObservablePropertyGenerator).FullName,
|
||||||
|
defaultSeverity: DiagnosticSeverity.Warning,
|
||||||
|
isEnabledByDefault: true,
|
||||||
|
description: "Annotating a field with [NotifyRecipients] is not necessary if the containing type has or inherits [NotifyRecipients] at the class-level.",
|
||||||
|
helpLinkUri: "https://aka.ms/mvvmtoolkit");
|
||||||
}
|
}
|
||||||
|
@ -1298,6 +1298,50 @@ public partial class SampleViewModel : ObservableObject
|
|||||||
VerifyGeneratedDiagnostics<ObservablePropertyGenerator>(source, "MVVMTK0006", "MVVMTK0028");
|
VerifyGeneratedDiagnostics<ObservablePropertyGenerator>(source, "MVVMTK0006", "MVVMTK0028");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UnnecessaryNotifyRecipientsWarning_SameType()
|
||||||
|
{
|
||||||
|
string source = @"
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace MyApp
|
||||||
|
{
|
||||||
|
[NotifyRecipients]
|
||||||
|
public partial class MyViewModel : ObservableRecipient
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyRecipients]
|
||||||
|
public int number;
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
VerifyGeneratedDiagnostics<ObservablePropertyGenerator>(source, "MVVMTK0029");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UnnecessaryNotifyRecipientsWarning_BaseType()
|
||||||
|
{
|
||||||
|
string source = @"
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace MyApp
|
||||||
|
{
|
||||||
|
[NotifyRecipients]
|
||||||
|
public class MyBaseViewModel : ObservableRecipient
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class MyViewModel : MyBaseViewModel
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyRecipients]
|
||||||
|
public int number;
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
VerifyGeneratedDiagnostics<ObservablePropertyGenerator>(source, "MVVMTK0029");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifies the output of a source generator.
|
/// Verifies the output of a source generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
Reference in New Issue
Block a user