diff --git a/ComputeSharp.sln b/ComputeSharp.sln index cb4e0e52d..8408de20e 100644 --- a/ComputeSharp.sln +++ b/ComputeSharp.sln @@ -187,6 +187,12 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ComputeSharp.D2D1.UI.Source EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.D2D1.Uwp.SourceGenerators", "src\ComputeSharp.D2D1.Uwp.SourceGenerators\ComputeSharp.D2D1.Uwp.SourceGenerators.csproj", "{690C4014-A06B-44DB-B717-AEA4CAFA9D68}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ComputeSharp.D2D1.UI.CodeFixers", "src\ComputeSharp.D2D1.UI.CodeFixers\ComputeSharp.D2D1.UI.CodeFixers.shproj", "{CE85DC5A-E455-42FE-9B64-0D5F0D7EE366}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.D2D1.WinUI.CodeFixers", "src\ComputeSharp.D2D1.WinUI.CodeFixers\ComputeSharp.D2D1.WinUI.CodeFixers.csproj", "{9D3C872E-D64E-47E7-BDC8-077A151DBB7D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.D2D1.Uwp.CodeFixers", "src\ComputeSharp.D2D1.Uwp.CodeFixers\ComputeSharp.D2D1.Uwp.CodeFixers.csproj", "{8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -535,6 +541,22 @@ Global {690C4014-A06B-44DB-B717-AEA4CAFA9D68}.Release|ARM64.Build.0 = Release|Any CPU {690C4014-A06B-44DB-B717-AEA4CAFA9D68}.Release|x64.ActiveCfg = Release|Any CPU {690C4014-A06B-44DB-B717-AEA4CAFA9D68}.Release|x64.Build.0 = Release|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Debug|ARM64.Build.0 = Debug|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Debug|x64.Build.0 = Debug|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Release|ARM64.ActiveCfg = Release|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Release|ARM64.Build.0 = Release|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Release|x64.ActiveCfg = Release|Any CPU + {9D3C872E-D64E-47E7-BDC8-077A151DBB7D}.Release|x64.Build.0 = Release|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Debug|ARM64.Build.0 = Debug|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Debug|x64.ActiveCfg = Debug|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Debug|x64.Build.0 = Debug|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Release|ARM64.ActiveCfg = Release|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Release|ARM64.Build.0 = Release|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Release|x64.ActiveCfg = Release|Any CPU + {8BE73DB3-16E0-41F4-A87F-0C2AB43856A2}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -597,14 +619,17 @@ Global src\ComputeSharp.SourceGeneration\ComputeSharp.SourceGeneration.projitems*{690c4014-a06b-44db-b717-aea4cafa9d68}*SharedItemsImports = 5 src\ComputeSharp.D2D1.UI\ComputeSharp.D2D1.UI.projitems*{716df19e-69ba-4a9c-9ca4-bfd196152f46}*SharedItemsImports = 5 samples\ComputeSharp.SwapChain.Shaders.D2D1\ComputeSharp.SwapChain.Shaders.D2D1.projitems*{73c32d0f-64db-4674-84e9-8fcc41228474}*SharedItemsImports = 5 + src\ComputeSharp.D2D1.UI.CodeFixers\ComputeSharp.D2D1.UI.CodeFixers.projitems*{8be73db3-16e0-41f4-a87f-0c2ab43856a2}*SharedItemsImports = 5 src\ComputeSharp.SourceGeneration.Hlsl\ComputeSharp.SourceGeneration.Hlsl.projitems*{9ac496a3-bbf0-4c8f-a50d-a20bf01c5e05}*SharedItemsImports = 13 src\ComputeSharp.CodeFixing\ComputeSharp.CodeFixing.projitems*{9b4448b1-200f-4966-8a13-a508691b3003}*SharedItemsImports = 5 + src\ComputeSharp.D2D1.UI.CodeFixers\ComputeSharp.D2D1.UI.CodeFixers.projitems*{9d3c872e-d64e-47e7-bdc8-077a151dbb7d}*SharedItemsImports = 5 src\ComputeSharp.Win32.D2D1\ComputeSharp.Win32.D2D1.projitems*{9da1da9f-f8b2-4b25-be80-c21f773029e3}*SharedItemsImports = 13 samples\ComputeSharp.SwapChain.Shaders.D2D1\ComputeSharp.SwapChain.Shaders.D2D1.projitems*{9ea5ae9d-c39a-4f43-b03e-0a848ea2558a}*SharedItemsImports = 5 samples\ComputeSharp.SwapChain.Shaders.D2D1\ComputeSharp.SwapChain.Shaders.D2D1.projitems*{9fbe070e-a210-4cef-9f04-61c2b269c600}*SharedItemsImports = 5 src\ComputeSharp.D2D1.UI\ComputeSharp.D2D1.UI.projitems*{a2a2171b-0baf-4a2a-bfb3-3357ef714bf0}*SharedItemsImports = 13 src\ComputeSharp.D2D1.UI\ComputeSharp.D2D1.UI.projitems*{bd9e6556-357e-4c20-bfcd-fb131f9372fa}*SharedItemsImports = 5 samples\ComputeSharp.SwapChain.Shaders\ComputeSharp.SwapChain.Shaders.projitems*{c12d7ace-98ed-4813-8118-6667c34f484f}*SharedItemsImports = 5 + src\ComputeSharp.D2D1.UI.CodeFixers\ComputeSharp.D2D1.UI.CodeFixers.projitems*{ce85dc5a-e455-42fe-9b64-0d5f0d7ee366}*SharedItemsImports = 13 src\ComputeSharp.D2D1.UI.SourceGenerators\ComputeSharp.D2D1.UI.SourceGenerators.projitems*{d20e610f-eb37-46e7-b028-04784d7400d5}*SharedItemsImports = 13 src\ComputeSharp.SourceGeneration.Hlsl\ComputeSharp.SourceGeneration.Hlsl.projitems*{e44053bd-a761-47fb-aa78-087a599672ea}*SharedItemsImports = 5 src\ComputeSharp.SourceGeneration\ComputeSharp.SourceGeneration.projitems*{e44053bd-a761-47fb-aa78-087a599672ea}*SharedItemsImports = 5 diff --git a/build/Directory.Build.props b/build/Directory.Build.props index 5d060e9de..6545de68c 100644 --- a/build/Directory.Build.props +++ b/build/Directory.Build.props @@ -186,7 +186,9 @@ false diff --git a/src/ComputeSharp.CodeFixers/ComputeSharp.CodeFixers.csproj b/src/ComputeSharp.CodeFixers/ComputeSharp.CodeFixers.csproj index 40b481406..685c48f96 100644 --- a/src/ComputeSharp.CodeFixers/ComputeSharp.CodeFixers.csproj +++ b/src/ComputeSharp.CodeFixers/ComputeSharp.CodeFixers.csproj @@ -4,7 +4,7 @@ - + diff --git a/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj b/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj index cf24b82b9..dbfc9741f 100644 --- a/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj +++ b/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj @@ -4,7 +4,7 @@ - + diff --git a/src/ComputeSharp.D2D1.UI.CodeFixers/ComputeSharp.D2D1.UI.CodeFixers.projitems b/src/ComputeSharp.D2D1.UI.CodeFixers/ComputeSharp.D2D1.UI.CodeFixers.projitems new file mode 100644 index 000000000..7f9be6958 --- /dev/null +++ b/src/ComputeSharp.D2D1.UI.CodeFixers/ComputeSharp.D2D1.UI.CodeFixers.projitems @@ -0,0 +1,14 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + ce85dc5a-e455-42fe-9b64-0d5f0d7ee366 + + + ComputeSharp.D2D1.UI.CodeFixers + + + + + \ No newline at end of file diff --git a/src/ComputeSharp.D2D1.UI.CodeFixers/ComputeSharp.D2D1.UI.CodeFixers.shproj b/src/ComputeSharp.D2D1.UI.CodeFixers/ComputeSharp.D2D1.UI.CodeFixers.shproj new file mode 100644 index 000000000..51be84cca --- /dev/null +++ b/src/ComputeSharp.D2D1.UI.CodeFixers/ComputeSharp.D2D1.UI.CodeFixers.shproj @@ -0,0 +1,13 @@ + + + + ce85dc5a-e455-42fe-9b64-0d5f0d7ee366 + 14.0 + + + + + + + + diff --git a/src/ComputeSharp.D2D1.UI.CodeFixers/UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer.cs b/src/ComputeSharp.D2D1.UI.CodeFixers/UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer.cs new file mode 100644 index 000000000..da15eade9 --- /dev/null +++ b/src/ComputeSharp.D2D1.UI.CodeFixers/UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer.cs @@ -0,0 +1,350 @@ +using System.Collections.Immutable; +using System.Composition; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; +#if WINDOWS_UWP +using ComputeSharp.D2D1.Uwp.SourceGenerators.Constants; +#else +using ComputeSharp.D2D1.WinUI.SourceGenerators.Constants; +#endif +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Text; +#if WINDOWS_UWP +using static ComputeSharp.D2D1.Uwp.SourceGenerators.DiagnosticDescriptors; +#else +using static ComputeSharp.D2D1.WinUI.SourceGenerators.DiagnosticDescriptors; +#endif +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +#if WINDOWS_UWP +namespace ComputeSharp.D2D1.Uwp.SourceGenerators; +#else +namespace ComputeSharp.D2D1.WinUI.SourceGenerators; +#endif + +/// +/// A code fixer that converts manual properties into partial properties using [GeneratedCanvasEffectProperty]. +/// +[ExportCodeFixProvider(LanguageNames.CSharp)] +[Shared] +public sealed class UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer : CodeFixProvider +{ + /// + public override ImmutableArray FixableDiagnosticIds { get; } = [UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyId]; + + /// + public override Microsoft.CodeAnalysis.CodeFixes.FixAllProvider? GetFixAllProvider() + { + return new FixAllProvider(); + } + + /// + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + Diagnostic diagnostic = context.Diagnostics[0]; + TextSpan diagnosticSpan = context.Span; + + // This code fixer needs the semantic model, so check that first + if (!context.Document.SupportsSemanticModel) + { + return; + } + + // Retrieve the properties passed by the analyzer + if (!int.TryParse(diagnostic.Properties[UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.InvalidationTypePropertyName], out int invalidationType)) + { + return; + } + + SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + + // Get the property declaration from the target diagnostic + if (root!.FindNode(diagnosticSpan) is PropertyDeclarationSyntax propertyDeclaration) + { + // Get the semantic model, as we need to resolve symbols + SemanticModel semanticModel = (await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false))!; + + // Register the code fix to update the semi-auto property to a partial property with [GeneratedCanvasEffectProperty] + context.RegisterCodeFix( + CodeAction.Create( + title: "Use [GeneratedCanvasEffectProperty]", + createChangedDocument: token => ConvertToPartialProperty( + context.Document, + semanticModel, + root, + propertyDeclaration, + invalidationType), + equivalenceKey: "Use [GeneratedCanvasEffectProperty]"), + diagnostic); + } + } + + /// + /// Tries to get an for the [GeneratedCanvasEffectProperty] attribute. + /// + /// The original document being fixed. + /// The instance for the current compilation. + /// The resulting attribute list, if successfully retrieved. + /// Whether could be retrieved successfully. + private static bool TryGetGeneratedCanvasEffectPropertyAttributeList( + Document document, + SemanticModel semanticModel, + [NotNullWhen(true)] out AttributeListSyntax? generatedCanvasEffectPropertyAttributeList) + { + // Make sure we can resolve the '[GeneratedCanvasEffectProperty]' attribute + if (semanticModel.Compilation.GetTypeByMetadataName(WellKnownTypeNames.GeneratedCanvasEffectPropertyAttribute) is not INamedTypeSymbol attributeSymbol) + { + generatedCanvasEffectPropertyAttributeList = null; + + return false; + } + + SyntaxGenerator syntaxGenerator = SyntaxGenerator.GetGenerator(document); + + // Create the attribute syntax for the new '[GeneratedCanvasEffectProperty]' attribute here too + SyntaxNode attributeTypeSyntax = syntaxGenerator.TypeExpression(attributeSymbol).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation); + + generatedCanvasEffectPropertyAttributeList = (AttributeListSyntax)syntaxGenerator.Attribute(attributeTypeSyntax); + + return true; + } + + /// + /// Updates an for the [GeneratedCanvasEffectProperty] attribute with the right default value. + /// + /// The original document being fixed. + /// The instance for the current compilation. + /// The with the attribute to add. + /// The invalidation type to use. + /// The updated attribute syntax. + private static AttributeListSyntax UpdateGeneratedCanvasEffectPropertyAttributeList( + Document document, + SemanticModel semanticModel, + AttributeListSyntax generatedCanvasEffectPropertyAttributeList, + int invalidationType) + { + // If the invalidation type is not the default, set it in the attribute. + // We extract the generated attribute so we can add the new argument. + // It's important to reuse it, as it has the "add usings" annotation. + if (invalidationType == 1) + { + // Try to resolve the attribute type, if present (this should always be the case) + if (semanticModel.Compilation.GetTypeByMetadataName(WellKnownTypeNames.CanvasEffectInvalidationType) is INamedTypeSymbol enumTypeSymbol) + { + SyntaxGenerator syntaxGenerator = SyntaxGenerator.GetGenerator(document); + + // Create the identifier syntax for the enum type, with the right annotations + SyntaxNode enumTypeSyntax = syntaxGenerator.TypeExpression(enumTypeSymbol).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation); + + // Create the member access expression for the target enum type. + // We only ever take this path for the 'Creation' invalidation type. + SyntaxNode enumMemberAccessExpressionSyntax = syntaxGenerator.MemberAccessExpression(enumTypeSyntax, "Creation"); + + // Create the attribute argument to insert + SyntaxNode attributeArgumentSyntax = syntaxGenerator.AttributeArgument(enumMemberAccessExpressionSyntax); + + // Actually add the argument to the existing attribute syntax + return (AttributeListSyntax)syntaxGenerator.AddAttributeArguments(generatedCanvasEffectPropertyAttributeList, [attributeArgumentSyntax]); + } + + // This failed... For some reason. Use the fully qualified type name as a last resort. + return + AttributeList(SingletonSeparatedList( + generatedCanvasEffectPropertyAttributeList.Attributes[0] + .AddArgumentListArguments( + AttributeArgument(ParseExpression( + $"global::{WellKnownTypeNames.CanvasEffectInvalidationType}.Creation"))))); + } + + // If we have no custom invalidation type, we can just reuse the attribute with no changes + return generatedCanvasEffectPropertyAttributeList; + } + + /// + /// Applies the code fix to a target identifier and returns an updated document. + /// + /// The original document being fixed. + /// The instance for the current compilation. + /// The original tree root belonging to the current document. + /// The for the property being updated. + /// The invalidation type to use. + /// An updated document with the applied code fix, and being replaced with a partial property. + private static async Task ConvertToPartialProperty( + Document document, + SemanticModel semanticModel, + SyntaxNode root, + PropertyDeclarationSyntax propertyDeclaration, + int invalidationType) + { + await Task.CompletedTask; + + // If we can't generate the new attribute list, bail (this should never happen) + if (!TryGetGeneratedCanvasEffectPropertyAttributeList(document, semanticModel, out AttributeListSyntax? generatedCanvasEffectPropertyAttributeList)) + { + return document; + } + + // Create an editor to perform all mutations + SyntaxEditor syntaxEditor = new(root, document.Project.Solution.Workspace.Services); + + ConvertToPartialProperty( + document, + semanticModel, + propertyDeclaration, + generatedCanvasEffectPropertyAttributeList, + syntaxEditor, + invalidationType); + + // Create the new document with the single change + return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot()); + } + + /// + /// Applies the code fix to a target identifier and returns an updated document. + /// + /// The original document being fixed. + /// The instance for the current compilation. + /// The for the property being updated. + /// The with the attribute to add. + /// The instance to use. + /// The invalidation type to use. + /// An updated document with the applied code fix, and being replaced with a partial property. + private static void ConvertToPartialProperty( + Document document, + SemanticModel semanticModel, + PropertyDeclarationSyntax propertyDeclaration, + AttributeListSyntax generatedCanvasEffectPropertyAttributeList, + SyntaxEditor syntaxEditor, + int invalidationType) + { + // Update the attribute to insert with the invalidation type, if needed + generatedCanvasEffectPropertyAttributeList = UpdateGeneratedCanvasEffectPropertyAttributeList( + document, + semanticModel, + generatedCanvasEffectPropertyAttributeList, + invalidationType); + + // Start setting up the updated attribute lists + SyntaxList attributeLists = propertyDeclaration.AttributeLists; + + if (attributeLists is [AttributeListSyntax firstAttributeListSyntax, ..]) + { + // Remove the trivia from the original first attribute + attributeLists = attributeLists.Replace( + nodeInList: firstAttributeListSyntax, + newNode: firstAttributeListSyntax.WithoutTrivia()); + + // If the property has at least an attribute list, move the trivia from it to the new attribute + generatedCanvasEffectPropertyAttributeList = generatedCanvasEffectPropertyAttributeList.WithTriviaFrom(firstAttributeListSyntax); + + // Insert the new attribute + attributeLists = attributeLists.Insert(0, generatedCanvasEffectPropertyAttributeList); + } + else + { + // Otherwise (there are no attribute lists), transfer the trivia to the new (only) attribute list + generatedCanvasEffectPropertyAttributeList = generatedCanvasEffectPropertyAttributeList.WithTriviaFrom(propertyDeclaration); + + // Save the new attribute list + attributeLists = attributeLists.Add(generatedCanvasEffectPropertyAttributeList); + } + + // Get a new property that is partial and with semicolon token accessors + PropertyDeclarationSyntax updatedPropertyDeclaration = + propertyDeclaration + .AddModifiers(Token(SyntaxKind.PartialKeyword)) + .WithoutLeadingTrivia() + .WithAttributeLists(attributeLists) + .WithAdditionalAnnotations(Formatter.Annotation) + .WithAccessorList(AccessorList(List( + [ + // Keep the accessors (so we can easily keep all trivia, modifiers, attributes, etc.) but make them semicolon only + propertyDeclaration.AccessorList!.Accessors[0] + .WithBody(null) + .WithExpressionBody(null) + .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) + .WithAdditionalAnnotations(Formatter.Annotation), + propertyDeclaration.AccessorList!.Accessors[1] + .WithBody(null) + .WithExpressionBody(null) + .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) + .WithTrailingTrivia(propertyDeclaration.AccessorList.Accessors[1].GetTrailingTrivia()) + .WithAdditionalAnnotations(Formatter.Annotation) + ])).WithTrailingTrivia(propertyDeclaration.AccessorList.GetTrailingTrivia())); + + syntaxEditor.ReplaceNode(propertyDeclaration, updatedPropertyDeclaration); + + // Find the parent type for the property + TypeDeclarationSyntax typeDeclaration = propertyDeclaration.FirstAncestorOrSelf()!; + + // Make sure it's partial (we create the updated node in the function to preserve the updated property declaration). + // If we created it separately and replaced it, the whole tree would also be replaced, and we'd lose the new property. + if (!typeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) + { + syntaxEditor.ReplaceNode(typeDeclaration, static (node, generator) => generator.WithModifiers(node, generator.GetModifiers(node).WithPartial(true))); + } + } + + /// + /// A custom with the logic from . + /// + private sealed class FixAllProvider : DocumentBasedFixAllProvider + { + /// + protected override async Task FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray diagnostics) + { + // Get the semantic model, as we need to resolve symbols + if (await document.GetSemanticModelAsync(fixAllContext.CancellationToken).ConfigureAwait(false) is not SemanticModel semanticModel) + { + return document; + } + + // Get the document root (this should always succeed) + if (await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false) is not SyntaxNode root) + { + return document; + } + + // If we can't generate the new attribute list, bail (this should never happen) + if (!TryGetGeneratedCanvasEffectPropertyAttributeList(document, semanticModel, out AttributeListSyntax? generatedCanvasEffectPropertyAttributeList)) + { + return document; + } + + // Create an editor to perform all mutations (across all edits in the file) + SyntaxEditor syntaxEditor = new(root, fixAllContext.Solution.Services); + + foreach (Diagnostic diagnostic in diagnostics) + { + // Get the current property declaration for the diagnostic + if (root.FindNode(diagnostic.Location.SourceSpan) is not PropertyDeclarationSyntax propertyDeclaration) + { + continue; + } + + // Retrieve the properties passed by the analyzer + if (!int.TryParse(diagnostic.Properties[UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.InvalidationTypePropertyName], out int invalidationType)) + { + continue; + } + + ConvertToPartialProperty( + document, + semanticModel, + propertyDeclaration, + generatedCanvasEffectPropertyAttributeList, + syntaxEditor, + invalidationType); + } + + return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot()); + } + } +} \ No newline at end of file diff --git a/src/ComputeSharp.D2D1.UI.SourceGenerators/ComputeSharp.D2D1.UI.SourceGenerators.projitems b/src/ComputeSharp.D2D1.UI.SourceGenerators/ComputeSharp.D2D1.UI.SourceGenerators.projitems index b21e1a362..02d5da44e 100644 --- a/src/ComputeSharp.D2D1.UI.SourceGenerators/ComputeSharp.D2D1.UI.SourceGenerators.projitems +++ b/src/ComputeSharp.D2D1.UI.SourceGenerators/ComputeSharp.D2D1.UI.SourceGenerators.projitems @@ -16,6 +16,7 @@ + diff --git a/src/ComputeSharp.D2D1.UI.SourceGenerators/Constants/WellKnownTypeNames.cs b/src/ComputeSharp.D2D1.UI.SourceGenerators/Constants/WellKnownTypeNames.cs index 4abbee9d6..d79fbb566 100644 --- a/src/ComputeSharp.D2D1.UI.SourceGenerators/Constants/WellKnownTypeNames.cs +++ b/src/ComputeSharp.D2D1.UI.SourceGenerators/Constants/WellKnownTypeNames.cs @@ -10,7 +10,7 @@ namespace ComputeSharp.D2D1.WinUI.SourceGenerators.Constants; internal static class WellKnownTypeNames { /// - /// The fully qualified type name for the [GeneratedCanvasEffectPropertyAttribute] type. + /// The fully qualified type name for the [GeneratedCanvasEffectProperty] type. /// public const string GeneratedCanvasEffectPropertyAttribute = #if WINDOWS_UWP diff --git a/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/Analyzers/UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.cs b/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/Analyzers/UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.cs new file mode 100644 index 000000000..b34fdb6fd --- /dev/null +++ b/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/Analyzers/UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +#if WINDOWS_UWP +using ComputeSharp.D2D1.Uwp.SourceGenerators.Constants; +#else +using ComputeSharp.D2D1.WinUI.SourceGenerators.Constants; +#endif +using ComputeSharp.SourceGeneration.Extensions; +using ComputeSharp.SourceGeneration.Helpers; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +#if WINDOWS_UWP +using static ComputeSharp.D2D1.Uwp.SourceGenerators.DiagnosticDescriptors; +#else +using static ComputeSharp.D2D1.WinUI.SourceGenerators.DiagnosticDescriptors; +#endif + +#if WINDOWS_UWP +namespace ComputeSharp.D2D1.Uwp.SourceGenerators; +#else +namespace ComputeSharp.D2D1.WinUI.SourceGenerators; +#endif + +/// +/// A diagnostic analyzer that generates a suggestion whenever [GeneratedCanvasEffectProperty] is used on a semi-auto property when a partial property could be used instead. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer : DiagnosticAnalyzer +{ + /// + /// The number of pooled flags per stack (ie. how many properties we expect on average per type). + /// + private const int NumberOfPooledFlagsPerStack = 20; + + /// + /// Shared pool for instances. + /// + [SuppressMessage("MicrosoftCodeAnalysisPerformance", "RS1008", Justification = "This is a pool of (empty) dictionaries, it is not actually storing compilation data.")] + private static readonly ObjectPool> PropertyMapPool = new(static () => new Dictionary(SymbolEqualityComparer.Default)); + + /// + /// Shared pool for -s of flags, one per type being processed. + /// + private static readonly ObjectPool> PropertyFlagsStackPool = new(CreatePropertyFlagsStack); + + /// + /// The property name for the serialized invalidation type. + /// + public const string InvalidationTypePropertyName = "InvalidationType"; + + /// + public override ImmutableArray SupportedDiagnostics { get; } = [UseGeneratedCanvasEffectPropertyOnSemiAutoProperty]; + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterCompilationStartAction(static context => + { + // Using [GeneratedCanvasEffectProperty] on partial properties is only supported when using C# preview. + // As such, if that is not the case, return immediately, as no diagnostic should be produced. + if (!context.Compilation.IsLanguageVersionPreview()) + { + return; + } + + // Get the [GeneratedCanvasEffectProperty] and CanvasEffect symbols + if (context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.GeneratedCanvasEffectPropertyAttribute) is not { } generatedCanvasEffectPropertyAttributeSymbol || + context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.CanvasEffect) is not { } canvasEffectSymbol) + { + return; + } + + // Get the symbol for the SetPropertyAndInvalidateEffectGraph method as well + if (!TryGetSetPropertyMethodSymbol(canvasEffectSymbol, out IMethodSymbol? setPropertySymbol)) + { + return; + } + + context.RegisterSymbolStartAction(context => + { + // We only care about types that could derive from ObservableObject + if (context.Symbol is not INamedTypeSymbol { IsStatic: false, IsReferenceType: true, BaseType.SpecialType: not SpecialType.System_Object } typeSymbol) + { + return; + } + + // If the type does not derive from ObservableObject, ignore it + if (!typeSymbol.InheritsFromType(canvasEffectSymbol)) + { + return; + } + + Dictionary propertyMap = PropertyMapPool.Allocate(); + Stack propertyFlagsStack = PropertyFlagsStackPool.Allocate(); + + // Crawl all members to discover properties that might be of interest + foreach (ISymbol memberSymbol in typeSymbol.GetMembers()) + { + // We're only looking for properties that might be valid candidates for conversion + if (memberSymbol is not IPropertySymbol + { + IsStatic: false, + IsPartialDefinition: false, + PartialDefinitionPart: null, + PartialImplementationPart: null, + ReturnsByRef: false, + ReturnsByRefReadonly: false, + Type.IsRefLikeType: false, + GetMethod: not null, + SetMethod.IsInitOnly: false + } propertySymbol) + { + continue; + } + + // We can safely ignore properties that already have [GeneratedCanvasEffectProperty]. + // This is because in that case, the other analyzer will already emit an error. + if (propertySymbol.HasAttributeWithType(generatedCanvasEffectPropertyAttributeSymbol)) + { + continue; + } + + // Take an array from the stack or create a new one otherwise + byte[] flags = propertyFlagsStack.Count > 0 + ? propertyFlagsStack.Pop() + : new byte[2]; + + // Track the property for later + propertyMap.Add(propertySymbol, flags); + } + + // We want to process both accessors, where we specifically need both the syntax + // and their semantic model to verify what they're doing. We can use a code callback. + context.RegisterOperationBlockAction(context => + { + // Make sure the current symbol is a property accessor + if (context.OwningSymbol is not IMethodSymbol { MethodKind: MethodKind.PropertyGet or MethodKind.PropertySet, AssociatedSymbol: IPropertySymbol propertySymbol }) + { + return; + } + + // If so, check that we are actually processing one of the properties we care about + if (!propertyMap.TryGetValue(propertySymbol, out byte[]? validFlags)) + { + return; + } + + // Handle the 'get' logic + if (SymbolEqualityComparer.Default.Equals(propertySymbol.GetMethod, context.OwningSymbol)) + { + // We expect a top-level block operation, that immediately returns an expression + if (context.OperationBlocks is not [IBlockOperation { Operations: [IReturnOperation returnOperation] }]) + { + return; + } + + // Next, we expect the return to produce a field reference + if (returnOperation is not { ReturnedValue: IFieldReferenceOperation fieldReferenceOperation }) + { + return; + } + + // The field has to be implicitly declared and not constant (and not static) + if (fieldReferenceOperation.Field is not { IsImplicitlyDeclared: true, IsStatic: false } fieldSymbol) + { + return; + } + + // Validate tha the field is indeed 'field' (it will be associated with the property) + if (!SymbolEqualityComparer.Default.Equals(fieldSymbol.AssociatedSymbol, propertySymbol)) + { + return; + } + + // The 'get' accessor is valid + validFlags[0] = 1; + } + else if (SymbolEqualityComparer.Default.Equals(propertySymbol.SetMethod, context.OwningSymbol)) + { + // We expect a top-level block operation, that immediately performs an invocation + if (context.OperationBlocks is not [IBlockOperation { Operations: [IExpressionStatementOperation { Operation: IInvocationOperation invocationOperation }] }]) + { + return; + } + + // Brief filtering of the target method, also get the original definition + if (invocationOperation.TargetMethod is not { Name: "SetPropertyAndInvalidateEffectGraph", IsGenericMethod: true, IsStatic: false } methodSymbol) + { + return; + } + + // First, check that we're calling 'CanvasEffect.SetPropertyAndInvalidateEffectGraph' + if (!SymbolEqualityComparer.Default.Equals(methodSymbol.ConstructedFrom, setPropertySymbol)) + { + return; + } + + // We matched the method, now let's validate the arguments + if (invocationOperation.Arguments is not [{ } locationArgument, { } valueArgument, { } invalidationTypeArgument]) + { + return; + } + + // The field has to be implicitly declared and not constant (and not static) + if (locationArgument.Value is not IFieldReferenceOperation { Field: { IsImplicitlyDeclared: true, IsStatic: false } fieldSymbol }) + { + return; + } + + // Validate tha the field is indeed 'field' (it will be associated with the property) + if (!SymbolEqualityComparer.Default.Equals(fieldSymbol.AssociatedSymbol, propertySymbol)) + { + return; + } + + // The value is just the 'value' keyword + if (valueArgument.Value is not IParameterReferenceOperation { Syntax: IdentifierNameSyntax { Identifier.Text: "value" } }) + { + return; + } + + // The invalidation mode can either be the default value... + if (invalidationTypeArgument is { IsImplicit: true, ArgumentKind: ArgumentKind.DefaultValue }) + { + validFlags[1] = 1; + } + else if (invalidationTypeArgument is { Value.ConstantValue: { HasValue: true, Value: byte mode } } && mode is 0 or 1) + { + // ...Or is has to be set explicitly to one of the two supported values + validFlags[1] = (byte)(mode + 1); + } + } + }); + + // We also need to track getters which have no body, and we need syntax for that + context.RegisterSyntaxNodeAction(context => + { + // Let's just make sure we do have a property symbol + if (context.ContainingSymbol is not IPropertySymbol { GetMethod: not null } propertySymbol) + { + return; + } + + // Lookup the property to get its flags + if (!propertyMap.TryGetValue(propertySymbol, out byte[]? validFlags)) + { + return; + } + + // We expect two accessors, skip if otherwise (the setter will be validated by the other callback) + if (context.Node is not PropertyDeclarationSyntax { AccessorList.Accessors: [{ } firstAccessor, { } secondAccessor] }) + { + return; + } + + // Check that either of them is a semicolon token 'get;' accessor (it can be in either position) + if ((firstAccessor.IsKind(SyntaxKind.GetAccessorDeclaration) && + firstAccessor.SemicolonToken.IsKind(SyntaxKind.SemicolonToken) && + firstAccessor.ExpressionBody is null) || + (secondAccessor.IsKind(SyntaxKind.GetAccessorDeclaration) && + secondAccessor.SemicolonToken.IsKind(SyntaxKind.SemicolonToken) && + secondAccessor.ExpressionBody is null)) + { + validFlags[0] = 1; + } + }, SyntaxKind.PropertyDeclaration); + + // Finally, we can consume this information when we finish processing the symbol + context.RegisterSymbolEndAction(context => + { + // Emit a diagnostic for each property that was a valid match + foreach (KeyValuePair pair in propertyMap) + { + if (pair.Value is [1, 1 or 2]) + { + // Shift back the index to match the actual enum values, to simplify the code fixer. Here we're adding 1 to + // signal "the setter is valid", but we want to hide this implementation detail to downstream consumers. + int invalidationType = pair.Value[1] - 1; + + context.ReportDiagnostic(Diagnostic.Create( + UseGeneratedCanvasEffectPropertyOnSemiAutoProperty, + pair.Key.Locations.FirstOrDefault(), + ImmutableDictionary.Create().Add(InvalidationTypePropertyName, invalidationType.ToString()), + pair.Key)); + } + } + + // Before clearing the dictionary, move back all values to the stack + foreach (byte[] propertyFlags in propertyMap.Values) + { + // Make sure the array is cleared before returning it + propertyFlags.AsSpan().Clear(); + + propertyFlagsStack.Push(propertyFlags); + } + + // We are now done processing the symbol, we can return the dictionary. + // Note that we must clear it before doing so to avoid leaks and issues. + propertyMap.Clear(); + + PropertyMapPool.Free(propertyMap); + + // Also do the same for the stack, except we don't need to clean it (since it roots no compilation objects) + PropertyFlagsStackPool.Free(propertyFlagsStack); + }); + }, SymbolKind.NamedType); + }); + } + + /// + /// Tries to get the symbol for the target SetPropertyAndInvalidateEffectGraph method this analyzer looks for. + /// + /// The symbol for CanvasEffect. + /// The resulting method symbol, if found (this should always be the case). + /// Whether could be resolved correctly. + private static bool TryGetSetPropertyMethodSymbol(INamedTypeSymbol canvasEffectSymbol, [NotNullWhen(true)] out IMethodSymbol? setPropertySymbol) + { + foreach (ISymbol symbol in canvasEffectSymbol.GetMembers("SetPropertyAndInvalidateEffectGraph")) + { + // There's only one method with this name, so we can just return it directly + setPropertySymbol = (IMethodSymbol)symbol; + + return true; + } + + setPropertySymbol = null; + + return false; + } + + /// + /// Produces a new instance to pool. + /// + /// The resulting instance to use. + private static Stack CreatePropertyFlagsStack() + { + static IEnumerable EnumerateFlags() + { + for (int i = 0; i < NumberOfPooledFlagsPerStack; i++) + { + yield return new byte[2]; + } + } + + return new(EnumerateFlags()); + } +} \ No newline at end of file diff --git a/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs b/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs index 4a745df32..8c0623325 100644 --- a/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs +++ b/src/ComputeSharp.D2D1.UI.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs @@ -31,6 +31,11 @@ internal static class DiagnosticDescriptors "ComputeSharp.D2D1.WinUI.Effects"; #endif + /// + /// The diagnostic id for . + /// + public const string UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyId = $"{DiagnosticIdPrefix}0008"; + /// /// Gets a for an invalid CanvasEffect property. /// @@ -142,4 +147,20 @@ internal static class DiagnosticDescriptors isEnabledByDefault: true, description: "The C# language version must be set to 'preview' when using [GeneratedComputeShaderDescriptor] for the source generators to emit valid code (the preview option must be set in the .csproj/.props file).", helpLinkUri: "https://github.com/Sergio0694/ComputeSharp"); + + /// + /// Gets a for when a semi-auto property can be converted to use [GeneratedCanvasEffectProperty] instead. + /// + /// Format: "The semi-auto property "{0}" can be converted to a partial property using [GeneratedCanvasEffectProperty], which is recommended (doing so makes the code less verbose and results in more optimized code)". + /// + /// + public static readonly DiagnosticDescriptor UseGeneratedCanvasEffectPropertyOnSemiAutoProperty = new( + id: UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyId, + title: "Prefer using [GeneratedCanvasEffectProperty] over semi-auto properties", + messageFormat: """The semi-auto property "{0}" can be converted to a partial property using [GeneratedCanvasEffectProperty], which is recommended (doing so makes the code less verbose and results in more optimized code)""", + category: DiagnosticCategory, + defaultSeverity: DiagnosticSeverity.Info, + isEnabledByDefault: true, + description: "Semi-auto properties should be converted to partial properties using [GeneratedCanvasEffectProperty] when possible, which is recommended (doing so makes the code less verbose and results in more optimized code).", + helpLinkUri: "https://github.com/Sergio0694/ComputeSharp"); } \ No newline at end of file diff --git a/src/ComputeSharp.D2D1.Uwp.CodeFixers/ComputeSharp.D2D1.Uwp.CodeFixers.csproj b/src/ComputeSharp.D2D1.Uwp.CodeFixers/ComputeSharp.D2D1.Uwp.CodeFixers.csproj new file mode 100644 index 000000000..725f187a7 --- /dev/null +++ b/src/ComputeSharp.D2D1.Uwp.CodeFixers/ComputeSharp.D2D1.Uwp.CodeFixers.csproj @@ -0,0 +1,16 @@ + + + netstandard2.0 + $(DefineConstants);WINDOWS_UWP;D2D1_UI_SOURCE_GENERATOR + + + + + + + + + + + + diff --git a/src/ComputeSharp.D2D1.Uwp.SourceGenerators/AnalyzerReleases.Shipped.md b/src/ComputeSharp.D2D1.Uwp.SourceGenerators/AnalyzerReleases.Shipped.md index 8c38544e6..d1feb69ca 100644 --- a/src/ComputeSharp.D2D1.Uwp.SourceGenerators/AnalyzerReleases.Shipped.md +++ b/src/ComputeSharp.D2D1.Uwp.SourceGenerators/AnalyzerReleases.Shipped.md @@ -14,3 +14,4 @@ CMPSD2DUWP0004 | ComputeSharp.D2D1.Uwp.Effects | Error | [Documentation](https:/ CMPSD2DUWP0005 | ComputeSharp.D2D1.Uwp.Effects | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp) CMPSD2DUWP0006 | ComputeSharp.D2D1.Uwp.Effects | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp) CMPSD2DUWP0007 | ComputeSharp.D2D1.Uwp.Effects | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp) +CMPSD2DUWP0008 | ComputeSharp.D2D1.Uwp.Effects | Info | [Documentation](https://github.com/Sergio0694/ComputeSharp) diff --git a/src/ComputeSharp.D2D1.Uwp.SourceGenerators/ComputeSharp.D2D1.Uwp.SourceGenerators.csproj b/src/ComputeSharp.D2D1.Uwp.SourceGenerators/ComputeSharp.D2D1.Uwp.SourceGenerators.csproj index 2500e6831..29b983fce 100644 --- a/src/ComputeSharp.D2D1.Uwp.SourceGenerators/ComputeSharp.D2D1.Uwp.SourceGenerators.csproj +++ b/src/ComputeSharp.D2D1.Uwp.SourceGenerators/ComputeSharp.D2D1.Uwp.SourceGenerators.csproj @@ -8,7 +8,7 @@ - + @@ -18,4 +18,9 @@ + + + + + diff --git a/src/ComputeSharp.D2D1.Uwp/ComputeSharp.D2D1.Uwp.targets b/src/ComputeSharp.D2D1.Uwp/ComputeSharp.D2D1.Uwp.targets index 976c3a7ca..6ce36516b 100644 --- a/src/ComputeSharp.D2D1.Uwp/ComputeSharp.D2D1.Uwp.targets +++ b/src/ComputeSharp.D2D1.Uwp/ComputeSharp.D2D1.Uwp.targets @@ -7,7 +7,7 @@ - + @(ComputeSharpD2D1UwpCurrentCompilerAssemblyIdentity->'%(Version)') - true + true - + - + + diff --git a/src/ComputeSharp.D2D1.WinUI.CodeFixers/ComputeSharp.D2D1.WinUI.CodeFixers.csproj b/src/ComputeSharp.D2D1.WinUI.CodeFixers/ComputeSharp.D2D1.WinUI.CodeFixers.csproj new file mode 100644 index 000000000..f305ea879 --- /dev/null +++ b/src/ComputeSharp.D2D1.WinUI.CodeFixers/ComputeSharp.D2D1.WinUI.CodeFixers.csproj @@ -0,0 +1,16 @@ + + + netstandard2.0 + $(DefineConstants);D2D1_UI_SOURCE_GENERATOR + + + + + + + + + + + + diff --git a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/AnalyzerReleases.Shipped.md b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/AnalyzerReleases.Shipped.md index a67085fd6..6573ce3d2 100644 --- a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/AnalyzerReleases.Shipped.md +++ b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/AnalyzerReleases.Shipped.md @@ -14,3 +14,4 @@ CMPSD2DWINUI0004 | ComputeSharp.D2D1.WinUI.Effects | Error | [Documentation](htt CMPSD2DWINUI0005 | ComputeSharp.D2D1.WinUI.Effects | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp) CMPSD2DWINUI0006 | ComputeSharp.D2D1.WinUI.Effects | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp) CMPSD2DWINUI0007 | ComputeSharp.D2D1.WinUI.Effects | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp) +CMPSD2DWINUI0008 | ComputeSharp.D2D1.WinUI.Effects | Info | [Documentation](https://github.com/Sergio0694/ComputeSharp) diff --git a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/ComputeSharp.D2D1.WinUI.SourceGenerators.csproj b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/ComputeSharp.D2D1.WinUI.SourceGenerators.csproj index 1781f0d7c..338ece165 100644 --- a/src/ComputeSharp.D2D1.WinUI.SourceGenerators/ComputeSharp.D2D1.WinUI.SourceGenerators.csproj +++ b/src/ComputeSharp.D2D1.WinUI.SourceGenerators/ComputeSharp.D2D1.WinUI.SourceGenerators.csproj @@ -8,7 +8,7 @@ - + @@ -18,4 +18,9 @@ + + + + + diff --git a/src/ComputeSharp.D2D1.WinUI/ComputeSharp.D2D1.WinUI.targets b/src/ComputeSharp.D2D1.WinUI/ComputeSharp.D2D1.WinUI.targets index e178811f9..792dd290b 100644 --- a/src/ComputeSharp.D2D1.WinUI/ComputeSharp.D2D1.WinUI.targets +++ b/src/ComputeSharp.D2D1.WinUI/ComputeSharp.D2D1.WinUI.targets @@ -7,7 +7,7 @@ - + @(ComputeSharpD2D1WinUICurrentCompilerAssemblyIdentity->'%(Version)') - true + true - + - + + diff --git a/src/ComputeSharp.D2D1/ComputeSharp.D2D1.targets b/src/ComputeSharp.D2D1/ComputeSharp.D2D1.targets index 6e684e620..7b6a59ac9 100644 --- a/src/ComputeSharp.D2D1/ComputeSharp.D2D1.targets +++ b/src/ComputeSharp.D2D1/ComputeSharp.D2D1.targets @@ -42,7 +42,7 @@ emitting this manually lets us customize the message to inform developers as to why exactly the generators have been disabled, and that ComputeSharp will not work at all unless a more up to date IDE or compiler version are used. --> - + diff --git a/src/ComputeSharp/ComputeSharp.targets b/src/ComputeSharp/ComputeSharp.targets index c4a233093..566b5c97a 100644 --- a/src/ComputeSharp/ComputeSharp.targets +++ b/src/ComputeSharp/ComputeSharp.targets @@ -42,7 +42,7 @@ emitting this manually lets us customize the message to inform developers as to why exactly the generators have been disabled, and that ComputeSharp will not work at all unless a more up to date IDE or compiler version are used. --> - + diff --git a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/ComputeSharp.D2D1.Tests.SourceGenerators.csproj b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/ComputeSharp.D2D1.Tests.SourceGenerators.csproj index 479f672ef..ebee105a0 100644 --- a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/ComputeSharp.D2D1.Tests.SourceGenerators.csproj +++ b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/ComputeSharp.D2D1.Tests.SourceGenerators.csproj @@ -19,7 +19,7 @@ - + @@ -30,7 +30,7 @@ - + diff --git a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator.cs b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator.cs index c49e2d724..ec2379b31 100644 --- a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator.cs +++ b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator.cs @@ -1780,25 +1780,25 @@ file static class Data /// The task for the operation. private static async Task VerifyGeneratedDiagnosticsAsync(string source, (string Filename, string Source) result) { - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); CSharpGeneratorTest.VerifySources(source, result); } diff --git a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator_Analyzers.cs b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator_Analyzers.cs index fa1d3ccc8..71a93b3d6 100644 --- a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator_Analyzers.cs +++ b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderDescriptorGenerator_Analyzers.cs @@ -25,7 +25,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, allowUnsafeBlocks: false); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, allowUnsafeBlocks: false); } [TestMethod] @@ -44,7 +44,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -112,7 +112,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -135,7 +135,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -156,7 +156,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -171,7 +171,7 @@ internal partial struct MyType } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -191,7 +191,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -214,7 +214,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -235,7 +235,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -257,7 +257,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -280,7 +280,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -304,7 +304,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -328,7 +328,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -351,7 +351,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -364,7 +364,7 @@ public async Task UnnecessaryD2DEnableRuntimeCompilation_OnAssembly_Warns() [assembly: {|CMPSD2D0079:D2DEnableRuntimeCompilation|}] """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -388,7 +388,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -411,7 +411,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -433,7 +433,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -466,7 +466,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -489,7 +489,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -515,7 +515,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -538,7 +538,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -564,7 +564,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -590,7 +590,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -628,7 +628,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -640,7 +640,7 @@ public async Task InvalidPackMatrixColumnMajorOption_AssemblyLevel_WithColumnMaj [assembly: {|CMPSD2D0044:D2DCompileOptions(D2D1CompileOptions.PackMatrixColumnMajor)|}] """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -661,7 +661,7 @@ public Float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -752,7 +752,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -773,7 +773,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -793,7 +793,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -814,7 +814,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -837,7 +837,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -859,7 +859,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -882,7 +882,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -910,7 +910,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -929,7 +929,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -952,7 +952,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -975,7 +975,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -999,7 +999,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1029,7 +1029,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1053,7 +1053,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1077,7 +1077,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1103,7 +1103,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1135,7 +1135,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1156,7 +1156,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1178,7 +1178,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1200,7 +1200,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1220,7 +1220,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1239,7 +1239,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1260,7 +1260,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1288,7 +1288,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1311,7 +1311,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1331,7 +1331,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1354,7 +1354,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1374,7 +1374,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1403,7 +1403,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1430,7 +1430,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1460,7 +1460,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1481,7 +1481,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1508,7 +1508,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1536,7 +1536,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -1562,6 +1562,6 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } } \ No newline at end of file diff --git a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderSourceGenerator_Analyzers.cs b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderSourceGenerator_Analyzers.cs index 840b97131..1206ba94e 100644 --- a/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderSourceGenerator_Analyzers.cs +++ b/tests/ComputeSharp.D2D1.Tests.SourceGenerators/Test_D2DPixelShaderSourceGenerator_Analyzers.cs @@ -33,7 +33,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -69,7 +69,7 @@ public unsafe partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -98,7 +98,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -128,7 +128,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -156,7 +156,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -185,7 +185,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -215,7 +215,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -243,7 +243,7 @@ public partial class MyClass } """"; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -262,6 +262,6 @@ public partial class MyClass } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } } \ No newline at end of file diff --git a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators.csproj b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators.csproj index a053cda57..31d6a4c29 100644 --- a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators.csproj +++ b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators.csproj @@ -18,18 +18,19 @@ - + + - + diff --git a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Helpers/CSharpCodeFixerTest{TAnalyzer,TCodeFixer}.cs b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Helpers/CSharpCodeFixerTest{TAnalyzer,TCodeFixer}.cs new file mode 100644 index 000000000..54e832426 --- /dev/null +++ b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Helpers/CSharpCodeFixerTest{TAnalyzer,TCodeFixer}.cs @@ -0,0 +1,42 @@ +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Testing; + +#pragma warning disable IDE0290 + +namespace ComputeSharp.Tests.SourceGenerators.Helpers; + +/// +/// A custom that uses a specific C# language version to parse code. +/// +/// The type of the analyzer to produce diagnostics. +/// The type of code fix to test. +internal sealed class CSharpCodeFixTest : CSharpCodeFixTest + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFixer : CodeFixProvider, new() +{ + /// + /// The C# language version to use to parse code. + /// + private readonly LanguageVersion languageVersion; + + /// + /// Creates a new instance with the specified parameters. + /// + /// The C# language version to use to parse code. + public CSharpCodeFixTest(LanguageVersion languageVersion) + { + this.languageVersion = languageVersion; + + TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "[*]\nend_of_line = lf")); + } + + /// + protected override ParseOptions CreateParseOptions() + { + return new CSharpParseOptions(this.languageVersion, DocumentationMode.Diagnose); + } +} 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 72ff08143..0b2196c94 100644 --- a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_CanvasEffectPropertyGenerator_Analyzers.cs +++ b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_CanvasEffectPropertyGenerator_Analyzers.cs @@ -22,7 +22,7 @@ public partial class MyEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -38,7 +38,7 @@ public partial class MyEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -54,7 +54,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -70,7 +70,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -86,7 +86,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -104,7 +104,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -124,7 +124,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -142,7 +142,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -158,7 +158,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -174,7 +174,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -191,7 +191,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } [TestMethod] @@ -208,7 +208,7 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -225,6 +225,233 @@ public abstract partial class MyEffect : CanvasEffect } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_NormalProperty_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string Name { get; set; } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_SimilarProperty_NotObservableObject_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : MyBaseCanvasEffect + { + public string Name + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + + public abstract class MyBaseCanvasEffect + { + protected void SetPropertyAndInvalidateEffectGraph(ref T location, T value, CanvasEffectInvalidationType invalidationType = CanvasEffectInvalidationType.Update) + { + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_NoGetter_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string Name + { + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_NoSetter_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string Name + { + get => field; + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_OtherLocation_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string Name + { + get => field; + set + { + string test = field; + + SetPropertyAndInvalidateEffectGraph(ref test, value); + } + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_OtherValue_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string Name + { + get => field; + set + { + string test = "Bob"; + + SetPropertyAndInvalidateEffectGraph(ref field, test); + } + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_ValidProperty_WithGeneratedCanvasEffectProperty_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + public string Name + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_GetAccessorWithExpressionBody_DoesNotWarn() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string Name + { + get => "Hello world"; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_ValidProperty_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public string {|CMPSD2DWINUI0008:Name|} + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_ValidProperty_WithModifiers_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public new string {|CMPSD2DWINUI0008:Name|} + { + get => field; + private set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); + } + + [TestMethod] + public async Task UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer_ValidProperty_WithBlocks_Warns() + { + const string source = """ + using ComputeSharp.D2D1.WinUI; + + public abstract partial class SampleCanvasEffect : CanvasEffect + { + public new string {|CMPSD2DWINUI0008:Name|} + { + get + { + return field; + } + private set + { + SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + } + """; + + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, languageVersion: LanguageVersion.Preview); } } \ No newline at end of file diff --git a/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer.cs b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer.cs new file mode 100644 index 000000000..33ecd76c6 --- /dev/null +++ b/tests/ComputeSharp.D2D1.WinUI.Tests.SourceGenerators/Test_UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer.cs @@ -0,0 +1,767 @@ +extern alias Core; +extern alias D2D1_WinUI; +extern alias D2D1; + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.UI.Xaml.Controls; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Windows.Foundation; +using Windows.UI.ViewManagement; +using CSharpCodeFixTest = ComputeSharp.Tests.SourceGenerators.Helpers.CSharpCodeFixTest< + ComputeSharp.D2D1.WinUI.SourceGenerators.UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer, + ComputeSharp.D2D1.WinUI.SourceGenerators.UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer>; + +namespace ComputeSharp.D2D1.WinUI.Tests.SourceGenerators; + +[TestClass] +public class Test_UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyCodeFixer +{ + [TestMethod] + [DataRow("get;")] + [DataRow("get => field;")] + public async Task SimpleProperty_ImplicitInvalidationType(string getAccessor) + { + string original = $$""" + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + public string? [|Name|] + { + {{getAccessor}} + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + [DataRow("get;")] + [DataRow("get => field;")] + public async Task SimpleProperty_InvalidationTypeUpdate(string getAccessor) + { + string original = $$""" + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + public string? [|Name|] + { + {{getAccessor}} + set => SetPropertyAndInvalidateEffectGraph(ref field, value, CanvasEffectInvalidationType.Update); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + [DataRow("get;")] + [DataRow("get => field;")] + public async Task SimpleProperty_InvalidationTypeCreation(string getAccessor) + { + string original = $$""" + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + public string? [|Name|] + { + {{getAccessor}} + set => SetPropertyAndInvalidateEffectGraph(ref field, value, CanvasEffectInvalidationType.Creation); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty(CanvasEffectInvalidationType.Creation)] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_WithMissingUsingDirective() + { + const string original = """ + namespace MyApp; + + public abstract class MyEffect : ComputeSharp.D2D1.WinUI.CanvasEffect + { + public string? [|Name|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : ComputeSharp.D2D1.WinUI.CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_WithLeadingTrivia() + { + const string original = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + /// + /// This is a property. + /// + public string? [|Name|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + /// + /// This is a property. + /// + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_WithLeadingTrivia_AndAttribute() + { + const string original = """ + using System; + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + /// + /// This is a property. + /// + [Test("Targeting property")] + [field: Test("Targeting field")] + public string? [|Name|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + + public class TestAttribute(string text) : Attribute; + """; + + const string @fixed = """ + using System; + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + /// + /// This is a property. + /// + [GeneratedCanvasEffectProperty] + [Test("Targeting property")] + [field: Test("Targeting field")] + public partial string? {|CS9248:Name|} { get; set; } + } + + public class TestAttribute(string text) : Attribute; + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_Multiple() + { + const string original = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + public string? [|FirstName|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + public string? [|LastName|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:FirstName|} { get; set; } + + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:LastName|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_Multiple_OnlyTriggersOnFirstOne() + { + const string original = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + public string? [|FirstName|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + private string? lastName; + + public string? LastName + { + get => this.lastName; + set => SetPropertyAndInvalidateEffectGraph(ref this.lastName, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:FirstName|} { get; set; } + + private string? lastName; + + public string? LastName + { + get => this.lastName; + set => SetPropertyAndInvalidateEffectGraph(ref this.lastName, value); + } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_Multiple_OnlyTriggersOnSecondOne() + { + const string original = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + private string? firstName; + + public string? FirstName + { + get => this.firstName; + set => SetPropertyAndInvalidateEffectGraph(ref this.firstName, value); + } + + public string? [|LastName|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + private string? firstName; + + public string? FirstName + { + get => this.firstName; + set => SetPropertyAndInvalidateEffectGraph(ref this.firstName, value); + } + + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:LastName|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_WithinPartialType() + { + const string original = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + public string? [|Name|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:Name|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_WithMissingUsingDirective_Multiple() + { + const string original = """ + namespace MyApp; + + public abstract class MyEffect : ComputeSharp.D2D1.WinUI.CanvasEffect + { + public string? [|FirstName|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + public string? [|LastName|] + { + get; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + """; + + const string @fixed = """ + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : ComputeSharp.D2D1.WinUI.CanvasEffect + { + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:FirstName|} { get; set; } + + [GeneratedCanvasEffectProperty] + public partial string? {|CS9248:LastName|} { get; set; } + } + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } + + [TestMethod] + public async Task SimpleProperty_Multiple_MixedScenario() + { + const string original = """ + using System; + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract class MyEffect : CanvasEffect + { + [Test("This is an attribute")] + public string [|Prop1|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + // Single comment + public string [|Prop2|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + /// + /// This is a property. + /// + public string [|Prop3|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + /// + /// This is another property. + /// + [Test("Another attribute")] + public string [|Prop4|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + // Some other single comment + [Test("Yet another attribute")] + public string [|Prop5|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + [Test("Attribute without trivia")] + public string [|Prop6|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + + public string [|Prop7|] + { + get => field; + set => SetPropertyAndInvalidateEffectGraph(ref field, value); + } + } + + public class TestAttribute(string text) : Attribute; + """; + + const string @fixed = """ + using System; + using ComputeSharp.D2D1.WinUI; + + namespace MyApp; + + public abstract partial class MyEffect : CanvasEffect + { + [GeneratedCanvasEffectProperty] + [Test("This is an attribute")] + public partial string {|CS9248:Prop1|} { get; set; } + + // Single comment + [GeneratedCanvasEffectProperty] + public partial string {|CS9248:Prop2|} { get; set; } + + /// + /// This is a property. + /// + [GeneratedCanvasEffectProperty] + public partial string {|CS9248:Prop3|} { get; set; } + + /// + /// This is another property. + /// + [GeneratedCanvasEffectProperty] + [Test("Another attribute")] + public partial string {|CS9248:Prop4|} { get; set; } + + // Some other single comment + [GeneratedCanvasEffectProperty] + [Test("Yet another attribute")] + public partial string {|CS9248:Prop5|} { get; set; } + + [GeneratedCanvasEffectProperty] + [Test("Attribute without trivia")] + public partial string {|CS9248:Prop6|} { get; set; } + + [GeneratedCanvasEffectProperty] + public partial string {|CS9248:Prop7|} { get; set; } + } + + public class TestAttribute(string text) : Attribute; + """; + + CSharpCodeFixTest test = new(LanguageVersion.Preview) + { + TestCode = original, + FixedCode = @fixed, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + TestState = { AdditionalReferences = + { + MetadataReference.CreateFromFile(typeof(Point).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ApplicationView).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Button).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1_WinUI::ComputeSharp.D2D1.WinUI.CanvasEffect).Assembly.Location), + MetadataReference.CreateFromFile(typeof(D2D1::ComputeSharp.D2D1.ID2D1PixelShader).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Float4).Assembly.Location) + } } + }; + + await test.RunAsync(); + } +} diff --git a/tests/ComputeSharp.Tests.SourceGenerators/ComputeSharp.Tests.SourceGenerators.csproj b/tests/ComputeSharp.Tests.SourceGenerators/ComputeSharp.Tests.SourceGenerators.csproj index 77c046aa8..04f866bc0 100644 --- a/tests/ComputeSharp.Tests.SourceGenerators/ComputeSharp.Tests.SourceGenerators.csproj +++ b/tests/ComputeSharp.Tests.SourceGenerators/ComputeSharp.Tests.SourceGenerators.csproj @@ -12,7 +12,7 @@ - + diff --git a/tests/ComputeSharp.Tests.SourceGenerators/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs b/tests/ComputeSharp.Tests.SourceGenerators/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs similarity index 86% rename from tests/ComputeSharp.Tests.SourceGenerators/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs rename to tests/ComputeSharp.Tests.SourceGenerators/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs index 11cfc23f5..9cf93ad12 100644 --- a/tests/ComputeSharp.Tests.SourceGenerators/Helpers/CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs +++ b/tests/ComputeSharp.Tests.SourceGenerators/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs @@ -22,7 +22,7 @@ namespace ComputeSharp.Tests.SourceGenerators.Helpers; /// A custom that uses a specific C# language version to parse code. /// /// The type of the analyzer to test. -internal sealed class CSharpAnalyzerWithLanguageVersionTest : CSharpAnalyzerTest +internal sealed class CSharpAnalyzerTest : CSharpAnalyzerTest where TAnalyzer : DiagnosticAnalyzer, new() { /// @@ -36,11 +36,11 @@ internal sealed class CSharpAnalyzerWithLanguageVersionTest : CSharpA private readonly LanguageVersion languageVersion; /// - /// Creates a new instance with the specified paramaters. + /// Creates a new instance with the specified paramaters. /// /// Whether to enable unsafe blocks. /// The C# language version to use to parse code. - private CSharpAnalyzerWithLanguageVersionTest(bool allowUnsafeBlocks, LanguageVersion languageVersion) + private CSharpAnalyzerTest(bool allowUnsafeBlocks, LanguageVersion languageVersion) { this.allowUnsafeBlocks = allowUnsafeBlocks; this.languageVersion = languageVersion; @@ -67,7 +67,7 @@ public static Task VerifyAnalyzerAsync( bool allowUnsafeBlocks = true, LanguageVersion languageVersion = LanguageVersion.CSharp12) { - CSharpAnalyzerWithLanguageVersionTest test = new(allowUnsafeBlocks, languageVersion) { TestCode = source }; + CSharpAnalyzerTest test = new(allowUnsafeBlocks, languageVersion) { TestCode = source }; test.TestState.ReferenceAssemblies = ReferenceAssemblies.Net.Net80; test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(Core::ComputeSharp.Hlsl).Assembly.Location)); diff --git a/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator.cs b/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator.cs index 3f9c5fe9c..9c420dc41 100644 --- a/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator.cs +++ b/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator.cs @@ -864,18 +864,18 @@ protected override void Dispose(bool disposing) /// The task for the operation. private static async Task VerifyGeneratedDiagnosticsAsync(string source, (string Filename, string Source) result) { - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); CSharpGeneratorTest.VerifySources(source, result); } diff --git a/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator_Analyzers.cs b/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator_Analyzers.cs index 67f65a418..f4c7f5932 100644 --- a/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator_Analyzers.cs +++ b/tests/ComputeSharp.Tests.SourceGenerators/Test_ComputeShaderDescriptorGenerator_Analyzers.cs @@ -26,7 +26,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source, allowUnsafeBlocks: false); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source, allowUnsafeBlocks: false); } [TestMethod] @@ -45,7 +45,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -64,7 +64,7 @@ public float4 Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -110,7 +110,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -135,7 +135,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -166,7 +166,7 @@ private struct Bar } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -187,7 +187,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -205,7 +205,7 @@ internal partial struct MyType } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -227,7 +227,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -249,7 +249,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -271,7 +271,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -289,7 +289,7 @@ internal partial struct MyType } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -311,7 +311,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -333,7 +333,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -355,7 +355,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -370,7 +370,7 @@ internal partial struct MyType } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -388,7 +388,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -409,7 +409,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -432,7 +432,7 @@ Float4 IComputeShader.Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -449,7 +449,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -467,7 +467,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -485,7 +485,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -503,7 +503,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -521,7 +521,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -546,7 +546,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -564,7 +564,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -630,7 +630,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -655,7 +655,7 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } [TestMethod] @@ -720,6 +720,6 @@ public void Execute() } """; - await CSharpAnalyzerWithLanguageVersionTest.VerifyAnalyzerAsync(source); + await CSharpAnalyzerTest.VerifyAnalyzerAsync(source); } } \ No newline at end of file