From 5a4f4dcb7a2c930fc3c09c134dfe50fbd037837c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 18 Aug 2024 19:47:11 -0700 Subject: [PATCH] Add unit tests for new analyzer diagnostics --- ...edCanvasEffectPropertyAccessorsAnalyzer.cs | 6 + ...vasEffectPropertyContainingTypeAnalyzer.cs | 4 +- ...CanvasEffectPropertyDeclarationAnalyzer.cs | 4 +- ...CanvasEffectPropertyGenerator_Analyzers.cs | 117 ++++++++++++++++++ 4 files changed, 127 insertions(+), 4 deletions(-) diff --git a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyAccessorsAnalyzer.cs b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyAccessorsAnalyzer.cs index 163601a64..58d2de2be 100644 --- a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyAccessorsAnalyzer.cs +++ b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyAccessorsAnalyzer.cs @@ -37,6 +37,12 @@ public override void Initialize(AnalysisContext context) return; } + // Skip implementation parts to avoid duplicate errors + if (context.Symbol is IPropertySymbol { PartialDefinitionPart: not null }) + { + return; + } + // If the property is using [GeneratedCanvasEffectProperty], emit the diagnostic if (context.Symbol.TryGetAttributeWithType(generatedCanvasEffectPropertyAttributeSymbol, out AttributeData? generatedCanvasEffectPropertyAttribute)) { diff --git a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyContainingTypeAnalyzer.cs b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyContainingTypeAnalyzer.cs index f002420b0..05e85c87e 100644 --- a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyContainingTypeAnalyzer.cs +++ b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyContainingTypeAnalyzer.cs @@ -32,8 +32,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSymbolAction(context => { - // Validate that we have a valid containing type - if (context.Symbol is not IPropertySymbol { ContainingType: { } containingTypeSymbol }) + // Validate that we have a valid containing type (also skip implementation parts) + if (context.Symbol is not IPropertySymbol { ContainingType: { } containingTypeSymbol, PartialDefinitionPart: null }) { return; } diff --git a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer.cs b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer.cs index 94482d0a2..68222d64d 100644 --- a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer.cs +++ b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/Diagnostics/Analyzers/InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer.cs @@ -37,8 +37,8 @@ public override void Initialize(AnalysisContext context) context.RegisterSymbolAction(context => { - // Ensure that we have some target property to analyze - if (context.Symbol is not IPropertySymbol propertySymbol) + // Ensure that we have some target property to analyze (also skip implementation parts) + if (context.Symbol is not IPropertySymbol { PartialDefinitionPart: null } propertySymbol) { return; } diff --git a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_CanvasEffectPropertyGenerator_Analyzers.cs b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_CanvasEffectPropertyGenerator_Analyzers.cs index b56cd23d2..91b4b1640 100644 --- a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_CanvasEffectPropertyGenerator_Analyzers.cs +++ b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_CanvasEffectPropertyGenerator_Analyzers.cs @@ -56,4 +56,121 @@ public abstract partial class MyEffect : CanvasEffect await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_StaticProperty_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + [{|CMPSD2DWINUI0003:GeneratedCanvasEffectProperty|}] + public static partial int {|CS9248:Number|} { get; set; } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_NotPartialProperty_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + [{|CMPSD2DWINUI0004:GeneratedCanvasEffectProperty|}] + public int Number { get; set; } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_PartialPropertyWithImplementation_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + [{|CMPSD2DWINUI0004:GeneratedCanvasEffectProperty|}] + public partial int Number { get; set; } + + public partial int Number { get => 42; set { } } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_PartialPropertyImplementationPart_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + public partial int Number { get; set; } + + [{|CMPSD2DWINUI0004:GeneratedCanvasEffectProperty|}] + public partial int Number { get => 42; set { } } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_ReturnsByRef_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + [{|CMPSD2DWINUI0005:GeneratedCanvasEffectProperty|}] + public partial ref int {|CS9248:Number|} { get; {|CS8147:set|}; } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_ReturnsByRefReadonly_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + [{|CMPSD2DWINUI0005:GeneratedCanvasEffectProperty|}] + public partial ref readonly int {|CS9248:Number|} { get; {|CS8147:set|}; } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task InvalidGeneratedCanvasEffectPropertyDeclarationAnalyzer_ReturnsRefStructType_Warns() + { + const string source = """ + using System; + using ComputeSharp.D2D1.WinUI; + + public abstract partial class MyEffect : CanvasEffect + { + [{|CMPSD2DWINUI0006:GeneratedCanvasEffectProperty|}] + public partial Span {|CS9248:Number|} { get; set; } + } + """; + + await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } } \ No newline at end of file