Skip to content

Commit 1b02376

Browse files
committed
Add InvalidClassLevelNotifyDataErrorInfoAttributeAnalyzer
1 parent 7c9958c commit 1b02376

File tree

5 files changed

+55
-37
lines changed

5 files changed

+55
-37
lines changed

src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
<Compile Include="$(MSBuildThisFileDirectory)ComponentModel\ObservableValidatorValidateAllPropertiesGenerator.Execute.cs" />
4040
<Compile Include="$(MSBuildThisFileDirectory)ComponentModel\TransitiveMembersGenerator.cs" />
4141
<Compile Include="$(MSBuildThisFileDirectory)ComponentModel\TransitiveMembersGenerator.Execute.cs" />
42+
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\InvalidClassLevelNotifyDataErrorInfoAttributeAnalyzer.cs" />
4243
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\InvalidClassLevelNotifyPropertyChangedRecipientsAttributeAnalyzer.cs" />
4344
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\ClassUsingAttributeInsteadOfInheritanceAnalyzer.cs" />
4445
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\FieldWithOrphanedDependentObservablePropertyAttributesAnalyzer.cs" />

src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -637,25 +637,6 @@ private static bool TryGetNotifyDataErrorInfo(
637637
return false;
638638
}
639639

640-
/// <summary>
641-
/// Checks whether a given type using <c>[NotifyDataErrorInfo]</c> is valid and creates a <see cref="Diagnostic"/> if not.
642-
/// </summary>
643-
/// <param name="typeSymbol">The input <see cref="INamedTypeSymbol"/> instance to process.</param>
644-
/// <returns>The <see cref="Diagnostic"/> for <paramref name="typeSymbol"/>, if not a valid type.</returns>
645-
public static Diagnostic? GetIsNotifyDataErrorInfoDiagnosticForType(INamedTypeSymbol typeSymbol)
646-
{
647-
// If the containing type is valid, track it
648-
if (!typeSymbol.InheritsFromFullyQualifiedMetadataName("CommunityToolkit.Mvvm.ComponentModel.ObservableValidator"))
649-
{
650-
return Diagnostic.Create(
651-
InvalidTypeForNotifyDataErrorInfoError,
652-
typeSymbol.Locations.FirstOrDefault(),
653-
typeSymbol);
654-
}
655-
656-
return null;
657-
}
658-
659640
/// <summary>
660641
/// Gets a <see cref="CompilationUnitSyntax"/> instance with the cached args for property changing notifications.
661642
/// </summary>

src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.cs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,5 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
113113
context.AddSource("__KnownINotifyPropertyChangedArgs.g.cs", compilationUnit.GetText(Encoding.UTF8));
114114
}
115115
});
116-
117-
// Get all class declarations with at least one attribute
118-
IncrementalValuesProvider<INamedTypeSymbol> classSymbols =
119-
context.SyntaxProvider
120-
.CreateSyntaxProvider(
121-
static (node, _) => node is ClassDeclarationSyntax { AttributeLists.Count: > 0 },
122-
static (context, _) => (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
123-
124-
// Filter only the type symbols with [NotifyDataErrorInfo] and create diagnostics for them
125-
IncrementalValuesProvider<Diagnostic> notifyDataErrorInfoErrors =
126-
classSymbols
127-
.Where(static item => item.HasAttributeWithFullyQualifiedMetadataName("CommunityToolkit.Mvvm.ComponentModel.NotifyDataErrorInfoAttribute"))
128-
.Select(static (item, _) => Execute.GetIsNotifyDataErrorInfoDiagnosticForType(item))
129-
.Where(static item => item is not null)!;
130-
131-
// Output the diagnostics for [NotifyDataErrorInfo]
132-
context.ReportDiagnostics(notifyDataErrorInfoErrors);
133116
}
134117
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Immutable;
6+
using System.Linq;
7+
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
8+
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.Diagnostics;
10+
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
11+
12+
namespace CommunityToolkit.Mvvm.SourceGenerators;
13+
14+
/// <summary>
15+
/// A diagnostic analyzer that generates an error when a class level <c>[NotifyDataErrorInfo]</c> use is detected.
16+
/// </summary>
17+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
18+
public sealed class InvalidClassLevelNotifyDataErrorInfoAttributeAnalyzer : DiagnosticAnalyzer
19+
{
20+
/// <inheritdoc/>
21+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(InvalidTypeForNotifyDataErrorInfoError);
22+
23+
/// <inheritdoc/>
24+
public override void Initialize(AnalysisContext context)
25+
{
26+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
27+
context.EnableConcurrentExecution();
28+
29+
context.RegisterSymbolAction(static context =>
30+
{
31+
// We're looking for all class declarations
32+
if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Class, IsImplicitlyDeclared: false } classSymbol)
33+
{
34+
return;
35+
}
36+
37+
// Only inspect classes that are using [NotifyDataErrorInfo]
38+
if (!classSymbol.HasAttributeWithFullyQualifiedMetadataName("CommunityToolkit.Mvvm.ComponentModel.NotifyDataErrorInfoAttribute"))
39+
{
40+
return;
41+
}
42+
43+
// If the containing type is not valid, emit a diagnostic
44+
if (!classSymbol.InheritsFromFullyQualifiedMetadataName("CommunityToolkit.Mvvm.ComponentModel.ObservableValidator"))
45+
{
46+
context.ReportDiagnostic(Diagnostic.Create(
47+
InvalidTypeForNotifyDataErrorInfoError,
48+
classSymbol.Locations.FirstOrDefault(),
49+
classSymbol));
50+
}
51+
}, SymbolKind.NamedType);
52+
}
53+
}

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/InvalidClassLevelNotifyPropertyChangedRecipientsAttributeAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public override void Initialize(AnalysisContext context)
3434
return;
3535
}
3636

37-
// Only inspect class that are using [NotifyPropertyChangedRecipients]
37+
// Only inspect classes that are using [NotifyPropertyChangedRecipients]
3838
if (!classSymbol.HasAttributeWithFullyQualifiedMetadataName("CommunityToolkit.Mvvm.ComponentModel.NotifyPropertyChangedRecipientsAttribute"))
3939
{
4040
return;

0 commit comments

Comments
 (0)