Skip to content

Commit 1f88b1e

Browse files
committed
Skip MVVMTK0041 when properties are not partial
1 parent 70e4691 commit 1f88b1e

File tree

2 files changed

+70
-3
lines changed

2 files changed

+70
-3
lines changed

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using System.Collections.Immutable;
88
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
99
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.CSharp;
11+
using Microsoft.CodeAnalysis.CSharp.Syntax;
1012
using Microsoft.CodeAnalysis.Diagnostics;
1113
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
1214

@@ -44,11 +46,25 @@ public override void Initialize(AnalysisContext context)
4446
context.RegisterSymbolAction(context =>
4547
{
4648
// We only want to target partial property definitions (also include non-partial ones for diagnostics)
47-
if (context.Symbol is not IPropertySymbol { PartialDefinitionPart: null })
49+
if (context.Symbol is not IPropertySymbol { PartialDefinitionPart: null } partialProperty)
4850
{
4951
return;
5052
}
5153

54+
// Make sure to skip the warning if the property is not actually partial
55+
if (partialProperty.DeclaringSyntaxReferences is [var syntaxReference])
56+
{
57+
// Make sure we can find the syntax node, and that it's a property declaration
58+
if (syntaxReference.GetSyntax(context.CancellationToken) is PropertyDeclarationSyntax propertyDeclarationSyntax)
59+
{
60+
// If the property is not partial, ignore it, as we'll already have a warning from the other analyzer here
61+
if (!propertyDeclarationSyntax.Modifiers.Any(SyntaxKind.PartialKeyword))
62+
{
63+
return;
64+
}
65+
}
66+
}
67+
5268
// If the property is using [ObservableProperty], emit the diagnostic
5369
if (context.Symbol.TryGetAttributeWithType(observablePropertySymbol, out AttributeData? observablePropertyAttribute))
5470
{

tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4110.UnitTests/Test_SourceGeneratorsDiagnostics.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
using System.Threading.Tasks;
66
using CommunityToolkit.Mvvm.SourceGenerators.UnitTests.Helpers;
77
using Microsoft.CodeAnalysis.CSharp;
8+
using Microsoft.CodeAnalysis.Testing;
89
using Microsoft.VisualStudio.TestTools.UnitTesting;
910

1011
namespace CommunityToolkit.Mvvm.SourceGenerators.UnitTests;
1112

1213
partial class Test_SourceGeneratorsDiagnostics
1314
{
1415
[TestMethod]
15-
public async Task RequireCSharpLanguageVersionPreviewAnalyzer_LanguageVersionIsNotPreview_Warns()
16+
public async Task RequireCSharpLanguageVersionPreviewAnalyzer_LanguageVersionIsNotPreview_DoesnNotWarn()
1617
{
1718
const string source = """
1819
using CommunityToolkit.Mvvm.ComponentModel;
@@ -21,7 +22,7 @@ namespace MyApp
2122
{
2223
public partial class SampleViewModel : ObservableObject
2324
{
24-
[{|MVVMTK0041:ObservableProperty|}]
25+
[ObservableProperty]
2526
public string Name { get; set; }
2627
}
2728
}
@@ -30,6 +31,32 @@ public partial class SampleViewModel : ObservableObject
3031
await VerifyAnalyzerDiagnosticsAndSuccessfulGeneration<RequiresCSharpLanguageVersionPreviewAnalyzer>(source, LanguageVersion.CSharp12);
3132
}
3233

34+
[TestMethod]
35+
public async Task RequireCSharpLanguageVersionPreviewAnalyzer_LanguageVersionIsNotPreview_Partial_Warns()
36+
{
37+
const string source = """
38+
using CommunityToolkit.Mvvm.ComponentModel;
39+
40+
namespace MyApp
41+
{
42+
public partial class SampleViewModel : ObservableObject
43+
{
44+
[{|MVVMTK0041:ObservableProperty|}]
45+
public partial string Name { get; set; }
46+
}
47+
}
48+
""";
49+
50+
await CSharpAnalyzerWithLanguageVersionTest<RequiresCSharpLanguageVersionPreviewAnalyzer>.VerifyAnalyzerAsync(
51+
source,
52+
LanguageVersion.CSharp12,
53+
54+
// /0/Test0.cs(8,31): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version 'preview' or greater.
55+
DiagnosticResult.CompilerError("CS8703").WithSpan(8, 31, 8, 35).WithArguments("partial", "12.0", "preview"),
56+
// /0/Test0.cs(8,31): error CS9248: Partial property 'SampleViewModel.Name' must have an implementation part.
57+
DiagnosticResult.CompilerError("CS9248").WithSpan(8, 31, 8, 35).WithArguments("MyApp.SampleViewModel.Name"));
58+
}
59+
3360
[TestMethod]
3461
public async Task RequireCSharpLanguageVersionPreviewAnalyzer_LanguageVersionIsPreview_DoesNotWarn()
3562
{
@@ -49,6 +76,30 @@ public partial class SampleViewModel : ObservableObject
4976
await VerifyAnalyzerDiagnosticsAndSuccessfulGeneration<RequiresCSharpLanguageVersionPreviewAnalyzer>(source, languageVersion: LanguageVersion.Preview);
5077
}
5178

79+
[TestMethod]
80+
public async Task RequireCSharpLanguageVersionPreviewAnalyzer_LanguageVersionIsPreview_Partial_DoesNotWarn()
81+
{
82+
const string source = """
83+
using CommunityToolkit.Mvvm.ComponentModel;
84+
85+
namespace MyApp
86+
{
87+
public partial class SampleViewModel : ObservableObject
88+
{
89+
[ObservableProperty]
90+
public partial string Name { get; set; }
91+
}
92+
}
93+
""";
94+
95+
await CSharpAnalyzerWithLanguageVersionTest<RequiresCSharpLanguageVersionPreviewAnalyzer>.VerifyAnalyzerAsync(
96+
source,
97+
LanguageVersion.Preview,
98+
99+
// /0/Test0.cs(8,31): error CS9248: Partial property 'SampleViewModel.Name' must have an implementation part.
100+
DiagnosticResult.CompilerError("CS9248").WithSpan(8, 31, 8, 35).WithArguments("MyApp.SampleViewModel.Name"));
101+
}
102+
52103
[TestMethod]
53104
public async Task UseObservablePropertyOnPartialPropertyAnalyzer_LanguageVersionIsNotPreview_DoesNotWarn()
54105
{

0 commit comments

Comments
 (0)