diff --git a/.editorconfig b/.editorconfig index 1592c6e58bf..e4e7e031444 100644 --- a/.editorconfig +++ b/.editorconfig @@ -231,10 +231,6 @@ dotnet_diagnostic.CA1822.severity = warning # Increase visibility for Member 'xx dotnet_diagnostic.CS8785.severity = error # Do not hide root cause for: Generator 'xxx' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'xxx' with message 'xxx' dotnet_diagnostic.RS2008.severity = none # Enable analyzer release tracking - we don't use the release tracking analyzer -# This should be removed in https://github.com/SonarSource/sonar-dotnet/issues/3364 -# RS1010: Provide an explicit argument for optional parameter 'equivalenceKey', which is non-null and unique across all code actions created by this fixer. -dotnet_diagnostic.RS1010.severity = none - # ---------------------------------------------------------------------------------------------------------------------- # SyleCop.Analyzers rules - note that the URLs below are for tag 1.1.118 # ---------------------------------------------------------------------------------------------------------------------- diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanCheckInvertedCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanCheckInvertedCodeFix.cs index c009a152a02..39955ae1e7b 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanCheckInvertedCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanCheckInvertedCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -36,7 +35,7 @@ public override ImmutableArray FixableDiagnosticIds } } - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -47,25 +46,24 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var expression = syntaxNode.Operand.RemoveParentheses(); - var newBinary = ChangeOperator((BinaryExpressionSyntax)expression); + Title, + c => + { + var expression = syntaxNode.Operand.RemoveParentheses(); + var newBinary = ChangeOperator((BinaryExpressionSyntax)expression); - if (syntaxNode.Parent is ExpressionSyntax && - !(syntaxNode.Parent is AssignmentExpressionSyntax)) - { - newBinary = SyntaxFactory.ParenthesizedExpression(newBinary); - } + if (syntaxNode.Parent is ExpressionSyntax && + !(syntaxNode.Parent is AssignmentExpressionSyntax)) + { + newBinary = SyntaxFactory.ParenthesizedExpression(newBinary); + } - var newRoot = root.ReplaceNode( - syntaxNode, - newBinary.WithAdditionalAnnotations(Formatter.Annotation)); + var newRoot = root.ReplaceNode( + syntaxNode, + newBinary.WithAdditionalAnnotations(Formatter.Annotation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanLiteralUnnecessaryCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanLiteralUnnecessaryCodeFix.cs index 62ae52b1965..4c22a773777 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanLiteralUnnecessaryCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/BooleanLiteralUnnecessaryCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -31,7 +30,7 @@ public sealed class BooleanLiteralUnnecessaryCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(BooleanLiteralUnnecessary.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -87,72 +86,66 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c return Task.CompletedTask; } - private static void RegisterForStatementConditionRemoval(CodeFixContext context, SyntaxNode root, ForStatementSyntax forStatement) => + private static void RegisterForStatementConditionRemoval(SonarCodeFixContext context, SyntaxNode root, ForStatementSyntax forStatement) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode( - forStatement, - forStatement.WithCondition(null).WithAdditionalAnnotations(Formatter.Annotation)); - - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode( + forStatement, + forStatement.WithCondition(null).WithAdditionalAnnotations(Formatter.Annotation)); + + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); - private static void RegisterBinaryExpressionRemoval(CodeFixContext context, SyntaxNode root, LiteralExpressionSyntax literal, BinaryExpressionSyntax binaryParent) + private static void RegisterBinaryExpressionRemoval(SonarCodeFixContext context, SyntaxNode root, LiteralExpressionSyntax literal, BinaryExpressionSyntax binaryParent) { var otherNode = binaryParent.Left.RemoveParentheses().Equals(literal) ? binaryParent.Right : binaryParent.Left; context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newExpression = GetNegatedExpression(otherNode); - var newRoot = root.ReplaceNode(binaryParent, newExpression - .WithAdditionalAnnotations(Formatter.Annotation)); - - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newExpression = GetNegatedExpression(otherNode); + var newRoot = root.ReplaceNode(binaryParent, newExpression + .WithAdditionalAnnotations(Formatter.Annotation)); + + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } - private static void RegisterConditionalExpressionRewrite(CodeFixContext context, SyntaxNode root, LiteralExpressionSyntax literal, ConditionalExpressionSyntax conditionalParent) => + private static void RegisterConditionalExpressionRewrite(SonarCodeFixContext context, SyntaxNode root, LiteralExpressionSyntax literal, ConditionalExpressionSyntax conditionalParent) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => Task.FromResult(RewriteConditional(context.Document, root, literal, conditionalParent))), + Title, + c => Task.FromResult(RewriteConditional(context.Document, root, literal, conditionalParent)), context.Diagnostics); - private static void RegisterBooleanInversion(CodeFixContext context, SyntaxNode root, LiteralExpressionSyntax literal) => + private static void RegisterBooleanInversion(SonarCodeFixContext context, SyntaxNode root, LiteralExpressionSyntax literal) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => Task.FromResult(RemovePrefixUnary(context.Document, root, literal))), + Title, + c => Task.FromResult(RemovePrefixUnary(context.Document, root, literal)), context.Diagnostics); - private static void RegisterConditionalExpressionRemoval(CodeFixContext context, SyntaxNode root, ConditionalExpressionSyntax conditional) => + private static void RegisterConditionalExpressionRemoval(SonarCodeFixContext context, SyntaxNode root, ConditionalExpressionSyntax conditional) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => Task.FromResult(RemoveConditional(context.Document, root, conditional))), + Title, + c => Task.FromResult(RemoveConditional(context.Document, root, conditional)), context.Diagnostics); - private static void RegisterBinaryExpressionReplacement(CodeFixContext context, SyntaxNode root, SyntaxNode syntaxNode, BinaryExpressionSyntax binary) => + private static void RegisterBinaryExpressionReplacement(SonarCodeFixContext context, SyntaxNode root, SyntaxNode syntaxNode, BinaryExpressionSyntax binary) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var keepThisNode = FindNodeToKeep(binary); - var newRoot = root.ReplaceNode(syntaxNode, keepThisNode - .WithAdditionalAnnotations(Formatter.Annotation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var keepThisNode = FindNodeToKeep(binary); + var newRoot = root.ReplaceNode(syntaxNode, keepThisNode + .WithAdditionalAnnotations(Formatter.Annotation)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); private static SyntaxNode FindNodeToKeep(BinaryExpressionSyntax binary) diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/CatchRethrowCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/CatchRethrowCodeFix.cs index 5da88cb029a..abb03364baa 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/CatchRethrowCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/CatchRethrowCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -28,15 +27,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class CatchRethrowCodeFix : SonarCodeFix { internal const string Title = "Remove redundant catch"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(CatchRethrow.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CatchRethrow.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -48,13 +41,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( Title, c => { var newRoot = CalculateNewRoot(root, syntaxNode, tryStatement); return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/CheckFileLicenseCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/CheckFileLicenseCodeFix.cs index 03674a1bd90..747b2ad02a4 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/CheckFileLicenseCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/CheckFileLicenseCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -29,7 +28,7 @@ public sealed class CheckFileLicenseCodeFix : SonarCodeFix internal const string Title = "Add or update license header"; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(CheckFileLicense.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); if (!diagnostic.Properties.Any() || @@ -48,14 +47,13 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c var syntaxNode = root.FindNode(diagnosticSpan); context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var fileHeaderTrivias = CreateFileHeaderTrivias(diagnostic.Properties[CheckFileLicense.HeaderFormatPropertyKey]); - var newRoot = root.ReplaceNode(syntaxNode, syntaxNode.WithLeadingTrivia(fileHeaderTrivias)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var fileHeaderTrivias = CreateFileHeaderTrivias(diagnostic.Properties[CheckFileLicense.HeaderFormatPropertyKey]); + var newRoot = root.ReplaceNode(syntaxNode, syntaxNode.WithLeadingTrivia(fileHeaderTrivias)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/CollectionEmptinessCheckingCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/CollectionEmptinessCheckingCodeFix.cs index 2b01c04fb9a..c718a43f78a 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/CollectionEmptinessCheckingCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/CollectionEmptinessCheckingCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -33,7 +32,7 @@ public sealed class CollectionEmptinessCheckingCodeFix : SonarCodeFix private readonly CSharpFacade language = CSharpFacade.Instance; - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { if (root.FindNode(context.Diagnostics.First().Location.SourceSpan)?.FirstAncestorOrSelf() is { } binary) { @@ -52,12 +51,13 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c return Task.CompletedTask; } - public static void Simplify(SyntaxNode root, ExpressionSyntax expression, ExpressionSyntax countExpression, CountComparisonResult comparisonResult, CodeFixContext context) => + public static void Simplify(SyntaxNode root, ExpressionSyntax expression, ExpressionSyntax countExpression, CountComparisonResult comparisonResult, SonarCodeFixContext context) => context.RegisterCodeFix( - CodeAction.Create(Title, c => Replacement(root, expression, (InvocationExpressionSyntax)countExpression, comparisonResult, context)), + Title, + c => Replacement(root, expression, (InvocationExpressionSyntax)countExpression, comparisonResult, context), context.Diagnostics); - private static Task Replacement(SyntaxNode root, ExpressionSyntax expression, InvocationExpressionSyntax count, CountComparisonResult comparison, CodeFixContext context) + private static Task Replacement(SyntaxNode root, ExpressionSyntax expression, InvocationExpressionSyntax count, CountComparisonResult comparison, SonarCodeFixContext context) { var any = IsExtension(count) ? AnyFromExtension(count) diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/CommentedOutCodeCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/CommentedOutCodeCodeFix.cs index f445dfbcc0b..6fb21f0c664 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/CommentedOutCodeCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/CommentedOutCodeCodeFix.cs @@ -18,8 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp; @@ -31,17 +29,17 @@ public sealed class CommentedOutCodeCodeFix : SonarCodeFix public override FixAllProvider GetFixAllProvider() => null; - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var comment = root.FindTrivia(diagnostic.Location.SourceSpan.Start, findInsideTrivia: true); if (comment.IsKind(SyntaxKind.SingleLineCommentTrivia) || IsCode(comment)) { - context.RegisterCodeFix(CodeAction.Create( + context.RegisterCodeFix( CommentedOutCode.MessageFormat, - c => new Context(comment).ChangeDocument(context.Document, root)), - diagnostic); + c => new Context(comment).ChangeDocument(context.Document, root), + context.Diagnostics); } return Task.CompletedTask; } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/ConditionalSimplificationCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/ConditionalSimplificationCodeFix.cs index 1e8b760334d..8b18286f14b 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/ConditionalSimplificationCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/ConditionalSimplificationCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -31,7 +30,7 @@ public sealed class ConditionalSimplificationCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(ConditionalSimplification.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var oldNode = root.FindNode(diagnostic.Location.SourceSpan); @@ -44,14 +43,17 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon var newNode = Simplify(diagnostic, semanticModel, oldNode); if (newNode != null) { - context.RegisterCodeFix(CodeAction.Create(Title, c => - { - var replacement = newNode.WithTriviaFrom(oldNode).WithAdditionalAnnotations(Formatter.Annotation); + context.RegisterCodeFix( + Title, + c => + { + var replacement = newNode.WithTriviaFrom(oldNode).WithAdditionalAnnotations(Formatter.Annotation); - var newRoot = root.ReplaceNode(oldNode, replacement); + var newRoot = root.ReplaceNode(oldNode, replacement); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), context.Diagnostics); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyMethodCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyMethodCodeFix.cs index c810502ef4b..92283071206 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyMethodCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyMethodCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -35,7 +34,7 @@ public sealed class EmptyMethodCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(EmptyMethod.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -53,31 +52,29 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon await RegisterCodeFixesForMethodsAsync(context, root, methodBody).ConfigureAwait(false); } - private static async Task RegisterCodeFixesForMethodsAsync(CodeFixContext context, SyntaxNode root, BlockSyntax methodBody) + private static async Task RegisterCodeFixesForMethodsAsync(SonarCodeFixContext context, SyntaxNode root, BlockSyntax methodBody) { context.RegisterCodeFix( - CodeAction.Create( - TitleComment, - c => - { - var newMethodBody = methodBody; - newMethodBody = newMethodBody - .WithOpenBraceToken(newMethodBody.OpenBraceToken - .WithTrailingTrivia(SyntaxFactory.TriviaList() - .Add(SyntaxFactory.EndOfLine(Environment.NewLine)))); + TitleComment, + c => + { + var newMethodBody = methodBody; + newMethodBody = newMethodBody + .WithOpenBraceToken(newMethodBody.OpenBraceToken + .WithTrailingTrivia(SyntaxFactory.TriviaList() + .Add(SyntaxFactory.EndOfLine(Environment.NewLine)))); - newMethodBody = newMethodBody - .WithCloseBraceToken(newMethodBody.CloseBraceToken - .WithLeadingTrivia(SyntaxFactory.TriviaList() - .Add(SyntaxFactory.Comment("// Method intentionally left empty.")) - .Add(SyntaxFactory.EndOfLine(Environment.NewLine)))); + newMethodBody = newMethodBody + .WithCloseBraceToken(newMethodBody.CloseBraceToken + .WithLeadingTrivia(SyntaxFactory.TriviaList() + .Add(SyntaxFactory.Comment("// Method intentionally left empty.")) + .Add(SyntaxFactory.EndOfLine(Environment.NewLine)))); - var newRoot = root.ReplaceNode( - methodBody, - newMethodBody.WithTriviaFrom(methodBody).WithAdditionalAnnotations(Formatter.Annotation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - TitleComment), + var newRoot = root.ReplaceNode( + methodBody, + newMethodBody.WithTriviaFrom(methodBody).WithAdditionalAnnotations(Formatter.Annotation)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); @@ -91,26 +88,24 @@ private static async Task RegisterCodeFixesForMethodsAsync(CodeFixContext contex : SyntaxFactory.IdentifierName(LiteralNotSupportedException); context.RegisterCodeFix( - CodeAction.Create( - TitleThrow, - c => - { - var newRoot = root.ReplaceNode(methodBody, - methodBody.WithStatements( - SyntaxFactory.List( - new StatementSyntax[] - { - SyntaxFactory.ThrowStatement( - SyntaxFactory.ObjectCreationExpression( - memberAccessRoot, - SyntaxFactory.ArgumentList(), - null)) - })) - .WithTriviaFrom(methodBody) - .WithAdditionalAnnotations(Formatter.Annotation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - TitleThrow), + TitleThrow, + c => + { + var newRoot = root.ReplaceNode(methodBody, + methodBody.WithStatements( + SyntaxFactory.List( + new StatementSyntax[] + { + SyntaxFactory.ThrowStatement( + SyntaxFactory.ObjectCreationExpression( + memberAccessRoot, + SyntaxFactory.ArgumentList(), + null)) + })) + .WithTriviaFrom(methodBody) + .WithAdditionalAnnotations(Formatter.Annotation)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyNamespaceCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyNamespaceCodeFix.cs index c75c2bd401c..6578908c3aa 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyNamespaceCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyNamespaceCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class EmptyNamespaceCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(EmptyNamespace.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -43,13 +42,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyStatementCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyStatementCodeFix.cs index 31f39508847..2db6e9b72fe 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyStatementCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/EmptyStatementCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class EmptyStatementCodeFix : SonarCodeFix { internal const string Title = "Remove empty statement"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(EmptyStatement.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(EmptyStatement.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -47,13 +40,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = RemoveUnusedCode(root, syntaxNode); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = RemoveUnusedCode(root, syntaxNode); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/ExceptionRethrowCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/ExceptionRethrowCodeFix.cs index 52fad95924d..c843c14dda8 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/ExceptionRethrowCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/ExceptionRethrowCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class ExceptionRethrowCodeFix : SonarCodeFix { internal const string Title = "Change to 'throw;'"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(ExceptionRethrow.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(ExceptionRethrow.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -46,15 +39,14 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode( - throwStatement, - SyntaxFactory.ThrowStatement().WithTriviaFrom(throwStatement)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode( + throwStatement, + SyntaxFactory.ThrowStatement().WithTriviaFrom(throwStatement)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/FieldShouldBeReadonlyCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/FieldShouldBeReadonlyCodeFix.cs index 91cbe1e45f5..17c6a7795a6 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/FieldShouldBeReadonlyCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/FieldShouldBeReadonlyCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class FieldShouldBeReadonlyCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(FieldShouldBeReadonly.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -50,19 +49,18 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var readonlyToken = SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword); - var newFieldDeclaration = HasAnyAccessibilityModifier(fieldDeclaration) - ? fieldDeclaration.AddModifiers(readonlyToken) - : fieldDeclaration.WithoutLeadingTrivia() - .AddModifiers(readonlyToken.WithLeadingTrivia(fieldDeclaration.GetLeadingTrivia())); + Title, + c => + { + var readonlyToken = SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword); + var newFieldDeclaration = HasAnyAccessibilityModifier(fieldDeclaration) + ? fieldDeclaration.AddModifiers(readonlyToken) + : fieldDeclaration.WithoutLeadingTrivia() + .AddModifiers(readonlyToken.WithLeadingTrivia(fieldDeclaration.GetLeadingTrivia())); - var newRoot = root.ReplaceNode(fieldDeclaration, newFieldDeclaration); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + var newRoot = root.ReplaceNode(fieldDeclaration, newFieldDeclaration); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/ForeachLoopExplicitConversionCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/ForeachLoopExplicitConversionCodeFix.cs index 2c0b4670af5..98344ec0980 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/ForeachLoopExplicitConversionCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/ForeachLoopExplicitConversionCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -31,7 +30,7 @@ public sealed class ForeachLoopExplicitConversionCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(ForeachLoopExplicitConversion.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -47,13 +46,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (enumerableHelperType != null) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = CalculateNewRoot(root, foreachSyntax, semanticModel); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = CalculateNewRoot(root, foreachSyntax, semanticModel); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericReadonlyFieldPropertyAssignmentCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericReadonlyFieldPropertyAssignmentCodeFix.cs index 5c2c8485713..3cd42ab19ca 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericReadonlyFieldPropertyAssignmentCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericReadonlyFieldPropertyAssignmentCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -34,7 +33,7 @@ public sealed class GenericReadonlyFieldPropertyAssignmentCodeFix : SonarCodeFix private static readonly SyntaxAnnotation Annotation = new(nameof(GenericReadonlyFieldPropertyAssignmentCodeFix)); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -56,38 +55,34 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon if (classDeclarations.Any()) { context.RegisterCodeFix( - CodeAction.Create( - TitleAddClassConstraint, - async c => + TitleAddClassConstraint, + async c => + { + var currentSolution = context.Document.Project.Solution; + var mapping = GetDocumentIdClassDeclarationMapping(classDeclarations, currentSolution); + + foreach (var classes in mapping) { - var currentSolution = context.Document.Project.Solution; - var mapping = GetDocumentIdClassDeclarationMapping(classDeclarations, currentSolution); - - foreach (var classes in mapping) - { - var document = currentSolution.GetDocument(classes.Key); - var docRoot = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var newDocRoot = GetNewDocumentRoot(docRoot, typeParameterSymbol, classes); - currentSolution = currentSolution.WithDocumentSyntaxRoot(classes.Key, newDocRoot); - } - - return currentSolution; - }, - TitleAddClassConstraint), + var document = currentSolution.GetDocument(classes.Key); + var docRoot = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var newDocRoot = GetNewDocumentRoot(docRoot, typeParameterSymbol, classes); + currentSolution = currentSolution.WithDocumentSyntaxRoot(classes.Key, newDocRoot); + } + + return currentSolution; + }, context.Diagnostics); } if (memberAccess is { Parent: ExpressionSyntax { Parent: StatementSyntax statement } }) { context.RegisterCodeFix( - CodeAction.Create( - TitleRemove, - c => - { - var newRoot = root.RemoveNode(statement, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - TitleRemove), + TitleRemove, + c => + { + var newRoot = root.RemoveNode(statement, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericTypeParameterEmptinessCheckingCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericTypeParameterEmptinessCheckingCodeFix.cs index 3980908befe..ad4b0b94630 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericTypeParameterEmptinessCheckingCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/GenericTypeParameterEmptinessCheckingCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class GenericTypeParameterEmptinessCheckingCodeFix : SonarCodeFix { internal const string Title = "Change null checking"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(GenericTypeParameterEmptinessChecking.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(GenericTypeParameterEmptinessChecking.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -67,15 +60,13 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode(binary, newNode.WithTriviaFrom(binary)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode(binary, newNode.WithTriviaFrom(binary)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } } } - diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/GetHashCodeMutableCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/GetHashCodeMutableCodeFix.cs index b642e1347ed..0c4be6ba09f 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/GetHashCodeMutableCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/GetHashCodeMutableCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editing; @@ -31,7 +30,7 @@ public sealed class GetHashCodeMutableCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(GetHashCodeMutable.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); @@ -55,13 +54,12 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCo allFieldDeclarations = allFieldDeclarations.WhereNotNull().ToArray(); context.RegisterCodeFix( - CodeAction.Create( - Title, - token => AddReadonlyToFieldDeclarationsAsync(context.Document, token, allFieldDeclarations)), + Title, + c => AddReadonlyToFieldDeclarationsAsync(context.Document, c, allFieldDeclarations), context.Diagnostics); } - private async Task GetFieldDeclarationSyntaxAsync(SemanticModel semanticModel, IdentifierNameSyntax identifierName, CancellationToken cancel) + private static async Task GetFieldDeclarationSyntaxAsync(SemanticModel semanticModel, IdentifierNameSyntax identifierName, CancellationToken cancel) { if (!(semanticModel.GetSymbolInfo(identifierName).Symbol is IFieldSymbol fieldSymbol) || !fieldSymbol.DeclaringSyntaxReferences.Any()) @@ -97,4 +95,3 @@ private static async Task AddReadonlyToFieldDeclarationsAsync(Document } } } - diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/GetTypeWithIsAssignableFromCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/GetTypeWithIsAssignableFromCodeFix.cs index 8af79890d25..9103ccf147d 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/GetTypeWithIsAssignableFromCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/GetTypeWithIsAssignableFromCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -31,13 +30,13 @@ public sealed class GetTypeWithIsAssignableFromCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(GetTypeWithIsAssignableFrom.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); if (NewRoot(root, diagnostic, node) is { } newRoot) { - context.RegisterCodeFix(CodeAction.Create(Title, c => Task.FromResult(context.Document.WithSyntaxRoot(newRoot))), context.Diagnostics); + context.RegisterCodeFix(Title, c => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)), context.Diagnostics); } return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/LinkedListPropertiesInsteadOfMethodsCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/LinkedListPropertiesInsteadOfMethodsCodeFix.cs index fcf5f2fa949..c319b6108fc 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/LinkedListPropertiesInsteadOfMethodsCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/LinkedListPropertiesInsteadOfMethodsCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -31,7 +30,7 @@ public sealed class LinkedListPropertiesInsteadOfMethodsCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(LinkedListPropertiesInsteadOfMethods.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -41,13 +40,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c { var newMember = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expression, SyntaxFactory.IdentifierName("Value")); context.RegisterCodeFix( - CodeAction.Create( - Title, - _ => - { - var newRoot = root.ReplaceNode(invocationExpression, newMember); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + _ => + { + var newRoot = root.ReplaceNode(invocationExpression, newMember); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/LiteralSuffixUpperCaseCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/LiteralSuffixUpperCaseCodeFix.cs index 9f00a10a415..72f5bcca6a7 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/LiteralSuffixUpperCaseCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/LiteralSuffixUpperCaseCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -35,7 +34,7 @@ public override ImmutableArray FixableDiagnosticIds } } - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -51,14 +50,13 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (!newLiteral.IsKind(SyntaxKind.None)) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode(literal, - literal.WithToken(newLiteral).WithTriviaFrom(literal)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode(literal, + literal.WithToken(newLiteral).WithTriviaFrom(literal)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberInitializedToDefaultCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberInitializedToDefaultCodeFix.cs index 26bce4821f1..a371143873b 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberInitializedToDefaultCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberInitializedToDefaultCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -32,7 +31,7 @@ public sealed class MemberInitializedToDefaultCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MemberInitializedToDefault.DiagnosticId, MemberInitializerRedundant.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -43,33 +42,32 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var parent = initializer.Parent; + Title, + c => + { + var parent = initializer.Parent; - SyntaxNode newParent; + SyntaxNode newParent; - if (!(parent is PropertyDeclarationSyntax propDecl)) - { - newParent = parent.RemoveNode(initializer, SyntaxRemoveOptions.KeepNoTrivia); - } - else - { - var newPropDecl = propDecl - .WithInitializer(null) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) - .WithTriviaFrom(propDecl); + if (!(parent is PropertyDeclarationSyntax propDecl)) + { + newParent = parent.RemoveNode(initializer, SyntaxRemoveOptions.KeepNoTrivia); + } + else + { + var newPropDecl = propDecl + .WithInitializer(null) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) + .WithTriviaFrom(propDecl); - newParent = newPropDecl; - } + newParent = newPropDecl; + } - var newRoot = root.ReplaceNode( - parent, - newParent.WithAdditionalAnnotations(Formatter.Annotation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + var newRoot = root.ReplaceNode( + parent, + newParent.WithAdditionalAnnotations(Formatter.Annotation)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberOverrideCallsBaseMemberCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberOverrideCallsBaseMemberCodeFix.cs index e703fbcc98f..a9f83f922c6 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberOverrideCallsBaseMemberCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MemberOverrideCallsBaseMemberCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class MemberOverrideCallsBaseMemberCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MemberOverrideCallsBaseMember.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan; @@ -40,13 +39,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(member, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(member, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideAddsParamsCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideAddsParamsCodeFix.cs index 2bee2662aac..857751732b1 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideAddsParamsCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideAddsParamsCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -31,7 +30,7 @@ public sealed class MethodOverrideAddsParamsCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MethodOverrideAddsParams.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -43,20 +42,19 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var node = paramsToken.Parent; - var newNode = node.ReplaceToken( - paramsToken, - SyntaxFactory.Token(SyntaxKind.None)); - - newNode = newNode.WithTriviaFrom(node); - - var newRoot = root.ReplaceNode(node, newNode); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var node = paramsToken.Parent; + var newNode = node.ReplaceToken( + paramsToken, + SyntaxFactory.Token(SyntaxKind.None)); + + newNode = newNode.WithTriviaFrom(node); + + var newRoot = root.ReplaceNode(node, newNode); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideChangedDefaultValueCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideChangedDefaultValueCodeFix.cs index d1ed93c34ec..95d55f9e8e1 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideChangedDefaultValueCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideChangedDefaultValueCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -27,13 +26,13 @@ namespace SonarAnalyzer.Rules.CSharp [ExportCodeFixProvider(LanguageNames.CSharp)] public sealed class MethodOverrideChangedDefaultValueCodeFix : SonarCodeFix { - private const string TitleGeneral = "Synchronize default parameter value"; - private const string TitleExplicitInterface = "Remove default parameter value from explicit interface implementation"; + internal const string TitleGeneral = "Synchronize default parameter value"; + internal const string TitleExplicitInterface = "Remove default parameter value from explicit interface implementation"; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MethodOverrideChangedDefaultValue.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -81,21 +80,17 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon RegisterCodeFix(context, root, parameter, newParameter, title); } - private static void RegisterCodeFix(CodeFixContext context, SyntaxNode root, ParameterSyntax parameter, - ParameterSyntax newParameter, string codeFixTitle) - { + private static void RegisterCodeFix(SonarCodeFixContext context, SyntaxNode root, ParameterSyntax parameter, ParameterSyntax newParameter, string codeFixTitle) => context.RegisterCodeFix( - CodeAction.Create( - codeFixTitle, - c => - { - var newRoot = root.ReplaceNode( - parameter, - newParameter.WithTriviaFrom(parameter)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + codeFixTitle, + c => + { + var newRoot = root.ReplaceNode( + parameter, + newParameter.WithTriviaFrom(parameter)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); - } private static bool TryGetNewParameterSyntax(ParameterSyntax parameter, IParameterSymbol overriddenParameter, out ParameterSyntax newParameterSyntax) { diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideNoParamsCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideNoParamsCodeFix.cs index eee5f7323ae..b736dda3923 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideNoParamsCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodOverrideNoParamsCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,33 +26,26 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class MethodOverrideNoParamsCodeFix : SonarCodeFix { internal const string Title = "Add the 'params' modifier"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(MethodOverrideNoParams.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MethodOverrideNoParams.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var parameter = (ParameterSyntax)root.FindNode(diagnosticSpan); context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newParameter = parameter.WithModifiers( - parameter.Modifiers.Add( - SyntaxFactory.Token(SyntaxKind.ParamsKeyword))); - var newRoot = root.ReplaceNode( - parameter, - newParameter.WithTriviaFrom(parameter)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newParameter = parameter.WithModifiers( + parameter.Modifiers.Add( + SyntaxFactory.Token(SyntaxKind.ParamsKeyword))); + var newRoot = root.ReplaceNode( + parameter, + newParameter.WithTriviaFrom(parameter)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterMissingOptionalCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterMissingOptionalCodeFix.cs index 27712d4fe98..1327a6af99d 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterMissingOptionalCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterMissingOptionalCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -31,7 +30,7 @@ public sealed class MethodParameterMissingOptionalCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MethodParameterMissingOptional.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -51,13 +50,12 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon } context.RegisterCodeFix( - CodeAction.Create( - Title, - _ => - { - var newRoot = root.ReplaceNode(attributeList, GetNewAttributeList(attributeList, optionalAttribute, semanticModel)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + _ => + { + var newRoot = root.ReplaceNode(attributeList, GetNewAttributeList(attributeList, optionalAttribute, semanticModel)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterUnusedCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterUnusedCodeFix.cs index 85e31c745af..2f45bcda182 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterUnusedCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/MethodParameterUnusedCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class MethodParameterUnusedCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MethodParameterUnused.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -42,15 +41,14 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode( - parameter, - SyntaxRemoveOptions.KeepLeadingTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode( + parameter, + SyntaxRemoveOptions.KeepLeadingTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/NonFlagsEnumInBitwiseOperationCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/NonFlagsEnumInBitwiseOperationCodeFix.cs index f00a1bca59c..542aaa4b324 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/NonFlagsEnumInBitwiseOperationCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/NonFlagsEnumInBitwiseOperationCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class NonFlagsEnumInBitwiseOperationCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(NonFlagsEnumInBitwiseOperation.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -64,25 +63,24 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon } context.RegisterCodeFix( - CodeAction.Create( - Title, - async c => - { - var enumDeclarationRoot = await currentSolution.GetDocument(documentId).GetSyntaxRootAsync(c).ConfigureAwait(false); + Title, + async c => + { + var enumDeclarationRoot = await currentSolution.GetDocument(documentId).GetSyntaxRootAsync(c).ConfigureAwait(false); - var flagsAttributeName = flagsAttributeType.ToMinimalDisplayString(semanticModel, enumDeclaration.SpanStart); - flagsAttributeName = flagsAttributeName.Remove(flagsAttributeName.IndexOf("Attribute", System.StringComparison.Ordinal)); + var flagsAttributeName = flagsAttributeType.ToMinimalDisplayString(semanticModel, enumDeclaration.SpanStart); + flagsAttributeName = flagsAttributeName.Remove(flagsAttributeName.IndexOf("Attribute", System.StringComparison.Ordinal)); - var attributes = enumDeclaration.AttributeLists.Add( - SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(new[] { - SyntaxFactory.Attribute(SyntaxFactory.ParseName(flagsAttributeName)) }))); + var attributes = enumDeclaration.AttributeLists.Add( + SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.Attribute(SyntaxFactory.ParseName(flagsAttributeName)) }))); - var newDeclaration = enumDeclaration.WithAttributeLists(attributes); - var newRoot = enumDeclarationRoot.ReplaceNode( - enumDeclaration, - newDeclaration); - return currentSolution.WithDocumentSyntaxRoot(documentId, newRoot); - }), + var newDeclaration = enumDeclaration.WithAttributeLists(attributes); + var newRoot = enumDeclarationRoot.ReplaceNode( + enumDeclaration, + newDeclaration); + return currentSolution.WithDocumentSyntaxRoot(documentId, newRoot); + }, context.Diagnostics); } } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalParameterWithDefaultValueCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalParameterWithDefaultValueCodeFix.cs index fa0be476af8..0f5ef1e77e6 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalParameterWithDefaultValueCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalParameterWithDefaultValueCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class OptionalParameterWithDefaultValueCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(OptionalParameterWithDefaultValue.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -51,19 +50,17 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon } context.RegisterCodeFix( - CodeAction.Create( - Title, - _ => - { - var attributeName = defaultParameterValueAttributeType.ToMinimalDisplayString(semanticModel, attribute.SpanStart); - attributeName = attributeName.Remove(attributeName.IndexOf("Attribute", System.StringComparison.Ordinal)); + Title, + _ => + { + var attributeName = defaultParameterValueAttributeType.ToMinimalDisplayString(semanticModel, attribute.SpanStart); + attributeName = attributeName.Remove(attributeName.IndexOf("Attribute", System.StringComparison.Ordinal)); - var newAttribute = attribute.WithName(SyntaxFactory.ParseName(attributeName)); - var newRoot = root.ReplaceNode(attribute, newAttribute); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + var newAttribute = attribute.WithName(SyntaxFactory.ParseName(attributeName)); + var newRoot = root.ReplaceNode(attribute, newAttribute); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } } } - diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalRefOutParameterCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalRefOutParameterCodeFix.cs index 7716542424f..0d4f1edb73d 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalRefOutParameterCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/OptionalRefOutParameterCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class OptionalRefOutParameterCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(OptionalRefOutParameter.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -42,13 +41,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/OrderByRepeatedCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/OrderByRepeatedCodeFix.cs index b93d521e045..36d189b559f 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/OrderByRepeatedCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/OrderByRepeatedCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,24 +26,17 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class OrderByRepeatedCodeFix : SonarCodeFix { internal const string Title = "Change 'OrderBy' to 'ThenBy'"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(OrderByRepeated.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(OrderByRepeated.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var syntaxNode = root.FindNode(diagnosticSpan); context.RegisterCodeFix( - CodeAction.Create( - Title, - c => ChangeToThenByAsync(context.Document, syntaxNode, c)), + Title, + c => ChangeToThenByAsync(context.Document, syntaxNode, c), context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/PreferGuidEmptyCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/PreferGuidEmptyCodeFix.cs index a6031bd70dc..e5012adc738 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/PreferGuidEmptyCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/PreferGuidEmptyCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -31,20 +30,19 @@ public sealed class PreferGuidEmptyCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(PreferGuidEmpty.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var toReplace = ToReplace(root, context); var replacement = Replacement(root, toReplace); context.RegisterCodeFix( - CodeAction.Create( Title, - token => Task.FromResult(context.Document.WithSyntaxRoot(replacement))), + token => Task.FromResult(context.Document.WithSyntaxRoot(replacement)), context.Diagnostics); return Task.CompletedTask; } - private static SyntaxNode ToReplace(SyntaxNode root, CodeFixContext context) + private static SyntaxNode ToReplace(SyntaxNode root, SonarCodeFixContext context) { var replacement = root.FindNode(context.Diagnostics.First().Location.SourceSpan); return replacement is ArgumentSyntax argument diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundancyInConstructorDestructorDeclarationCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundancyInConstructorDestructorDeclarationCodeFix.cs index 491cdc555c8..3edf41c12c2 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundancyInConstructorDestructorDeclarationCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundancyInConstructorDestructorDeclarationCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -32,7 +31,7 @@ public sealed class RedundancyInConstructorDestructorDeclarationCodeFix : SonarC public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundancyInConstructorDestructorDeclaration.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -59,40 +58,37 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c return Task.CompletedTask; } - private static void RegisterActionForDestructor(CodeFixContext context, SyntaxNode root, SyntaxNode method) => - context.RegisterCodeFix(CodeAction.Create(TitleRemoveDestructor, - c => - { - var newRoot = root.RemoveNode(method, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - TitleRemoveDestructor), + private static void RegisterActionForDestructor(SonarCodeFixContext context, SyntaxNode root, SyntaxNode method) => + context.RegisterCodeFix(TitleRemoveDestructor, + c => + { + var newRoot = root.RemoveNode(method, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); - private static void RegisterActionForConstructor(CodeFixContext context, SyntaxNode root, SyntaxNode method) => - context.RegisterCodeFix(CodeAction.Create(TitleRemoveConstructor, - c => - { - var newRoot = root.RemoveNode(method, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - TitleRemoveConstructor), + private static void RegisterActionForConstructor(SonarCodeFixContext context, SyntaxNode root, SyntaxNode method) => + context.RegisterCodeFix(TitleRemoveConstructor, + c => + { + var newRoot = root.RemoveNode(method, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); - private static void RegisterActionForBaseCall(CodeFixContext context, SyntaxNode root, SyntaxNode initializer) + private static void RegisterActionForBaseCall(SonarCodeFixContext context, SyntaxNode root, SyntaxNode initializer) { if (!(initializer.Parent is ConstructorDeclarationSyntax constructor)) { return; } - context.RegisterCodeFix(CodeAction.Create(TitleRemoveBaseCall, - c => - { - var newRoot = RemoveInitializer(root, constructor); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - TitleRemoveBaseCall), + context.RegisterCodeFix(TitleRemoveBaseCall, + c => + { + var newRoot = RemoveInitializer(root, constructor); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantArgumentCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantArgumentCodeFix.cs index a9ffe77762f..7a9193b34f3 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantArgumentCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantArgumentCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Text; using NodeAndSymbol = SonarAnalyzer.Common.NodeAndSymbol; @@ -31,15 +30,9 @@ public sealed class RedundantArgumentCodeFix : SonarCodeFix internal const string TitleRemove = "Remove redundant arguments"; internal const string TitleRemoveWithNameAdditions = "Remove redundant arguments with adding named arguments"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(RedundantArgument.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantArgument.DiagnosticId); - protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override async Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var invocation = GetInvocation(root, diagnostic.Location.SourceSpan); @@ -89,10 +82,8 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon if (argumentsCanBeRemovedWithoutNamed.Any()) { context.RegisterCodeFix( - CodeAction.Create( - TitleRemove, - c => RemoveArgumentsAsync(context.Document, argumentsCanBeRemovedWithoutNamed, c), - TitleRemove), + TitleRemove, + c => RemoveArgumentsAsync(context.Document, argumentsCanBeRemovedWithoutNamed, c), context.Diagnostics); } @@ -100,10 +91,8 @@ protected override async Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixCon if (cannotBeRemoved.Any()) { context.RegisterCodeFix( - CodeAction.Create( - TitleRemoveWithNameAdditions, - c => RemoveArgumentsAndAddNecessaryNamesAsync(context.Document, invocation.ArgumentList, argumentMappings, argumentsWithDefaultValues, semanticModel, c), - TitleRemoveWithNameAdditions), + TitleRemoveWithNameAdditions, + c => RemoveArgumentsAndAddNecessaryNamesAsync(context.Document, invocation.ArgumentList, argumentMappings, argumentsWithDefaultValues, semanticModel, c), context.Diagnostics); } } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCastCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCastCodeFix.cs index 750de1db861..976ef6a7ca6 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCastCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCastCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class RedundantCastCodeFix : SonarCodeFix { internal const string Title = "Remove redundant cast"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(RedundantCast.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantCast.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -53,28 +46,26 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c memberAccess != null) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = RemoveCall(root, castInvocation, memberAccess); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = RemoveCall(root, castInvocation, memberAccess); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } if (syntaxNode is BinaryExpressionSyntax asExpression) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode( - asExpression, - asExpression.Left.WithTriviaFrom(asExpression)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode( + asExpression, + asExpression.Left.WithTriviaFrom(asExpression)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantConditionalAroundAssignmentCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantConditionalAroundAssignmentCodeFix.cs index 435e93e3ee4..d0afddd7cea 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantConditionalAroundAssignmentCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantConditionalAroundAssignmentCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class RedundantConditionalAroundAssignmentCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantConditionalAroundAssignment.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -53,7 +52,7 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } } - private static Task HandleIfStatement(SyntaxNode root, CodeFixContext context, IfStatementSyntax ifStatement) + private static Task HandleIfStatement(SyntaxNode root, SonarCodeFixContext context, IfStatementSyntax ifStatement) { var statement = ifStatement.Statement; if (statement is BlockSyntax block) @@ -67,21 +66,20 @@ private static Task HandleIfStatement(SyntaxNode root, CodeFixContext context, I } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode( - ifStatement, - statement.WithTriviaFrom(ifStatement)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode( + ifStatement, + statement.WithTriviaFrom(ifStatement)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; } - private static Task HandleSwitchExpression(SyntaxNode root, CodeFixContext context, SyntaxNode switchExpression) + private static Task HandleSwitchExpression(SyntaxNode root, SonarCodeFixContext context, SyntaxNode switchExpression) { var switchArm = ((SwitchExpressionSyntaxWrapper)switchExpression).Arms.FirstOrDefault(); if (switchArm.SyntaxNode == null || switchArm.SyntaxNode.Parent.ChildNodes().Count(x => x.IsKind(SyntaxKindEx.SwitchExpressionArm)) != 1) @@ -90,15 +88,14 @@ private static Task HandleSwitchExpression(SyntaxNode root, CodeFixContext conte } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode( - switchExpression, - switchArm.Expression.WithTriviaFrom(switchExpression)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode( + switchExpression, + switchArm.Expression.WithTriviaFrom(switchExpression)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantDeclarationCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantDeclarationCodeFix.cs index 605317dcb0f..24ab1e8ee1e 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantDeclarationCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantDeclarationCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; using SonarAnalyzer.Constants; @@ -39,7 +38,7 @@ public sealed class RedundantDeclarationCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantDeclaration.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -50,178 +49,183 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c return Task.CompletedTask; } - if (TryGetAction(syntaxNode, root, diagnosticType, context.Document, diagnostic.Properties, out var action)) - { - context.RegisterCodeFix(action, context.Diagnostics); - } + RegisterAction(syntaxNode, root, diagnosticType, context.Document, diagnostic.Properties, context); return Task.CompletedTask; } - private static bool TryGetRedundantLambdaParameterAction(SyntaxNode syntaxNode, - SyntaxNode root, - Document document, - ImmutableDictionary properties, - out CodeAction action) + private static void RegisterRedundantLambdaParameterAction(SyntaxNode syntaxNode, + SyntaxNode root, + Document document, + ImmutableDictionary properties, + SonarCodeFixContext context) { var parentExpression = syntaxNode.Parent?.Parent; if (parentExpression is ParenthesizedLambdaExpressionSyntax lambdaExpressionSyntax) { - action = CodeAction.Create(TitleRedundantParameterName, c => - { - var parameterName = properties[RedundantDeclaration.ParameterNameKey]; - var parameter = lambdaExpressionSyntax.ParameterList.Parameters.Single(parameter => parameter.Identifier.Text == parameterName); - var newRoot = root.ReplaceNode(parameter, SyntaxFactory.Parameter(SyntaxFactory.Identifier(SyntaxConstants.Discard))); - - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, TitleRedundantParameterName); - return true; + context.RegisterCodeFix( + TitleRedundantParameterName, + c => + { + var parameterName = properties[RedundantDeclaration.ParameterNameKey]; + var parameter = lambdaExpressionSyntax.ParameterList.Parameters.Single(parameter => parameter.Identifier.Text == parameterName); + var newRoot = root.ReplaceNode(parameter, SyntaxFactory.Parameter(SyntaxFactory.Identifier(SyntaxConstants.Discard))); + + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } else if (parentExpression is ParameterListSyntax parameterList) { - action = CodeAction.Create(TitleRedundantLambdaParameterType, c => - { - var newParameterList = parameterList.WithParameters(SyntaxFactory.SeparatedList(parameterList.Parameters.Select(p => SyntaxFactory.Parameter(p.Identifier).WithTriviaFrom(p)))); - var newRoot = root.ReplaceNode(parameterList, newParameterList); + context.RegisterCodeFix( + TitleRedundantLambdaParameterType, + c => + { + var newParameterList = parameterList.WithParameters(SyntaxFactory.SeparatedList(parameterList.Parameters.Select(p => SyntaxFactory.Parameter(p.Identifier).WithTriviaFrom(p)))); + var newRoot = root.ReplaceNode(parameterList, newParameterList); - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, TitleRedundantLambdaParameterType); - return true; - } - else - { - action = null; - return false; + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } } - private static bool TryGetRedundantArraySizeAction(SyntaxNode syntaxNode, SyntaxNode root, - Document document, out CodeAction action) + private static void RegisterRedundantArraySizeAction(SyntaxNode syntaxNode, SyntaxNode root, Document document, SonarCodeFixContext context) { - if (!(syntaxNode.Parent is ArrayRankSpecifierSyntax arrayRank)) + if (syntaxNode.Parent is not ArrayRankSpecifierSyntax arrayRank) { - action = null; - return false; + return; } - action = CodeAction.Create(TitleRedundantArraySize, c => - { - var newArrayRankSpecifier = arrayRank.WithSizes( - SyntaxFactory.SeparatedList(arrayRank.Sizes.Select(s => - SyntaxFactory.OmittedArraySizeExpression()))); - var newRoot = root.ReplaceNode(arrayRank, newArrayRankSpecifier); - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, TitleRedundantArraySize); - return true; + context.RegisterCodeFix( + TitleRedundantArraySize, + c => + { + var newArrayRankSpecifier = arrayRank.WithSizes( + SyntaxFactory.SeparatedList(arrayRank.Sizes.Select(s => + SyntaxFactory.OmittedArraySizeExpression()))); + var newRoot = root.ReplaceNode(arrayRank, newArrayRankSpecifier); + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } - private static bool TryGetRedundantArrayTypeAction(SyntaxNode syntaxNode, SyntaxNode root, - Document document, out CodeAction action) + private static void RegisterRedundantArrayTypeAction(SyntaxNode syntaxNode, SyntaxNode root, Document document, SonarCodeFixContext context) { var arrayTypeSyntax = syntaxNode as ArrayTypeSyntax ?? syntaxNode.Parent as ArrayTypeSyntax; - if (!(arrayTypeSyntax?.Parent is ArrayCreationExpressionSyntax arrayCreation)) + if (arrayTypeSyntax?.Parent is not ArrayCreationExpressionSyntax arrayCreation) { - action = null; - return false; + return; } - action = CodeAction.Create(TitleRedundantArrayType, c => - { - var implicitArrayCreation = SyntaxFactory.ImplicitArrayCreationExpression(arrayCreation.Initializer); - var newRoot = root.ReplaceNode(arrayCreation, implicitArrayCreation); - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, TitleRedundantArrayType); - return true; + context.RegisterCodeFix( + TitleRedundantArrayType, + c => + { + var implicitArrayCreation = SyntaxFactory.ImplicitArrayCreationExpression(arrayCreation.Initializer); + var newRoot = root.ReplaceNode(arrayCreation, implicitArrayCreation); + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } - private static bool TryGetRedundantExplicitObjectCreationAction(SyntaxNode syntaxNode, SyntaxNode root, - Document document, RedundantDeclaration.RedundancyType diagnosticType, out CodeAction action) + private static void RegisterRedundantExplicitObjectCreationAction(SyntaxNode syntaxNode, + SyntaxNode root, + Document document, + RedundantDeclaration.RedundancyType diagnosticType, + SonarCodeFixContext context) { var title = diagnosticType == RedundantDeclaration.RedundancyType.ExplicitDelegate ? TitleRedundantExplicitDelegate : TitleRedundantExplicitNullable; - if (!(syntaxNode is ObjectCreationExpressionSyntax objectCreation)) + if (syntaxNode is not ObjectCreationExpressionSyntax objectCreation) { - action = null; - return false; + return; } var newExpression = objectCreation.ArgumentList?.Arguments.FirstOrDefault()?.Expression; if (newExpression == null) { - action = null; - return false; + return; } - action = CodeAction.Create(title, c => - { - newExpression = newExpression.WithTriviaFrom(objectCreation); - var newRoot = root.ReplaceNode(objectCreation, newExpression); - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, title); - return true; + context.RegisterCodeFix( + title, + c => + { + newExpression = newExpression.WithTriviaFrom(objectCreation); + var newRoot = root.ReplaceNode(objectCreation, newExpression); + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } - private static bool TryGetRedundantObjectInitializerAction(SyntaxNode syntaxNode, SyntaxNode root, - Document document, out CodeAction action) + private static void RegisterRedundantObjectInitializerAction(SyntaxNode syntaxNode, SyntaxNode root, Document document, SonarCodeFixContext context) { - if (!(syntaxNode.Parent is ObjectCreationExpressionSyntax objectCreation)) + if (syntaxNode.Parent is not ObjectCreationExpressionSyntax objectCreation) { - action = null; - return false; + return; } - action = CodeAction.Create(TitleRedundantObjectInitializer, c => - { - var newObjectCreation = objectCreation.WithInitializer(null).WithAdditionalAnnotations(Formatter.Annotation); - var newRoot = root.ReplaceNode(objectCreation, newObjectCreation); - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, TitleRedundantObjectInitializer); - return true; + context.RegisterCodeFix( + TitleRedundantObjectInitializer, + c => + { + var newObjectCreation = objectCreation.WithInitializer(null).WithAdditionalAnnotations(Formatter.Annotation); + var newRoot = root.ReplaceNode(objectCreation, newObjectCreation); + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } - private static bool TryGetRedundantParameterTypeAction(SyntaxNode syntaxNode, SyntaxNode root, - Document document, out CodeAction action) + private static void RegisterRedundantParameterTypeAction(SyntaxNode syntaxNode, SyntaxNode root, Document document, SonarCodeFixContext context) { - if (!(syntaxNode.Parent is AnonymousMethodExpressionSyntax anonymousMethod)) + if (syntaxNode.Parent is not AnonymousMethodExpressionSyntax anonymousMethod) { - action = null; - return false; + return; } - action = CodeAction.Create(TitleRedundantDelegateParameterList, c => - { - var newAnonymousMethod = anonymousMethod.WithParameterList(null); - var newRoot = root.ReplaceNode(anonymousMethod, newAnonymousMethod); - return Task.FromResult(document.WithSyntaxRoot(newRoot)); - }, TitleRedundantDelegateParameterList); - return true; + context.RegisterCodeFix( + TitleRedundantDelegateParameterList, + c => + { + var newAnonymousMethod = anonymousMethod.WithParameterList(null); + var newRoot = root.ReplaceNode(anonymousMethod, newAnonymousMethod); + return Task.FromResult(document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } - private static bool TryGetAction(SyntaxNode syntaxNode, + private static void RegisterAction(SyntaxNode syntaxNode, SyntaxNode root, RedundantDeclaration.RedundancyType diagnosticType, Document document, ImmutableDictionary properties, - out CodeAction action) + SonarCodeFixContext context) { switch (diagnosticType) { case RedundantDeclaration.RedundancyType.LambdaParameterType: - return TryGetRedundantLambdaParameterAction(syntaxNode, root, document, properties, out action); + RegisterRedundantLambdaParameterAction(syntaxNode, root, document, properties, context); + break; case RedundantDeclaration.RedundancyType.ArraySize: - return TryGetRedundantArraySizeAction(syntaxNode, root, document, out action); + RegisterRedundantArraySizeAction(syntaxNode, root, document, context); + break; case RedundantDeclaration.RedundancyType.ArrayType: - return TryGetRedundantArrayTypeAction(syntaxNode, root, document, out action); + RegisterRedundantArrayTypeAction(syntaxNode, root, document, context); + break; case RedundantDeclaration.RedundancyType.ExplicitDelegate: case RedundantDeclaration.RedundancyType.ExplicitNullable: - return TryGetRedundantExplicitObjectCreationAction(syntaxNode, root, document, diagnosticType, out action); + RegisterRedundantExplicitObjectCreationAction(syntaxNode, root, document, diagnosticType, context); + break; case RedundantDeclaration.RedundancyType.ObjectInitializer: - return TryGetRedundantObjectInitializerAction(syntaxNode, root, document, out action); + RegisterRedundantObjectInitializerAction(syntaxNode, root, document, context); + break; case RedundantDeclaration.RedundancyType.DelegateParameterList: - return TryGetRedundantParameterTypeAction(syntaxNode, root, document, out action); + RegisterRedundantParameterTypeAction(syntaxNode, root, document, context); + break; default: throw new NotSupportedException(); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantInheritanceListCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantInheritanceListCodeFix.cs index 5e0c29b535f..f6720bf51aa 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantInheritanceListCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantInheritanceListCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -30,7 +29,7 @@ public sealed class RedundantInheritanceListCodeFix : SonarCodeFix private const string Title = "Remove redundant declaration"; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantInheritanceList.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -38,13 +37,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c var redundantIndex = int.Parse(diagnostic.Properties[RedundantInheritanceList.RedundantIndexKey]); context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = RemoveDeclaration(root, baseList, redundantIndex); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = RemoveDeclaration(root, baseList, redundantIndex); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantModifierCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantModifierCodeFix.cs index 7f92b40d5b8..06b58559911 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantModifierCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantModifierCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -27,10 +26,10 @@ namespace SonarAnalyzer.Rules.CSharp [ExportCodeFixProvider(LanguageNames.CSharp)] public sealed class RedundantModifierCodeFix : SonarCodeFix { - private const string TitleUnsafe = "Remove redundant 'unsafe' modifier"; - private const string TitleChecked = "Remove redundant 'checked' and 'unchecked' modifier"; - private const string TitlePartial = "Remove redundant 'partial' modifier"; - private const string TitleSealed = "Remove redundant 'sealed' modifier"; + internal const string TitleUnsafe = "Remove redundant 'unsafe' modifier"; + internal const string TitleChecked = "Remove redundant 'checked' and 'unchecked' modifier"; + internal const string TitlePartial = "Remove redundant 'partial' modifier"; + internal const string TitleSealed = "Remove redundant 'sealed' modifier"; private static readonly SyntaxKind[] SimpleTokenKinds = { @@ -40,7 +39,7 @@ public sealed class RedundantModifierCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantModifier.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -48,25 +47,25 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (token.IsKind(SyntaxKind.UnsafeKeyword)) { - context.RegisterCodeFix(CodeAction.Create(TitleUnsafe, c => ReplaceRoot(context, RemoveRedundantUnsafe(root, token))), context.Diagnostics); + context.RegisterCodeFix(TitleUnsafe, c => ReplaceRoot(context, RemoveRedundantUnsafe(root, token)), context.Diagnostics); } else if (SimpleTokenKinds.Contains(token.Kind())) { var title = token.IsKind(SyntaxKind.PartialKeyword) ? TitlePartial : TitleSealed; - context.RegisterCodeFix(CodeAction.Create(title, c => ReplaceRoot(context, RemoveRedundantToken(root, token))), context.Diagnostics); + context.RegisterCodeFix(title, c => ReplaceRoot(context, RemoveRedundantToken(root, token)), context.Diagnostics); } else if (token.Parent is CheckedStatementSyntax checkedStatement) { - context.RegisterCodeFix(CodeAction.Create(TitleChecked, c => ReplaceRoot(context, RemoveRedundantCheckedStatement(root, checkedStatement))), context.Diagnostics); + context.RegisterCodeFix(TitleChecked, c => ReplaceRoot(context, RemoveRedundantCheckedStatement(root, checkedStatement)), context.Diagnostics); } else if (token.Parent is CheckedExpressionSyntax checkedExpression) { - context.RegisterCodeFix(CodeAction.Create(TitleChecked, c => ReplaceRoot(context, RemoveRedundantCheckedExpression(root, checkedExpression))), context.Diagnostics); + context.RegisterCodeFix(TitleChecked, c => ReplaceRoot(context, RemoveRedundantCheckedExpression(root, checkedExpression)), context.Diagnostics); } return Task.CompletedTask; } - private static Task ReplaceRoot(CodeFixContext context, SyntaxNode newRoot) => + private static Task ReplaceRoot(SonarCodeFixContext context, SyntaxNode newRoot) => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); private static SyntaxNode RemoveRedundantUnsafe(SyntaxNode root, SyntaxToken token) diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantNullCheckCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantNullCheckCodeFix.cs index f5e7b7433b6..5b53967e1f6 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantNullCheckCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantNullCheckCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class RedundantNullCheckCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(RedundantNullCheck.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -61,37 +60,35 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c return Task.CompletedTask; } - private static void RegisterBinaryExpressionCodeFix(CodeFixContext context, SyntaxNode root, SyntaxNode mustBeReplaced) => + private static void RegisterBinaryExpressionCodeFix(SonarCodeFixContext context, SyntaxNode root, SyntaxNode mustBeReplaced) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => + Title, + c => + { + var binaryExpression = mustBeReplaced.Parent.FirstAncestorOrSelf(); + var newRoot = root; + if (binaryExpression != null) { - var binaryExpression = mustBeReplaced.Parent.FirstAncestorOrSelf(); - var newRoot = root; - if (binaryExpression != null) - { - newRoot = ReplaceNode(root, binaryExpression, binaryExpression.Left, binaryExpression.Right, mustBeReplaced); - } - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + newRoot = ReplaceNode(root, binaryExpression, binaryExpression.Left, binaryExpression.Right, mustBeReplaced); + } + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); - private static void RegisterBinaryPatternCodeFix(CodeFixContext context, SyntaxNode root, SyntaxNode mustBeReplaced) => + private static void RegisterBinaryPatternCodeFix(SonarCodeFixContext context, SyntaxNode root, SyntaxNode mustBeReplaced) => context.RegisterCodeFix( - CodeAction.Create( - Title, - c => + Title, + c => + { + var binaryExpression = mustBeReplaced.Parent.FirstAncestorOrSelf(n => BinaryPatternSyntaxWrapper.IsInstance(n)); + var newRoot = root; + if (binaryExpression != null) { - var binaryExpression = mustBeReplaced.Parent.FirstAncestorOrSelf(n => BinaryPatternSyntaxWrapper.IsInstance(n)); - var newRoot = root; - if (binaryExpression != null) - { - var binaryPatternNode = (BinaryPatternSyntaxWrapper)binaryExpression; - newRoot = ReplaceNode(root, binaryExpression, binaryPatternNode.Left.SyntaxNode, binaryPatternNode.Right.SyntaxNode, mustBeReplaced); - } - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + var binaryPatternNode = (BinaryPatternSyntaxWrapper)binaryExpression; + newRoot = ReplaceNode(root, binaryExpression, binaryPatternNode.Left.SyntaxNode, binaryPatternNode.Right.SyntaxNode, mustBeReplaced); + } + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); private static SyntaxNode ReplaceNode(SyntaxNode root, SyntaxNode binaryExpression, SyntaxNode binaryLeft, SyntaxNode binaryRight, SyntaxNode mustBeReplaced) => diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantParenthesesCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantParenthesesCodeFix.cs index 3ffc5c00ab4..6055b5764df 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantParenthesesCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantParenthesesCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,7 +29,7 @@ public sealed class RedundantParenthesesCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantParentheses.DiagnosticId, RedundantParenthesesObjectsCreation.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -40,13 +39,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c syntaxNode is AttributeArgumentListSyntax) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepEndOfLine); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepEndOfLine); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } else diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantPropertyNamesInAnonymousClassCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantPropertyNamesInAnonymousClassCodeFix.cs index c475f8edb3c..d165994aafa 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantPropertyNamesInAnonymousClassCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantPropertyNamesInAnonymousClassCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -29,7 +28,7 @@ public sealed class RedundantPropertyNamesInAnonymousClassCodeFix : SonarCodeFix internal const string Title = "Remove redundant explicit property names"; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantPropertyNamesInAnonymousClass.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -40,21 +39,20 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newInitializersWithSeparators = anonymousObjectCreation.Initializers.GetWithSeparators() - .Select(item => GetNewSyntaxListItem(item)); - var newAnonymousObjectCreation = anonymousObjectCreation - .WithInitializers(SyntaxFactory.SeparatedList(newInitializersWithSeparators)) - .WithTriviaFrom(anonymousObjectCreation); + Title, + c => + { + var newInitializersWithSeparators = anonymousObjectCreation.Initializers.GetWithSeparators() + .Select(item => GetNewSyntaxListItem(item)); + var newAnonymousObjectCreation = anonymousObjectCreation + .WithInitializers(SyntaxFactory.SeparatedList(newInitializersWithSeparators)) + .WithTriviaFrom(anonymousObjectCreation); - var newRoot = root.ReplaceNode( - anonymousObjectCreation, - newAnonymousObjectCreation); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + var newRoot = root.ReplaceNode( + anonymousObjectCreation, + newAnonymousObjectCreation); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToArrayCallCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToArrayCallCodeFix.cs index 5b24e97a6cc..387d79c9a1b 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToArrayCallCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToArrayCallCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -29,7 +28,7 @@ public sealed class RedundantToArrayCallCodeFix : SonarCodeFix private const string Title = "Remove redundant 'ToArray' call"; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(RedundantToArrayCall.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -42,13 +41,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode(invocationExpressionSyntax, memberAccessExpressionSyntax.Expression); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode(invocationExpressionSyntax, memberAccessExpressionSyntax.Expression); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToStringCallCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToStringCallCodeFix.cs index 1d00a3f9fcc..8f8532a08a5 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToStringCallCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantToStringCallCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -33,7 +32,7 @@ public sealed class RedundantToStringCallCodeFix : SonarCodeFix public override FixAllProvider GetFixAllProvider() => null; // This CodeFix doesn't support FixAll (yet), because removing one .ToString() can invalidate other diagnostic in the same expression - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -44,13 +43,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode(invocation, memberAccess.Expression.WithTriviaFrom(invocation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceNode(invocation, memberAccess.Expression.WithTriviaFrom(invocation)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/SuppressFinalizeUselessCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/SuppressFinalizeUselessCodeFix.cs index bad53159b3e..df24dd2abf9 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/SuppressFinalizeUselessCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/SuppressFinalizeUselessCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class SuppressFinalizeUselessCodeFix : SonarCodeFix { internal const string Title = "Remove useless 'SuppressFinalize' call"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(SuppressFinalizeUseless.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(SuppressFinalizeUseless.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -44,13 +37,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (syntaxNode.Parent is ExpressionStatementSyntax) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntaxNode.Parent, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntaxNode.Parent, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchCaseFallsThroughToDefaultCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchCaseFallsThroughToDefaultCodeFix.cs index 7a41e7606df..a80d4699aec 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchCaseFallsThroughToDefaultCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchCaseFallsThroughToDefaultCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class SwitchCaseFallsThroughToDefaultCodeFix : SonarCodeFix { internal const string Title = "Remove useless 'case'"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(SwitchCaseFallsThroughToDefault.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(SwitchCaseFallsThroughToDefault.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -46,13 +39,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchDefaultClauseEmptyCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchDefaultClauseEmptyCodeFix.cs index d2d655b3b22..0842312aca5 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchDefaultClauseEmptyCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/SwitchDefaultClauseEmptyCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -29,7 +28,7 @@ public sealed class SwitchDefaultClauseEmptyCodeFix : SonarCodeFix internal const string Title = "Remove empty 'default' clause"; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(SwitchDefaultClauseEmpty.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -39,13 +38,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/ThreadStaticNonStaticFieldCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/ThreadStaticNonStaticFieldCodeFix.cs index a324826bc75..9a04eaa8487 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/ThreadStaticNonStaticFieldCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/ThreadStaticNonStaticFieldCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,15 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class ThreadStaticNonStaticFieldCodeFix : SonarCodeFix { internal const string Title = "Remove 'ThreadStatic' attribute"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(ThreadStaticNonStaticField.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(ThreadStaticNonStaticField.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -47,13 +40,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnaryPrefixOperatorRepeatedCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnaryPrefixOperatorRepeatedCodeFix.cs index 0d22289e946..9db5d4e7741 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnaryPrefixOperatorRepeatedCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnaryPrefixOperatorRepeatedCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; @@ -28,15 +27,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class UnaryPrefixOperatorRepeatedCodeFix : SonarCodeFix { internal const string Title = "Remove repeated prefix operator(s)"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(UnaryPrefixOperatorRepeated.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UnaryPrefixOperatorRepeated.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -47,23 +40,22 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - GetExpression(prefix, out var expression, out var count); + Title, + c => + { + GetExpression(prefix, out var expression, out var count); - if (count%2 == 1) - { - expression = SyntaxFactory.PrefixUnaryExpression( - prefix.Kind(), - expression); - } + if (count%2 == 1) + { + expression = SyntaxFactory.PrefixUnaryExpression( + prefix.Kind(), + expression); + } - var newRoot = root.ReplaceNode(prefix, expression - .WithAdditionalAnnotations(Formatter.Annotation)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + var newRoot = root.ReplaceNode(prefix, expression + .WithAdditionalAnnotations(Formatter.Annotation)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnchangedLocalVariablesShouldBeConstCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnchangedLocalVariablesShouldBeConstCodeFix.cs index cb74aae7d73..d3688d0c5d8 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnchangedLocalVariablesShouldBeConstCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnchangedLocalVariablesShouldBeConstCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -32,7 +31,7 @@ public sealed class UnchangedLocalVariablesShouldBeConstCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UnchangedLocalVariablesShouldBeConst.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { if (VariableDeclaration(root, context) is { @@ -41,9 +40,8 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } variable) { context.RegisterCodeFix( - CodeAction.Create( Title, - cancel => ChangeDocument(context.Document, root, variable, oldNode, cancel)), + c => ChangeDocument(context.Document, root, variable, oldNode, c), context.Diagnostics); } @@ -66,7 +64,7 @@ public static async Task ChangeDocument( return document.WithSyntaxRoot(newNode); } - private static VariableDeclarationSyntax VariableDeclaration(SyntaxNode root, CodeFixContext context) => + private static VariableDeclarationSyntax VariableDeclaration(SyntaxNode root, SonarCodeFixContext context) => root.FindNode(context.Diagnostics.First().Location.SourceSpan)?.Parent as VariableDeclarationSyntax; private static LocalDeclarationStatementSyntax ConstantDeclaration(VariableDeclarationSyntax declaration) diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnnecessaryUsingsCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnnecessaryUsingsCodeFix.cs index e585ab8e58f..6865406c66d 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnnecessaryUsingsCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnnecessaryUsingsCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,12 +26,9 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class UnnecessaryUsingsCodeFix : SonarCodeFix { internal const string Title = "Remove this unnecessary 'using'."; - public override ImmutableArray FixableDiagnosticIds - { - get => ImmutableArray.Create(UnnecessaryUsings.DiagnosticId); - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UnnecessaryUsings.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -43,13 +39,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntaxNode, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnusedPrivateMemberCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnusedPrivateMemberCodeFix.cs index b45d9d2fbb7..aba11b394de 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/UnusedPrivateMemberCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/UnusedPrivateMemberCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -30,20 +29,19 @@ public class UnusedPrivateMemberCodeFix : SonarCodeFix // We only want to fix S1144 and not S4487 because for S4487 the field is written so we don't know the fix public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UnusedPrivateMember.S1144DiagnosticId); - protected sealed override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected sealed override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(diag => diag.Id == UnusedPrivateMember.S1144DiagnosticId); var diagnosticSpan = diagnostic.Location.SourceSpan; var syntax = root.FindNode(diagnosticSpan); context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.RemoveNode(syntax, SyntaxRemoveOptions.KeepNoTrivia); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.RemoveNode(syntax, SyntaxRemoveOptions.KeepNoTrivia); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/UseCharOverloadOfStringMethodsCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/UseCharOverloadOfStringMethodsCodeFix.cs index 7190f71cbc2..98bc42ab8da 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/UseCharOverloadOfStringMethodsCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/UseCharOverloadOfStringMethodsCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -30,16 +29,15 @@ public sealed class UseCharOverloadOfStringMethodsCodeFix : SonarCodeFix private const string Title = "Convert to char."; public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UseCharOverloadOfStringMethods.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); if (root.FindNode(diagnostic.Location.SourceSpan) is { Parent: { Parent: InvocationExpressionSyntax invocation } } && invocation.ArgumentList.Arguments[0].Expression is LiteralExpressionSyntax node) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => Task.FromResult(context.Document.WithSyntaxRoot(root.ReplaceNode(node, Convert(node))))), + Title, + c => Task.FromResult(context.Document.WithSyntaxRoot(root.ReplaceNode(node, Convert(node)))), context.Diagnostics); } return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/UseUnixEpochCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/UseUnixEpochCodeFix.cs index 6ab6654fd01..acdb544e23d 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/UseUnixEpochCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/UseUnixEpochCodeFix.cs @@ -25,7 +25,7 @@ namespace SonarAnalyzer.Rules.CSharp [ExportCodeFixProvider(LanguageNames.CSharp)] public sealed class UseUnixEpochCodeFix : UseUnixEpochCodeFixBase { - protected override SyntaxNode ReplaceConstructorWithField(SyntaxNode root, SyntaxNode node, CodeFixContext context) + protected override SyntaxNode ReplaceConstructorWithField(SyntaxNode root, SyntaxNode node, SonarCodeFixContext context) { ExpressionSyntax typeNode; if (node.IsKind(SyntaxKindEx.ImplicitObjectCreationExpression)) diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/VirtualEventFieldCodeFix.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/VirtualEventFieldCodeFix.cs index 664075065d5..690b8d34c98 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/VirtualEventFieldCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/VirtualEventFieldCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.CSharp @@ -27,28 +26,21 @@ namespace SonarAnalyzer.Rules.CSharp public sealed class VirtualEventFieldCodeFix : SonarCodeFix { internal const string Title = "Remove 'virtual' keyword"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(VirtualEventField.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(VirtualEventField.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var token = root.FindToken(diagnosticSpan.Start); context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceToken(token, SyntaxFactory.Token(SyntaxKind.None)); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = root.ReplaceToken(token, SyntaxFactory.Token(SyntaxKind.None)); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarCodeFixContext.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarCodeFixContext.cs new file mode 100644 index 00000000000..2677b69c098 --- /dev/null +++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarCodeFixContext.cs @@ -0,0 +1,44 @@ +/* + * SonarAnalyzer for .NET + * Copyright (C) 2015-2023 SonarSource SA + * mailto: contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Text; + +namespace SonarAnalyzer.AnalysisContext; + +public readonly struct SonarCodeFixContext +{ + private readonly CodeFixContext context; + + public readonly CancellationToken CancellationToken => context.CancellationToken; + public readonly Document Document => context.Document; + public readonly ImmutableArray Diagnostics => context.Diagnostics; + public readonly TextSpan Span => context.Span; + + public SonarCodeFixContext(CodeFixContext context) => + this.context = context; + + public void RegisterCodeFix(string title, Func> createChangedDocument, ImmutableArray diagnostics) => + context.RegisterCodeFix(CodeAction.Create(title, createChangedDocument, title), diagnostics); + + public void RegisterCodeFix(string title, Func> createChangedDocument, ImmutableArray diagnostics) => + context.RegisterCodeFix(CodeAction.Create(title, createChangedDocument, title), diagnostics); +} diff --git a/analyzers/src/SonarAnalyzer.Common/Common/FixAllProviders/DocumentBasedFixAllProvider.cs b/analyzers/src/SonarAnalyzer.Common/Common/FixAllProviders/DocumentBasedFixAllProvider.cs index 12858fd70ac..0e71809e170 100644 --- a/analyzers/src/SonarAnalyzer.Common/Common/FixAllProviders/DocumentBasedFixAllProvider.cs +++ b/analyzers/src/SonarAnalyzer.Common/Common/FixAllProviders/DocumentBasedFixAllProvider.cs @@ -31,14 +31,14 @@ private DocumentBasedFixAllProvider() { } - private static readonly Lazy lazy = new Lazy(() => new DocumentBasedFixAllProvider()); - public static DocumentBasedFixAllProvider Instance => lazy.Value; + private static readonly Lazy Lazy = new(() => new DocumentBasedFixAllProvider()); + public static DocumentBasedFixAllProvider Instance => Lazy.Value; #endregion Singleton implementation - private const string titleSolutionPattern = "Fix all '{0}' in Solution"; - private const string titleScopePattern = "Fix all '{0}' in '{1}'"; - private const string titleFixAll = "Fix all '{0}'"; + private const string TitleSolutionPattern = "Fix all '{0}' in Solution"; + private const string TitleScopePattern = "Fix all '{0}' in '{1}'"; + private const string TitleFixAll = "Fix all '{0}'"; private static string GetFixAllTitle(FixAllContext fixAllContext) { @@ -48,16 +48,16 @@ private static string GetFixAllTitle(FixAllContext fixAllContext) switch (fixAllContext.Scope) { case FixAllScope.Document: - return string.Format(titleScopePattern, diagnosticId, fixAllContext.Document.Name); + return string.Format(TitleScopePattern, diagnosticId, fixAllContext.Document.Name); case FixAllScope.Project: - return string.Format(titleScopePattern, diagnosticId, fixAllContext.Project.Name); + return string.Format(TitleScopePattern, diagnosticId, fixAllContext.Project.Name); case FixAllScope.Solution: - return string.Format(titleSolutionPattern, diagnosticId); + return string.Format(TitleSolutionPattern, diagnosticId); default: - return titleFixAll; + return TitleFixAll; } } @@ -128,7 +128,7 @@ private static async Task GetFixedDocumentAsync(FixAllContext fixAll var currentDocument = document.WithSyntaxRoot(root); var annotatedElements = root.GetAnnotatedNodesAndTokens(annotationKind).ToList(); - while(annotatedElements.Any()) + while (annotatedElements.Any()) { var element = annotatedElements.First(); var annotation = element.GetAnnotations(annotationKind).First(); @@ -136,7 +136,7 @@ private static async Task GetFixedDocumentAsync(FixAllContext fixAll var location = root.GetAnnotatedNodesAndTokens(annotation).FirstOrDefault().GetLocation(); if (location == null) { - //annotation is already removed from the tree + // annotation is already removed from the tree continue; } @@ -184,7 +184,7 @@ private static SyntaxNodeOrToken GetReportedElement(Diagnostic diagnostic, Synta private static SyntaxNode RemoveAnnotationIfExists(SyntaxNode root, SyntaxAnnotation annotation) { var element = root.GetAnnotatedNodesAndTokens(annotation).FirstOrDefault(); - if (element == default(SyntaxNodeOrToken)) + if (element == default) { return root; } diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarCodeFix.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarCodeFix.cs index 0a1688a4809..896dac48170 100644 --- a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarCodeFix.cs @@ -42,12 +42,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) /// this problem: https://github.com/dotnet/roslyn/issues/4030 if (SonarAnalysisContext.LegacyIsRegisteredActionEnabled(Enumerable.Empty(), syntaxRoot.SyntaxTree)) { - await RegisterCodeFixesAsync(syntaxRoot, context).ConfigureAwait(false); + await RegisterCodeFixesAsync(syntaxRoot, new(context)).ConfigureAwait(false); } } public override FixAllProvider GetFixAllProvider() => DocumentBasedFixAllProvider.Instance; - protected abstract Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context); + protected abstract Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context); } diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/MultipleVariableDeclarationCodeFixBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/MultipleVariableDeclarationCodeFixBase.cs index b43a176d972..b8781edb999 100644 --- a/analyzers/src/SonarAnalyzer.Common/Rules/MultipleVariableDeclarationCodeFixBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Rules/MultipleVariableDeclarationCodeFixBase.cs @@ -18,9 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; - namespace SonarAnalyzer.Rules; public abstract class MultipleVariableDeclarationCodeFixBase : SonarCodeFix @@ -29,21 +26,18 @@ public abstract class MultipleVariableDeclarationCodeFixBase : SonarCodeFix public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(MultipleVariableDeclarationConstants.DiagnosticId); - protected sealed override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected sealed override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var node = root.FindNode(diagnosticSpan, getInnermostNodeForTie: true); - context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = CalculateNewRoot(root, node); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }, - Title), + Title, + c => + { + var newRoot = CalculateNewRoot(root, node); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/UnnecessaryBitwiseOperationCodeFixBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/UnnecessaryBitwiseOperationCodeFixBase.cs index ab85d259484..43a7acfc64a 100644 --- a/analyzers/src/SonarAnalyzer.Common/Rules/UnnecessaryBitwiseOperationCodeFixBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Rules/UnnecessaryBitwiseOperationCodeFixBase.cs @@ -18,8 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Text; namespace SonarAnalyzer.Rules @@ -32,14 +30,14 @@ public abstract class UnnecessaryBitwiseOperationCodeFixBase : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UnnecessaryBitwiseOperationBase.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var isReportingOnLeft = diagnostic.Properties.ContainsKey(UnnecessaryBitwiseOperationBase.IsReportingOnLeftKey) && bool.Parse(diagnostic.Properties[UnnecessaryBitwiseOperationBase.IsReportingOnLeftKey]); if (CreateNewRoot(root, diagnostic.Location.SourceSpan, isReportingOnLeft) is { } createNewRoot) { - context.RegisterCodeFix(CodeAction.Create(Title, c => Task.FromResult(context.Document.WithSyntaxRoot(createNewRoot()))), context.Diagnostics); + context.RegisterCodeFix(Title, c => Task.FromResult(context.Document.WithSyntaxRoot(createNewRoot())), context.Diagnostics); } return Task.CompletedTask; } diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/UseShortCircuitingOperatorCodeFixBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/UseShortCircuitingOperatorCodeFixBase.cs index ff41d25e3b9..25110cdc611 100644 --- a/analyzers/src/SonarAnalyzer.Common/Rules/UseShortCircuitingOperatorCodeFixBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Rules/UseShortCircuitingOperatorCodeFixBase.cs @@ -18,9 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; - namespace SonarAnalyzer.Rules { public abstract class UseShortCircuitingOperatorCodeFixBase : SonarCodeFix @@ -30,7 +27,7 @@ public abstract class UseShortCircuitingOperatorCodeFixBase : public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UseShortCircuitingOperatorBase.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -41,9 +38,8 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => ReplaceExpressionAsync(expression, root, context.Document)), + Title, + c => ReplaceExpressionAsync(expression, root, context.Document), context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/UseUnixEpochCodeFixBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/UseUnixEpochCodeFixBase.cs index f3df73236c8..15ead168fe7 100644 --- a/analyzers/src/SonarAnalyzer.Common/Rules/UseUnixEpochCodeFixBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Rules/UseUnixEpochCodeFixBase.cs @@ -18,9 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; - namespace SonarAnalyzer.Rules { public abstract class UseUnixEpochCodeFixBase : SonarCodeFix @@ -28,25 +25,24 @@ public abstract class UseUnixEpochCodeFixBase : SonarCodeFix { internal const string Title = "Use UnixEpoch field"; - protected abstract SyntaxNode ReplaceConstructorWithField(SyntaxNode root, SyntaxNode node, CodeFixContext context); + protected abstract SyntaxNode ReplaceConstructorWithField(SyntaxNode root, SyntaxNode node, SonarCodeFixContext context); public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(UseUnixEpochBase.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var node = root.FindNode(diagnosticSpan, getInnermostNodeForTie: true); context.RegisterCodeFix( - CodeAction.Create( - Title, - _ => - { - var newRoot = ReplaceConstructorWithField(root, node, context); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + _ => + { + var newRoot = ReplaceConstructorWithField(root, node, context); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayCreationLongSyntaxCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayCreationLongSyntaxCodeFix.cs index 7c074e26809..556bfd45d02 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayCreationLongSyntaxCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayCreationLongSyntaxCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.VisualBasic @@ -28,15 +27,9 @@ public sealed class ArrayCreationLongSyntaxCodeFix : SonarCodeFix { internal const string Title = "Use an array literal"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(ArrayCreationLongSyntax.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(ArrayCreationLongSyntax.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -61,16 +54,15 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (arrayCreation != null) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = root.ReplaceNode( - arrayCreation, - arrayCreation.Initializer); + Title, + c => + { + var newRoot = root.ReplaceNode( + arrayCreation, + arrayCreation.Initializer); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayDesignatorOnVariableCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayDesignatorOnVariableCodeFix.cs index 3fbeae459f3..3f615f50077 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayDesignatorOnVariableCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/ArrayDesignatorOnVariableCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.VisualBasic @@ -28,15 +27,9 @@ public sealed class ArrayDesignatorOnVariableCodeFix : SonarCodeFix { internal const string Title = "Move the array designator to the type"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(ArrayDesignatorOnVariable.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(ArrayDesignatorOnVariable.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -54,32 +47,32 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var type = simpleAsClause.Type.WithoutTrivia(); - var rankSpecifiers = name.ArrayRankSpecifiers.Select(rank => rank.WithoutTrivia()); - var newType = !(type is ArrayTypeSyntax typeAsArrayType) - ? SyntaxFactory.ArrayType( - type, - SyntaxFactory.List(rankSpecifiers)) - : typeAsArrayType.AddRankSpecifiers(rankSpecifiers.ToArray()); + Title, + c => + { + var type = simpleAsClause.Type.WithoutTrivia(); + var rankSpecifiers = name.ArrayRankSpecifiers.Select(rank => rank.WithoutTrivia()); + var newType = !(type is ArrayTypeSyntax typeAsArrayType) + ? SyntaxFactory.ArrayType( + type, + SyntaxFactory.List(rankSpecifiers)) + : typeAsArrayType.AddRankSpecifiers(rankSpecifiers.ToArray()); - newType = newType.WithTriviaFrom(simpleAsClause.Type); + newType = newType.WithTriviaFrom(simpleAsClause.Type); - var newVariableDeclarator = variableDeclarator - .WithNames(SyntaxFactory.SeparatedList(new[] { - SyntaxFactory.ModifiedIdentifier(name.Identifier, name.ArrayBounds).WithTriviaFrom(name) - })) - .WithAsClause(simpleAsClause.WithType(newType)); + var newVariableDeclarator = variableDeclarator + .WithNames(SyntaxFactory.SeparatedList(new[] + { + SyntaxFactory.ModifiedIdentifier(name.Identifier, name.ArrayBounds).WithTriviaFrom(name) + })) + .WithAsClause(simpleAsClause.WithType(newType)); - var newRoot = root.ReplaceNode( - variableDeclarator, - newVariableDeclarator); + var newRoot = root.ReplaceNode( + variableDeclarator, + newVariableDeclarator); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseByValCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseByValCodeFix.cs index e0d2c95dd07..be7b4bf39a2 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseByValCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseByValCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.VisualBasic @@ -31,7 +30,7 @@ public sealed class DoNotUseByValCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DoNotUseByVal.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -39,18 +38,17 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (root.FindNode(diagnosticSpan) is ParameterSyntax oldNode) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var modifiers = default(SyntaxTokenList) - .AddRange(oldNode.Modifiers.Where(m => !DoNotUseByVal.IsByVal(m))); - - var newNode = oldNode.WithModifiers(modifiers); - var newRoot = root.ReplaceNode(oldNode, newNode); - - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var modifiers = default(SyntaxTokenList) + .AddRange(oldNode.Modifiers.Where(m => !DoNotUseByVal.IsByVal(m))); + + var newNode = oldNode.WithModifiers(modifiers); + var newRoot = root.ReplaceNode(oldNode, newNode); + + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseIIfCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseIIfCodeFix.cs index 85fdce6bb0c..cccb8542a04 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseIIfCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/DoNotUseIIfCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.VisualBasic @@ -32,7 +31,7 @@ public sealed class DoNotUseIIfCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(DoNotUseIIf.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -40,18 +39,17 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (root.FindNode(diagnosticSpan) is InvocationExpressionSyntax iifInvocation) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var ifInvocation = SyntaxFactory.InvocationExpression( - SyntaxFactory.IdentifierName(IfOperatorName), iifInvocation.ArgumentList); - - var newRoot = root.ReplaceNode(iifInvocation, ifInvocation); - - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), - context.Diagnostics); + Title, + c => + { + var ifInvocation = SyntaxFactory.InvocationExpression( + SyntaxFactory.IdentifierName(IfOperatorName), iifInvocation.ArgumentList); + + var newRoot = root.ReplaceNode(iifInvocation, ifInvocation); + + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, + context.Diagnostics); } return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/NegatedIsExpressionCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/NegatedIsExpressionCodeFix.cs index 1c819bf8b9a..7133cd3a1d2 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/NegatedIsExpressionCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/NegatedIsExpressionCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.VisualBasic @@ -28,15 +27,9 @@ public sealed class NegatedIsExpressionCodeFix : SonarCodeFix { internal const string Title = "Replace 'Not...Is...' with 'IsNot'."; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(NegatedIsExpression.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(NegatedIsExpression.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -49,9 +42,8 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c } context.RegisterCodeFix( - CodeAction.Create( - Title, - c => ChangeToIsNotAsync(context.Document, unary, isExpression, c)), + Title, + c => ChangeToIsNotAsync(context.Document, unary, isExpression, c), context.Diagnostics); return Task.CompletedTask; diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/StringConcatenationWithPlusCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/StringConcatenationWithPlusCodeFix.cs index a22138d012e..e78851eb093 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/StringConcatenationWithPlusCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/StringConcatenationWithPlusCodeFix.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.Rules.VisualBasic @@ -28,15 +27,9 @@ public sealed class StringConcatenationWithPlusCodeFix : SonarCodeFix { internal const string Title = "Change to '&'"; - public override ImmutableArray FixableDiagnosticIds - { - get - { - return ImmutableArray.Create(StringConcatenationWithPlus.DiagnosticId); - } - } + public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(StringConcatenationWithPlus.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; @@ -44,13 +37,12 @@ protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext c if (root.FindNode(diagnosticSpan, getInnermostNodeForTie: true) is BinaryExpressionSyntax binary) { context.RegisterCodeFix( - CodeAction.Create( - Title, - c => - { - var newRoot = CalculateNewRoot(root, binary); - return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), + Title, + c => + { + var newRoot = CalculateNewRoot(root, binary); + return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); + }, context.Diagnostics); } diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/UseUnixEpochCodeFix.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/UseUnixEpochCodeFix.cs index 1ec36dcbaa8..53c7599cc61 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/UseUnixEpochCodeFix.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/UseUnixEpochCodeFix.cs @@ -25,7 +25,7 @@ namespace SonarAnalyzer.Rules.VisualBasic [ExportCodeFixProvider(LanguageNames.VisualBasic)] public sealed class UseUnixEpochCodeFix : UseUnixEpochCodeFixBase { - protected override SyntaxNode ReplaceConstructorWithField(SyntaxNode root, SyntaxNode node, CodeFixContext context) + protected override SyntaxNode ReplaceConstructorWithField(SyntaxNode root, SyntaxNode node, SonarCodeFixContext context) { var leadingTrivia = node.GetLeadingTrivia(); var trailingTrivia = node.GetTrailingTrivia(); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarCodeFixContextTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarCodeFixContextTest.cs new file mode 100644 index 00000000000..3fdd50b2c3f --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarCodeFixContextTest.cs @@ -0,0 +1,86 @@ +/* + * SonarAnalyzer for .NET + * Copyright (C) 2015-2023 SonarSource SA + * mailto: contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using SonarAnalyzer.AnalysisContext; + +namespace SonarAnalyzer.UnitTest.AnalysisContext +{ + [TestClass] + public class SonarCodeFixContextTest + { + [TestMethod] + public async Task SonarCodeFixContext_Properties_ReturnRoslynCodeFixContextProperties() + { + // Arrange + var document = CreateProject().FindDocument("MyFile.cs"); + var syntaxTree = await document.GetSyntaxTreeAsync(); + var literal = syntaxTree.GetRoot().DescendantNodesAndSelf().OfType().Single(); + var cancellationToken = new CancellationToken(true); + var diagnostic = Diagnostic.Create(new DiagnosticDescriptor("1", "title", "format", "category", DiagnosticSeverity.Hidden, false), literal.GetLocation()); + var sonarCodefix = new SonarCodeFixContext(new CodeFixContext(document, diagnostic, (_, _) => { }, cancellationToken)); + + // Act & Assert + sonarCodefix.CancellationToken.Should().Be(cancellationToken); + sonarCodefix.Document.Should().Be(document); + sonarCodefix.Diagnostics.Should().Contain(diagnostic); + sonarCodefix.Span.Should().Be(new TextSpan(18, 13)); + } + + [TestMethod] + public void SonarCodeFixContext_RegisterDocumentCodeFix_CodeFixRegistered() + { + // Arrange + var isActionRegistered = false; + var document = CreateProject().FindDocument("MyFile.cs"); + var diagnostic = Diagnostic.Create(new DiagnosticDescriptor("1", "title", "format", "category", DiagnosticSeverity.Hidden, false), Location.None); + var sonarCodefix = new SonarCodeFixContext(new CodeFixContext(document, diagnostic, (_, _) => isActionRegistered = true, CancellationToken.None)); + + // Act + sonarCodefix.RegisterCodeFix("Title", _ => Task.FromResult(document), ImmutableArray.Create(diagnostic)); + + // Assert + isActionRegistered.Should().BeTrue(); + } + + [TestMethod] + public void SonarCodeFixContext_RegisterSolutionCodeFix_CodeFixRegistered() + { + // Arrange + var isActionRegistered = false; + var document = CreateProject().FindDocument("MyFile.cs"); + var diagnostic = Diagnostic.Create(new DiagnosticDescriptor("1", "title", "format", "category", DiagnosticSeverity.Hidden, false), Location.None); + var sonarCodefix = new SonarCodeFixContext(new CodeFixContext(document, diagnostic, (_, _) => isActionRegistered = true, CancellationToken.None)); + + // Act + sonarCodefix.RegisterCodeFix("Title", _ => Task.FromResult(new AdhocWorkspace().CurrentSolution), ImmutableArray.Create(diagnostic)); + + // Assert + isActionRegistered.Should().BeTrue(); + } + + private static ProjectBuilder CreateProject() => + SolutionBuilder.Create() + .AddProject(AnalyzerLanguage.CSharp) + .AddSnippet(@"Console.WriteLine(""Hello World"")", "MyFile.cs"); + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Common/FixAllProviders/DocumentBasedFixAllProviderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Common/FixAllProviders/DocumentBasedFixAllProviderTest.cs new file mode 100644 index 00000000000..4616d47710f --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Common/FixAllProviders/DocumentBasedFixAllProviderTest.cs @@ -0,0 +1,124 @@ +/* + * SonarAnalyzer for .NET + * Copyright (C) 2015-2023 SonarSource SA + * mailto: contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using System.IO; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using SonarAnalyzer.UnitTest.TestFramework.Tests; + +namespace SonarAnalyzer.UnitTest.Common.FixAllProviders +{ + [TestClass] + public class DocumentBasedFixAllProviderTest + { + [DataTestMethod] + [DataRow(FixAllScope.Document, "Fix all 'SDummy' in 'MyFile1.cs'")] + [DataRow(FixAllScope.Project, "Fix all 'SDummy' in 'project0'")] + [DataRow(FixAllScope.Solution, "Fix all 'SDummy' in Solution")] + public async Task GetFixAsync_ForSupportedScope_HasCorrectTitle(FixAllScope scope, string expectedTitle) + { + var codeFix = new DummyCodeFixCS(); + var document = CreateProject().FindDocument("MyFile1.cs"); + var fixAllContext = new FixAllContext(document, codeFix, scope, "Dummy Action", codeFix.FixableDiagnosticIds, new FixAllDiagnosticProvider(null), default); + var result = await SonarAnalyzer.Common.DocumentBasedFixAllProvider.Instance.GetFixAsync(fixAllContext); + result.Title.Should().Be(expectedTitle); + } + + [TestMethod] + public async Task GetFixAsync_ForUnsupportedScope_ReturnsNull() + { + var codeFix = new DummyCodeFixCS(); + var document = CreateProject().FindDocument("MyFile1.cs"); + var fixAllContext = new FixAllContext(document, codeFix, FixAllScope.Custom, "Dummy Action", codeFix.FixableDiagnosticIds, new FixAllDiagnosticProvider(null), default); + var result = await SonarAnalyzer.Common.DocumentBasedFixAllProvider.Instance.GetFixAsync(fixAllContext); + result.Should().BeNull(); + } + + [TestMethod] + public async Task GetFixAsync_ForDocument_OnlyTheDocumentChanged() + { + var codeFix = new DummyCodeFixCS(); + var project = CreateProject(); + var document1Before = project.FindDocument("MyFile1.cs"); + var document2Before = project.FindDocument("MyFile2.cs"); + var compilation = project.GetCompilation(); + var diagnostics = DiagnosticVerifier.GetDiagnosticsNoExceptions(compilation, new DummyAnalyzerCS(), CompilationErrorBehavior.Ignore).ToImmutableArray(); + + var fixAllContext = new FixAllContext(document1Before, codeFix, FixAllScope.Document, "Dummy Action", codeFix.FixableDiagnosticIds, new FixAllDiagnosticProvider(diagnostics), default); + var result = await SonarAnalyzer.Common.DocumentBasedFixAllProvider.Instance.GetFixAsync(fixAllContext); + var executedOperation = await result.GetOperationsAsync(default); + var document1After = executedOperation.OfType().Single().ChangedSolution.GetDocument(document1Before.Id); + var document2After = executedOperation.OfType().Single().ChangedSolution.GetDocument(document2Before.Id); + + var document1BeforeRoot = await document1Before.GetSyntaxRootAsync(); + var document1BeforeContent = document1BeforeRoot.GetText().ToString(); + var document1AfterRoot = await document1After.GetSyntaxRootAsync(); + var document1AfterContent = document1AfterRoot.GetText().ToString(); + + document1BeforeContent.Should().NotBe(document1AfterContent); + + var document2BeforeRoot = await document2Before.GetSyntaxRootAsync(); + var document2BeforeContent = document2BeforeRoot.GetText().ToString(); + var document2AfterRoot = await document2After.GetSyntaxRootAsync(); + var document2AfterContent = document2AfterRoot.GetText().ToString(); + + document2BeforeContent.Should().Be(document2AfterContent); + } + + [DataTestMethod] + [DataRow(FixAllScope.Project)] + [DataRow(FixAllScope.Solution)] + public async Task GetFixAsync_ForProjectAndSolution_AllFilesAreFixed(FixAllScope scope) + { + var codeFix = new DummyCodeFixCS(); + var project = CreateProject(); + var document1Before = project.FindDocument("MyFile1.cs"); + var document2Before = project.FindDocument("MyFile2.cs"); + var compilation = project.GetCompilation(); + var diagnostics = DiagnosticVerifier.GetDiagnosticsNoExceptions(compilation, new DummyAnalyzerCS(), CompilationErrorBehavior.Ignore).ToImmutableArray(); + + var fixAllContext = new FixAllContext(project.Project, codeFix, scope, "Dummy Action", codeFix.FixableDiagnosticIds, new FixAllDiagnosticProvider(diagnostics), default); + var result = await SonarAnalyzer.Common.DocumentBasedFixAllProvider.Instance.GetFixAsync(fixAllContext); + var executedOperation = await result.GetOperationsAsync(default); + var document1After = executedOperation.OfType().Single().ChangedSolution.GetDocument(document1Before.Id); + var document2After = executedOperation.OfType().Single().ChangedSolution.GetDocument(document2Before.Id); + + var document1BeforeRoot = await document1Before.GetSyntaxRootAsync(); + var document1BeforeContent = document1BeforeRoot.GetText().ToString(); + var document1AfterRoot = await document1After.GetSyntaxRootAsync(); + var document1AfterContent = document1AfterRoot.GetText().ToString(); + + document1BeforeContent.Should().NotBe(document1AfterContent); + + var document2BeforeRoot = await document2Before.GetSyntaxRootAsync(); + var document2BeforeContent = document2BeforeRoot.GetText().ToString(); + var document2AfterRoot = await document2After.GetSyntaxRootAsync(); + var document2AfterContent = document2AfterRoot.GetText().ToString(); + + document2BeforeContent.Should().NotBe(document2AfterContent); + } + + private static ProjectBuilder CreateProject() => + SolutionBuilder.Create() + .AddProject(AnalyzerLanguage.CSharp, false) + .AddSnippet(@"public class C1 { public void M1() { int number1 = 1 } };", "MyFile1.cs") + .AddSnippet(@"public class C2 { public void M2() { int number2 = 2 } };", "MyFile2.cs"); + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/FixAllDiagnosticProvider.cs b/analyzers/tests/SonarAnalyzer.UnitTest/FixAllDiagnosticProvider.cs index 3d79e6d41fc..2182c220a54 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/FixAllDiagnosticProvider.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/FixAllDiagnosticProvider.cs @@ -18,8 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; namespace SonarAnalyzer.UnitTest diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/LiveVariableAnalysis/SonarLiveVariableAnalysisTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/LiveVariableAnalysis/SonarLiveVariableAnalysisTest.cs index 9f0f86391ef..77cafb5c9cd 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/LiveVariableAnalysis/SonarLiveVariableAnalysisTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/LiveVariableAnalysis/SonarLiveVariableAnalysisTest.cs @@ -640,7 +640,7 @@ private void Capturing(System.Func f) {{ }} else { var function = (LocalFunctionStatementSyntaxWrapper)method.DescendantNodes() - .Single(x => x.Kind() == SyntaxKindEx.LocalFunctionStatement && ((LocalFunctionStatementSyntaxWrapper)x).Identifier.Text == localFunctionName); + .Single(x => x.IsKind(SyntaxKindEx.LocalFunctionStatement) && ((LocalFunctionStatementSyntaxWrapper)x).Identifier.Text == localFunctionName); symbol = model.GetDeclaredSymbol(function) as IMethodSymbol; body = (CSharpSyntaxNode)function.Body ?? function.ExpressionBody; } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MethodOverrideChangedDefaultValueTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MethodOverrideChangedDefaultValueTest.cs index 78dc5ee9e53..021095d2dfa 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MethodOverrideChangedDefaultValueTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MethodOverrideChangedDefaultValueTest.cs @@ -59,11 +59,21 @@ public void MethodOverrideChangedDefaultValue_CSharp11_CodeFix() => #endif [TestMethod] - public void MethodOverrideChangedDefaultValue_CodeFix() => + public void MethodOverrideChangedDefaultValue_CodeFix_Synchronize() => builder.AddPaths("MethodOverrideChangedDefaultValue.cs") .WithCodeFix() - .WithCodeFixedPaths("MethodOverrideChangedDefaultValue.Fixed.cs", "MethodOverrideChangedDefaultValue.Fixed.Batch.cs") + .WithCodeFixedPaths("MethodOverrideChangedDefaultValue.Synchronize.Fixed.cs", "MethodOverrideChangedDefaultValue.Synchronize.Fixed.Batch.cs") .WithOptions(ParseOptionsHelper.FromCSharp8) + .WithCodeFixTitle(MethodOverrideChangedDefaultValueCodeFix.TitleGeneral) + .VerifyCodeFix(); + + [TestMethod] + public void MethodOverrideChangedDefaultValue_CodeFix_Remove() => + builder.AddPaths("MethodOverrideChangedDefaultValue.cs") + .WithCodeFix() + .WithCodeFixedPaths("MethodOverrideChangedDefaultValue.Remove.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp8) + .WithCodeFixTitle(MethodOverrideChangedDefaultValueCodeFix.TitleExplicitInterface) .VerifyCodeFix(); } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MultipleVariableDeclarationTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MultipleVariableDeclarationTest.cs index 68cae9e27db..cd6901445f0 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MultipleVariableDeclarationTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/MultipleVariableDeclarationTest.cs @@ -42,7 +42,6 @@ public void MultipleVariableDeclaration_CodeFix_CS_WrongIndentation() => builderCS.WithCodeFix() .AddPaths("MultipleVariableDeclaration.WrongIndentation.cs") .WithCodeFixedPaths("MultipleVariableDeclaration.WrongIndentation.Fixed.cs") - .WithCodeFixTitle(SonarAnalyzer.Rules.MultipleVariableDeclarationCodeFixBase.Title) .VerifyCodeFix(); [TestMethod] @@ -50,7 +49,6 @@ public void MultipleVariableDeclaration_CodeFix_CS() => builderCS.WithCodeFix() .AddPaths("MultipleVariableDeclaration.cs") .WithCodeFixedPaths("MultipleVariableDeclaration.Fixed.cs") - .WithCodeFixTitle(SonarAnalyzer.Rules.MultipleVariableDeclarationCodeFixBase.Title) .VerifyCodeFix(); [TestMethod] @@ -58,6 +56,5 @@ public void MultipleVariableDeclaration_CodeFix_VB() => builderVB.WithCodeFix() .AddPaths("MultipleVariableDeclaration.vb") .WithCodeFixedPaths("MultipleVariableDeclaration.Fixed.vb") - .WithCodeFixTitle(SonarAnalyzer.Rules.MultipleVariableDeclarationCodeFixBase.Title) .VerifyCodeFix(); } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/RedundantModifierTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/RedundantModifierTest.cs index 0de021b5197..5dfef0b0557 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/RedundantModifierTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/RedundantModifierTest.cs @@ -32,10 +32,35 @@ public void RedundantModifier() => builder.AddPaths("RedundantModifier.cs").Verify(); [TestMethod] - public void RedundantModifier_CodeFix() => + public void RedundantModifier_Unsafe_CodeFix() => builder.AddPaths("RedundantModifier.cs") .WithCodeFix() - .WithCodeFixedPaths("RedundantModifier.Fixed.cs") + .WithCodeFixedPaths("RedundantModifier.Unsafe.Fixed.cs") + .WithCodeFixTitle(RedundantModifierCodeFix.TitleUnsafe) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Checked_CodeFix() => + builder.AddPaths("RedundantModifier.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.Checked.Fixed.cs") + .WithCodeFixTitle(RedundantModifierCodeFix.TitleChecked) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Partial_CodeFix() => + builder.AddPaths("RedundantModifier.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.Partial.Fixed.cs") + .WithCodeFixTitle(RedundantModifierCodeFix.TitlePartial) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Sealed_CodeFix() => + builder.AddPaths("RedundantModifier.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.Sealed.Fixed.cs") + .WithCodeFixTitle(RedundantModifierCodeFix.TitleSealed) .VerifyCodeFix(); #if NET @@ -45,11 +70,39 @@ public void RedundantModifier_CSharp9() => builder.AddPaths("RedundantModifier.CSharp9.cs").WithOptions(ParseOptionsHelper.FromCSharp9).Verify(); [TestMethod] - public void RedundantModifier_CodeFix_CSharp9() => + public void RedundantModifier_Checked_CodeFix_CSharp9() => builder.AddPaths("RedundantModifier.CSharp9.cs") .WithCodeFix() - .WithCodeFixedPaths("RedundantModifier.CSharp9.Fixed.cs") + .WithCodeFixedPaths("RedundantModifier.CSharp9.Checked.Fixed.cs") .WithOptions(ParseOptionsHelper.FromCSharp9) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleChecked) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Partial_CodeFix_CSharp9() => + builder.AddPaths("RedundantModifier.CSharp9.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.CSharp9.Partial.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp9) + .WithCodeFixTitle(RedundantModifierCodeFix.TitlePartial) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Sealed_CodeFix_CSharp9() => + builder.AddPaths("RedundantModifier.CSharp9.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.CSharp9.Sealed.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp9) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleSealed) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Unsafe_CodeFix_CSharp9() => + builder.AddPaths("RedundantModifier.CSharp9.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.CSharp9.Unsafe.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp9) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleUnsafe) .VerifyCodeFix(); [TestMethod] @@ -57,11 +110,21 @@ public void RedundantModifier_CSharp10() => builder.AddPaths("RedundantModifier.CSharp10.cs").WithOptions(ParseOptionsHelper.FromCSharp10).Verify(); [TestMethod] - public void RedundantModifier_CodeFix_CSharp10() => + public void RedundantModifier_Unsafe_CodeFix_CSharp10() => + builder.AddPaths("RedundantModifier.CSharp10.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.CSharp10.Unsafe.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp10) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleUnsafe) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Checked_CodeFix_CSharp10() => builder.AddPaths("RedundantModifier.CSharp10.cs") .WithCodeFix() - .WithCodeFixedPaths("RedundantModifier.CSharp10.Fixed.cs") + .WithCodeFixedPaths("RedundantModifier.CSharp10.Checked.Fixed.cs") .WithOptions(ParseOptionsHelper.FromCSharp10) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleChecked) .VerifyCodeFix(); [TestMethod] @@ -71,11 +134,30 @@ public void RedundantModifier_CSharp11() => .Verify(); [TestMethod] - public void RedundantModifier_CodeFix_CSharp11() => + public void RedundantModifier_Partial_CodeFix_CSharp11() => + builder.AddPaths("RedundantModifier.CSharp11.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.CSharp11.Partial.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp11) + .WithCodeFixTitle(RedundantModifierCodeFix.TitlePartial) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Unsafe_CodeFix_CSharp11() => + builder.AddPaths("RedundantModifier.CSharp11.cs") + .WithCodeFix() + .WithCodeFixedPaths("RedundantModifier.CSharp11.Unsafe.Fixed.cs") + .WithOptions(ParseOptionsHelper.FromCSharp11) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleUnsafe) + .VerifyCodeFix(); + + [TestMethod] + public void RedundantModifier_Checked_CodeFix_CSharp11() => builder.AddPaths("RedundantModifier.CSharp11.cs") .WithCodeFix() - .WithCodeFixedPaths("RedundantModifier.CSharp11.Fixed.cs") + .WithCodeFixedPaths("RedundantModifier.CSharp11.Checked.Fixed.cs") .WithOptions(ParseOptionsHelper.FromCSharp11) + .WithCodeFixTitle(RedundantModifierCodeFix.TitleChecked) .VerifyCodeFix(); #endif diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Remove.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Remove.Fixed.cs new file mode 100644 index 00000000000..518208669be --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Remove.Fixed.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +namespace Tests.Diagnostics +{ + public interface IMyInterface + { + void Write(int i, int j = 5); + } + + public class Base : IMyInterface + { + public virtual void Write(int i, int j = 0) // Fixed + { + Console.WriteLine(i); + } + } + + public class Derived1 : Base + { + public override void Write(int i, + int j = 42) // Fixed + { + Console.WriteLine(i); + } + } + + public class Derived2 : Base + { + public override void Write(int i, + int j) // Fixed + { + Console.WriteLine(i); + } + } + + public class Derived3 : Base + { + public override void Write(int i = 5, // Fixed + int j = 0) + { + Console.WriteLine(i); + } + } + + public class ExplicitImpl1 : IMyInterface + { + void IMyInterface.Write(int i, + int j) // Fixed + { + } + } + + public interface IFirst + { + void Write(int i, int j = 5); + + void Write(int i = 42); + } + + public interface ISecond : IFirst + { + void Write(int i, int j = 5) + { + } + + void Write(int i = 0) // Compliant - This method can be called only after a cast to ISecond + { + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Fixed.Batch.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Synchronize.Fixed.Batch.cs similarity index 97% rename from analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Fixed.Batch.cs rename to analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Synchronize.Fixed.Batch.cs index 127336e0e7d..44cde21322b 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Fixed.Batch.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Synchronize.Fixed.Batch.cs @@ -46,7 +46,7 @@ public override void Write(int i, // Fixed public class ExplicitImpl1 : IMyInterface { void IMyInterface.Write(int i, - int j) // Fixed + int j = 0) // Fixed { } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Synchronize.Fixed.cs similarity index 97% rename from analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Fixed.cs rename to analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Synchronize.Fixed.cs index b925790cdf7..3b1d7d6a488 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Fixed.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/MethodOverrideChangedDefaultValue.Synchronize.Fixed.cs @@ -46,7 +46,7 @@ public override void Write(int i, // Fixed public class ExplicitImpl1 : IMyInterface { void IMyInterface.Write(int i, - int j) // Fixed + int j = 0) // Fixed { } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Checked.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Checked.Fixed.cs new file mode 100644 index 00000000000..7733f215f5d --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Checked.Fixed.cs @@ -0,0 +1,81 @@ +internal unsafe record struct UnsafeRecordStruct // Fixed +{ + int num; + + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe void M() // Fixed + { + } +} + +public record struct Foo +{ + public unsafe record struct Bar // Fixed + { + } + + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + public static void M() + { + checked + { + { + var z = 1 + 4; + var y = unchecked(1 + + 4); // Fixed + } + } + + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = 5.5 + 4; // Fixed + } + + unchecked + { + var f = 5.5; + var y = 5 + 4; // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + } +} + +public unsafe record struct RecordNewSyntax(string Input) // Fixed +{ + private string inputField = Input; +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Unsafe.Fixed.cs similarity index 84% rename from analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Fixed.cs rename to analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Unsafe.Fixed.cs index cfb51caf223..6acb1767026 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Fixed.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp10.Unsafe.Fixed.cs @@ -24,13 +24,15 @@ public static void M() { checked { + checked // Fixed { var z = 1 + 4; var y = unchecked(1 + - 4); // Fixed + unchecked(4)); // Fixed } } + checked // Fixed { var f = 5.5; var y = unchecked(5 + 4); @@ -47,13 +49,13 @@ public static void M() { var f = 5.5; var x = 5 + 4; - var y = 5.5 + 4; // Fixed + var y = unchecked(5.5 + 4); // Fixed } unchecked { var f = 5.5; - var y = 5 + 4; // Fixed + var y = unchecked(5 + 4); // Fixed } checked @@ -62,6 +64,7 @@ public static void M() var y = (int)x; } + checked // Fixed { var x = 10; var y = (double)x; diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Checked.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Checked.Fixed.cs new file mode 100644 index 00000000000..2eb33eb9c9e --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Checked.Fixed.cs @@ -0,0 +1,44 @@ +using System; + +public class Foo +{ + public static void Method() + { + { + nint x = 42; + IntPtr y = 2; + var _ = x + y; + } + + { + nuint x = 42; + UIntPtr y = 2; + var _ = x + y; + } + } +} + +// file-scoped types cannot use accessibility modifiers and cannot be nested. + +file partial class PartialFoo { } // Fixed + +file partial class PartialFooBar { } // Fixed + +file partial class PartialFileClass { } +file partial class PartialFileClass { } + + +file unsafe class UnsafeClass +{ + int* pointer; +} + +file unsafe class UnsafeClass2 // Fixed +{ + int num; +} + +file unsafe interface MyInterface +{ + unsafe int* Method(); // Fixed +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Partial.Fixed.cs similarity index 83% rename from analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Fixed.cs rename to analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Partial.Fixed.cs index aec0d166ee0..9b5019ef650 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Fixed.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Partial.Fixed.cs @@ -4,12 +4,14 @@ public class Foo { public static void Method() { + checked // Fixed { nint x = 42; IntPtr y = 2; var _ = x + y; } + checked // Fixed { nuint x = 42; UIntPtr y = 2; @@ -33,12 +35,12 @@ file unsafe class UnsafeClass int* pointer; } -file class UnsafeClass2 // Fixed +file unsafe class UnsafeClass2 // Fixed { int num; } file unsafe interface MyInterface { - int* Method(); // Fixed + unsafe int* Method(); // Fixed } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Unsafe.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Unsafe.Fixed.cs new file mode 100644 index 00000000000..ab42569391e --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp11.Unsafe.Fixed.cs @@ -0,0 +1,46 @@ +using System; + +public class Foo +{ + public static void Method() + { + checked // Fixed + { + nint x = 42; + IntPtr y = 2; + var _ = x + y; + } + + checked // Fixed + { + nuint x = 42; + UIntPtr y = 2; + var _ = x + y; + } + } +} + +// file-scoped types cannot use accessibility modifiers and cannot be nested. + +file partial class PartialFoo { } // Fixed + +file partial class PartialFooBar { } // Fixed + +file partial class PartialFileClass { } +file partial class PartialFileClass { } + + +file unsafe class UnsafeClass +{ + int* pointer; +} + +file class UnsafeClass2 // Fixed +{ + int num; +} + +file unsafe interface MyInterface +{ + int* Method(); // Fixed +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Checked.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Checked.Fixed.cs new file mode 100644 index 00000000000..c5326fa5235 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Checked.Fixed.cs @@ -0,0 +1,143 @@ +public record Record +{ + public virtual void MyNotOverriddenMethod() { } +} + +internal partial record PartialRecordDeclaredOnlyOnce // Fixed +{ + void Method() { } +} + +internal partial record PartialPositionalRecordDeclaredOnlyOnce(string parameter) // Fixed +{ + void Method() { } +} + +internal partial record PartialDeclaredMultipleTimes +{ +} + +internal partial record PartialDeclaredMultipleTimes +{ +} + +abstract record BaseRecord +{ + public abstract void MyOverriddenMethod(); + + public abstract int Prop { get; set; } +} + +sealed record SealedRecord : BaseRecord +{ + public sealed override void MyOverriddenMethod() { } // Fixed + + public sealed override int Prop { get; set; } // Fixed +} + +internal record BaseRecord +{ + public virtual string Process(string input) + { + return input; + } +} + +internal record SubRecord : BaseRecord +{ + public override string Process(string input) => "Test"; +} + +internal unsafe record UnsafeRecord // Fixed +{ + int num; + + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe void M() // Fixed + { + } + + unsafe ~UnsafeRecord() // Fixed + { + } +} + +public record Foo +{ + public unsafe record Bar // Fixed + { + } + + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + public static void M() + { + checked + { + { + var z = 1 + 4; + var y = unchecked(1 + + 4); // Fixed + } + } + + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = 5.5 + 4; // Fixed + } + + unchecked + { + var f = 5.5; + var y = 5 + 4; // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + + { + nint x = 42; + nuint y = 42; + + x += 42; + y += 42; + } + } +} + +public unsafe record RecordNewSyntax(string Input) // Fixed +{ + private string inputField = Input; +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Partial.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Partial.Fixed.cs new file mode 100644 index 00000000000..977920861ad --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Partial.Fixed.cs @@ -0,0 +1,147 @@ +public record Record +{ + public virtual void MyNotOverriddenMethod() { } +} + +internal record PartialRecordDeclaredOnlyOnce // Fixed +{ + void Method() { } +} + +internal record PartialPositionalRecordDeclaredOnlyOnce(string parameter) // Fixed +{ + void Method() { } +} + +internal partial record PartialDeclaredMultipleTimes +{ +} + +internal partial record PartialDeclaredMultipleTimes +{ +} + +abstract record BaseRecord +{ + public abstract void MyOverriddenMethod(); + + public abstract int Prop { get; set; } +} + +sealed record SealedRecord : BaseRecord +{ + public sealed override void MyOverriddenMethod() { } // Fixed + + public sealed override int Prop { get; set; } // Fixed +} + +internal record BaseRecord +{ + public virtual string Process(string input) + { + return input; + } +} + +internal record SubRecord : BaseRecord +{ + public override string Process(string input) => "Test"; +} + +internal unsafe record UnsafeRecord // Fixed +{ + int num; + + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe void M() // Fixed + { + } + + unsafe ~UnsafeRecord() // Fixed + { + } +} + +public record Foo +{ + public unsafe record Bar // Fixed + { + } + + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + public static void M() + { + checked + { + checked // Fixed + { + var z = 1 + 4; + var y = unchecked(1 + + unchecked(4)); // Fixed + } + } + + checked // Fixed + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5.5 + 4); // Fixed + } + + unchecked + { + var f = 5.5; + var y = unchecked(5 + 4); // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + checked // Fixed + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + + checked // Fixed + { + nint x = 42; + nuint y = 42; + + x += 42; + y += 42; + } + } +} + +public unsafe record RecordNewSyntax(string Input) // Fixed +{ + private string inputField = Input; +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Sealed.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Sealed.Fixed.cs new file mode 100644 index 00000000000..a077d1a9ef5 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Sealed.Fixed.cs @@ -0,0 +1,147 @@ +public record Record +{ + public virtual void MyNotOverriddenMethod() { } +} + +internal partial record PartialRecordDeclaredOnlyOnce // Fixed +{ + void Method() { } +} + +internal partial record PartialPositionalRecordDeclaredOnlyOnce(string parameter) // Fixed +{ + void Method() { } +} + +internal partial record PartialDeclaredMultipleTimes +{ +} + +internal partial record PartialDeclaredMultipleTimes +{ +} + +abstract record BaseRecord +{ + public abstract void MyOverriddenMethod(); + + public abstract int Prop { get; set; } +} + +sealed record SealedRecord : BaseRecord +{ + public override void MyOverriddenMethod() { } // Fixed + + public override int Prop { get; set; } // Fixed +} + +internal record BaseRecord +{ + public virtual string Process(string input) + { + return input; + } +} + +internal record SubRecord : BaseRecord +{ + public override string Process(string input) => "Test"; +} + +internal unsafe record UnsafeRecord // Fixed +{ + int num; + + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe void M() // Fixed + { + } + + unsafe ~UnsafeRecord() // Fixed + { + } +} + +public record Foo +{ + public unsafe record Bar // Fixed + { + } + + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + public static void M() + { + checked + { + checked // Fixed + { + var z = 1 + 4; + var y = unchecked(1 + + unchecked(4)); // Fixed + } + } + + checked // Fixed + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5.5 + 4); // Fixed + } + + unchecked + { + var f = 5.5; + var y = unchecked(5 + 4); // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + checked // Fixed + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + + checked // Fixed + { + nint x = 42; + nuint y = 42; + + x += 42; + y += 42; + } + } +} + +public unsafe record RecordNewSyntax(string Input) // Fixed +{ + private string inputField = Input; +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Unsafe.Fixed.cs similarity index 79% rename from analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Fixed.cs rename to analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Unsafe.Fixed.cs index 27c97e62c5b..be4229e105b 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Fixed.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.CSharp9.Unsafe.Fixed.cs @@ -3,12 +3,12 @@ public virtual void MyNotOverriddenMethod() { } } -internal record PartialRecordDeclaredOnlyOnce // Fixed +internal partial record PartialRecordDeclaredOnlyOnce // Fixed { void Method() { } } -internal record PartialPositionalRecordDeclaredOnlyOnce(string parameter) // Fixed +internal partial record PartialPositionalRecordDeclaredOnlyOnce(string parameter) // Fixed { void Method() { } } @@ -30,9 +30,9 @@ abstract record BaseRecord sealed record SealedRecord : BaseRecord { - public override void MyOverriddenMethod() { } // Fixed + public sealed override void MyOverriddenMethod() { } // Fixed - public override int Prop { get; set; } // Fixed + public sealed override int Prop { get; set; } // Fixed } internal record BaseRecord @@ -78,13 +78,15 @@ public static void M() { checked { + checked // Fixed { var z = 1 + 4; var y = unchecked(1 + - 4); // Fixed + unchecked(4)); // Fixed } } + checked // Fixed { var f = 5.5; var y = unchecked(5 + 4); @@ -101,13 +103,13 @@ public static void M() { var f = 5.5; var x = 5 + 4; - var y = 5.5 + 4; // Fixed + var y = unchecked(5.5 + 4); // Fixed } unchecked { var f = 5.5; - var y = 5 + 4; // Fixed + var y = unchecked(5 + 4); // Fixed } checked @@ -116,6 +118,7 @@ public static void M() var y = (int)x; } + checked // Fixed { var x = 10; var y = (double)x; @@ -127,6 +130,7 @@ public static void M() x += int.MaxValue; } + checked // Fixed { nint x = 42; nuint y = 42; diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Checked.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Checked.Fixed.cs new file mode 100644 index 00000000000..50b279db49a --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Checked.Fixed.cs @@ -0,0 +1,376 @@ +using System; + +namespace Tests.Diagnostics +{ + public class C1 + { + public virtual void MyNotOverriddenMethod() { } + } + internal partial class Partial1Part //Fixed + { + void Method() { } + } + partial struct PartialStruct //Fixed + { + } + partial interface PartialInterface //Fixed + { + } + + internal partial class Partial2Part + { + } + + internal abstract partial class Partial2Part + { + public virtual void MyOverriddenMethod() { } + public virtual int Prop { get; set; } + public abstract int this[int counter] { get; } + protected abstract event EventHandler MyEvent; + protected abstract event EventHandler MyEvent2; + } + + internal class Override : Partial2Part + { + public override void MyOverriddenMethod() { } + + public override int this[int counter] + { + get { return 0; } + } + + protected override event EventHandler MyEvent; + protected override event EventHandler MyEvent2 + { + add { } + remove { } + } + + public enum SomeEnumeration + { + + } + } + + sealed class SealedClass : Partial2Part + { + public override sealed void MyOverriddenMethod() { } // Fixed + public override sealed int Prop { get; set; } // Fixed + + public override sealed int this[int counter] // Fixed + { + get { return 0; } + } + + protected override sealed event EventHandler MyEvent; // Fixed + protected override sealed event EventHandler MyEvent2 // Fixed + { + add { } + remove { } + } + } + + abstract class AbstractClass : Partial2Part + { + public override sealed void MyOverriddenMethod() { } + public override sealed int Prop { get; set; } + + public override sealed int this[int counter] + { + get { return 0; } + } + + protected override sealed event EventHandler MyEvent; + protected override sealed event EventHandler MyEvent2 + { + add { } + remove { } + } + } + + sealed class SealedClassWithoutRedundantKeywordOnMembers : Partial2Part + { + public override void MyOverriddenMethod() { } + + public override int Prop { get; set; } + + public override int this[int counter] + { + get { return 0; } + } + + protected override event EventHandler MyEvent; + protected override event EventHandler MyEvent2 + { + add { } + remove { } + } + } + + internal class BaseClass + { + public virtual string Process(string input) + { + return input; + } + } + + internal class SubClass : BaseClass + { + public override string Process(string input) + { + return "Test"; + } + } + + unsafe class UnsafeClass + { + int* pointer; + } + + unsafe class UnsafeClass2 // Fixed + { + int num; + } + unsafe class UnsafeClass3 // Fixed + { + unsafe void M() // Fixed + { + + } + } + + class Point + { + public int x; + public int y; + } + + class Class4 + { + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + private unsafe delegate void MyDelegate(int* p); + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe class Inner { } // Fixed + + unsafe event MyDelegate MyEvent; // Fixed + unsafe event MyDelegate MyEvent2 + { + add + { + int* p; + } + remove { } + } + + unsafe ~Class4() // Fixed + { + } + void M() + { + Point pt = new Point(); + unsafe + { + fixed (int* p = &pt.x) + { + *p = 1; + } + } + + unsafe + { + unsafe // Fixed + { + unsafe // Fixed + { + var i = 1; + int* p = &i; + } + } + } + } + } + + public class Foo + { + public class Bar + { + public unsafe class Baz // Fixed + { + } + } + } + + public unsafe class Foo2 + { + public unsafe class Bar // Fixed + { + private int* p; + + public unsafe class Baz // Fixed + { + private int* p2; + } + } + } + + public class Checked + { + public static void M() + { + checked + { + { + var z = 1 + 4; + var y = unchecked(1 + + 4); // Fixed + } + } + + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = 5.5 + 4; // Fixed + } + + { + var f = 5.5; + var x = 5 + "somestring"; + } + + unchecked + { + var f = 5.5; + var y = 5 + 4; // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + + checked + { + var x = 10; + x = -int.MaxValue; + } + + checked + { + var x = 10; + x = -5; + } + + { + var x = 10; + x = -"1"; // Error [CS0023] + } + + { + var x = 10; + x = +5; + } + + { + var x = 10; + var y = 5 % x; + } + + checked + { + var x = (uint)null; // Error [CS0037] + var y = (int)x; + } + + checked + { + var x = (SomeClass)5; // Error [CS0246] + var y = (int)x; + } + } + } + + public unsafe struct FixedArraySample + { + private fixed int a[10]; + } + + public class StackAlloc + { + private unsafe void M() + { + var x = stackalloc int[100]; + } + } + + public class UnsafeHidden + { + private unsafe int* Method() { return null; } + private unsafe void Method2(int* p) { } + public unsafe void M1() + { + Method(); + } + + public unsafe void WithUndefinedInvocation() // Fixed + { + Undefined(); // Error [CS0103]: The name 'Undefined' does not exist in the current context + } + + private unsafe int* Prop { get; set; } + public unsafe void M2() + { + Method2(Prop); + } + } + + public class UnsafeParameter + { + public unsafe delegate void Unsafe(int* x); + + public unsafe void Method() + { + Unsafe u = (a) => { }; + } + } + + public class UnsafeCtor + { + public UnsafeCtor() + { + unsafe // Fixed + { + } + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Partial.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Partial.Fixed.cs new file mode 100644 index 00000000000..fe049385a19 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Partial.Fixed.cs @@ -0,0 +1,383 @@ +using System; + +namespace Tests.Diagnostics +{ + public class C1 + { + public virtual void MyNotOverriddenMethod() { } + } + internal class Partial1Part //Fixed + { + void Method() { } + } + struct PartialStruct //Fixed + { + } + interface PartialInterface //Fixed + { + } + + internal partial class Partial2Part + { + } + + internal abstract partial class Partial2Part + { + public virtual void MyOverriddenMethod() { } + public virtual int Prop { get; set; } + public abstract int this[int counter] { get; } + protected abstract event EventHandler MyEvent; + protected abstract event EventHandler MyEvent2; + } + + internal class Override : Partial2Part + { + public override void MyOverriddenMethod() { } + + public override int this[int counter] + { + get { return 0; } + } + + protected override event EventHandler MyEvent; + protected override event EventHandler MyEvent2 + { + add { } + remove { } + } + + public enum SomeEnumeration + { + + } + } + + sealed class SealedClass : Partial2Part + { + public override sealed void MyOverriddenMethod() { } // Fixed + public override sealed int Prop { get; set; } // Fixed + + public override sealed int this[int counter] // Fixed + { + get { return 0; } + } + + protected override sealed event EventHandler MyEvent; // Fixed + protected override sealed event EventHandler MyEvent2 // Fixed + { + add { } + remove { } + } + } + + abstract class AbstractClass : Partial2Part + { + public override sealed void MyOverriddenMethod() { } + public override sealed int Prop { get; set; } + + public override sealed int this[int counter] + { + get { return 0; } + } + + protected override sealed event EventHandler MyEvent; + protected override sealed event EventHandler MyEvent2 + { + add { } + remove { } + } + } + + sealed class SealedClassWithoutRedundantKeywordOnMembers : Partial2Part + { + public override void MyOverriddenMethod() { } + + public override int Prop { get; set; } + + public override int this[int counter] + { + get { return 0; } + } + + protected override event EventHandler MyEvent; + protected override event EventHandler MyEvent2 + { + add { } + remove { } + } + } + + internal class BaseClass + { + public virtual string Process(string input) + { + return input; + } + } + + internal class SubClass : BaseClass + { + public override string Process(string input) + { + return "Test"; + } + } + + unsafe class UnsafeClass + { + int* pointer; + } + + unsafe class UnsafeClass2 // Fixed + { + int num; + } + unsafe class UnsafeClass3 // Fixed + { + unsafe void M() // Fixed + { + + } + } + + class Point + { + public int x; + public int y; + } + + class Class4 + { + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + private unsafe delegate void MyDelegate(int* p); + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe class Inner { } // Fixed + + unsafe event MyDelegate MyEvent; // Fixed + unsafe event MyDelegate MyEvent2 + { + add + { + int* p; + } + remove { } + } + + unsafe ~Class4() // Fixed + { + } + void M() + { + Point pt = new Point(); + unsafe + { + fixed (int* p = &pt.x) + { + *p = 1; + } + } + + unsafe + { + unsafe // Fixed + { + unsafe // Fixed + { + var i = 1; + int* p = &i; + } + } + } + } + } + + public class Foo + { + public class Bar + { + public unsafe class Baz // Fixed + { + } + } + } + + public unsafe class Foo2 + { + public unsafe class Bar // Fixed + { + private int* p; + + public unsafe class Baz // Fixed + { + private int* p2; + } + } + } + + public class Checked + { + public static void M() + { + checked + { + checked // Fixed + { + var z = 1 + 4; + var y = unchecked(1 + + unchecked(4)); // Fixed + } + } + + checked // Fixed + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5.5 + 4); // Fixed + } + + checked // Fixed + { + var f = 5.5; + var x = 5 + "somestring"; + } + + unchecked + { + var f = 5.5; + var y = unchecked(5 + 4); // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + checked // Fixed + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + + checked + { + var x = 10; + x = -int.MaxValue; + } + + checked + { + var x = 10; + x = -5; + } + + checked // Fixed + { + var x = 10; + x = -"1"; // Error [CS0023] + } + + checked // Fixed + { + var x = 10; + x = +5; + } + + checked // Fixed + { + var x = 10; + var y = 5 % x; + } + + checked + { + var x = (uint)null; // Error [CS0037] + var y = (int)x; + } + + checked + { + var x = (SomeClass)5; // Error [CS0246] + var y = (int)x; + } + } + } + + public unsafe struct FixedArraySample + { + private fixed int a[10]; + } + + public class StackAlloc + { + private unsafe void M() + { + var x = stackalloc int[100]; + } + } + + public class UnsafeHidden + { + private unsafe int* Method() { return null; } + private unsafe void Method2(int* p) { } + public unsafe void M1() + { + Method(); + } + + public unsafe void WithUndefinedInvocation() // Fixed + { + Undefined(); // Error [CS0103]: The name 'Undefined' does not exist in the current context + } + + private unsafe int* Prop { get; set; } + public unsafe void M2() + { + Method2(Prop); + } + } + + public class UnsafeParameter + { + public unsafe delegate void Unsafe(int* x); + + public unsafe void Method() + { + Unsafe u = (a) => { }; + } + } + + public class UnsafeCtor + { + public UnsafeCtor() + { + unsafe // Fixed + { + } + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Sealed.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Sealed.Fixed.cs new file mode 100644 index 00000000000..70d3980d0d1 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Sealed.Fixed.cs @@ -0,0 +1,383 @@ +using System; + +namespace Tests.Diagnostics +{ + public class C1 + { + public virtual void MyNotOverriddenMethod() { } + } + internal partial class Partial1Part //Fixed + { + void Method() { } + } + partial struct PartialStruct //Fixed + { + } + partial interface PartialInterface //Fixed + { + } + + internal partial class Partial2Part + { + } + + internal abstract partial class Partial2Part + { + public virtual void MyOverriddenMethod() { } + public virtual int Prop { get; set; } + public abstract int this[int counter] { get; } + protected abstract event EventHandler MyEvent; + protected abstract event EventHandler MyEvent2; + } + + internal class Override : Partial2Part + { + public override void MyOverriddenMethod() { } + + public override int this[int counter] + { + get { return 0; } + } + + protected override event EventHandler MyEvent; + protected override event EventHandler MyEvent2 + { + add { } + remove { } + } + + public enum SomeEnumeration + { + + } + } + + sealed class SealedClass : Partial2Part + { + public override void MyOverriddenMethod() { } // Fixed + public override int Prop { get; set; } // Fixed + + public override int this[int counter] // Fixed + { + get { return 0; } + } + + protected override event EventHandler MyEvent; // Fixed + protected override event EventHandler MyEvent2 // Fixed + { + add { } + remove { } + } + } + + abstract class AbstractClass : Partial2Part + { + public override sealed void MyOverriddenMethod() { } + public override sealed int Prop { get; set; } + + public override sealed int this[int counter] + { + get { return 0; } + } + + protected override sealed event EventHandler MyEvent; + protected override sealed event EventHandler MyEvent2 + { + add { } + remove { } + } + } + + sealed class SealedClassWithoutRedundantKeywordOnMembers : Partial2Part + { + public override void MyOverriddenMethod() { } + + public override int Prop { get; set; } + + public override int this[int counter] + { + get { return 0; } + } + + protected override event EventHandler MyEvent; + protected override event EventHandler MyEvent2 + { + add { } + remove { } + } + } + + internal class BaseClass + { + public virtual string Process(string input) + { + return input; + } + } + + internal class SubClass : BaseClass + { + public override string Process(string input) + { + return "Test"; + } + } + + unsafe class UnsafeClass + { + int* pointer; + } + + unsafe class UnsafeClass2 // Fixed + { + int num; + } + unsafe class UnsafeClass3 // Fixed + { + unsafe void M() // Fixed + { + + } + } + + class Point + { + public int x; + public int y; + } + + class Class4 + { + unsafe interface MyInterface + { + unsafe int* Method(); // Fixed + } + + private unsafe delegate void MyDelegate(int* p); + private unsafe delegate void MyDelegate2(int i); // Fixed + + unsafe class Inner { } // Fixed + + unsafe event MyDelegate MyEvent; // Fixed + unsafe event MyDelegate MyEvent2 + { + add + { + int* p; + } + remove { } + } + + unsafe ~Class4() // Fixed + { + } + void M() + { + Point pt = new Point(); + unsafe + { + fixed (int* p = &pt.x) + { + *p = 1; + } + } + + unsafe + { + unsafe // Fixed + { + unsafe // Fixed + { + var i = 1; + int* p = &i; + } + } + } + } + } + + public class Foo + { + public class Bar + { + public unsafe class Baz // Fixed + { + } + } + } + + public unsafe class Foo2 + { + public unsafe class Bar // Fixed + { + private int* p; + + public unsafe class Baz // Fixed + { + private int* p2; + } + } + } + + public class Checked + { + public static void M() + { + checked + { + checked // Fixed + { + var z = 1 + 4; + var y = unchecked(1 + + unchecked(4)); // Fixed + } + } + + checked // Fixed + { + var f = 5.5; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5 + 4); + } + + checked + { + var f = 5.5; + var x = 5 + 4; + var y = unchecked(5.5 + 4); // Fixed + } + + checked // Fixed + { + var f = 5.5; + var x = 5 + "somestring"; + } + + unchecked + { + var f = 5.5; + var y = unchecked(5 + 4); // Fixed + } + + checked + { + var x = (uint)10; + var y = (int)x; + } + + checked // Fixed + { + var x = 10; + var y = (double)x; + } + + checked + { + var x = 10; + x += int.MaxValue; + } + + checked + { + var x = 10; + x = -int.MaxValue; + } + + checked + { + var x = 10; + x = -5; + } + + checked // Fixed + { + var x = 10; + x = -"1"; // Error [CS0023] + } + + checked // Fixed + { + var x = 10; + x = +5; + } + + checked // Fixed + { + var x = 10; + var y = 5 % x; + } + + checked + { + var x = (uint)null; // Error [CS0037] + var y = (int)x; + } + + checked + { + var x = (SomeClass)5; // Error [CS0246] + var y = (int)x; + } + } + } + + public unsafe struct FixedArraySample + { + private fixed int a[10]; + } + + public class StackAlloc + { + private unsafe void M() + { + var x = stackalloc int[100]; + } + } + + public class UnsafeHidden + { + private unsafe int* Method() { return null; } + private unsafe void Method2(int* p) { } + public unsafe void M1() + { + Method(); + } + + public unsafe void WithUndefinedInvocation() // Fixed + { + Undefined(); // Error [CS0103]: The name 'Undefined' does not exist in the current context + } + + private unsafe int* Prop { get; set; } + public unsafe void M2() + { + Method2(Prop); + } + } + + public class UnsafeParameter + { + public unsafe delegate void Unsafe(int* x); + + public unsafe void Method() + { + Unsafe u = (a) => { }; + } + } + + public class UnsafeCtor + { + public UnsafeCtor() + { + unsafe // Fixed + { + } + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Fixed.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Unsafe.Fixed.cs similarity index 88% rename from analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Fixed.cs rename to analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Unsafe.Fixed.cs index 4ad5d018694..bd61200e8ce 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Fixed.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantModifier.Unsafe.Fixed.cs @@ -6,14 +6,14 @@ public class C1 { public virtual void MyNotOverriddenMethod() { } } - internal class Partial1Part //Fixed + internal partial class Partial1Part //Fixed { void Method() { } } - struct PartialStruct //Fixed + partial struct PartialStruct //Fixed { } - interface PartialInterface //Fixed + partial interface PartialInterface //Fixed { } @@ -54,16 +54,16 @@ public enum SomeEnumeration sealed class SealedClass : Partial2Part { - public override void MyOverriddenMethod() { } // Fixed - public override int Prop { get; set; } // Fixed + public override sealed void MyOverriddenMethod() { } // Fixed + public override sealed int Prop { get; set; } // Fixed - public override int this[int counter] // Fixed + public override sealed int this[int counter] // Fixed { get { return 0; } } - protected override event EventHandler MyEvent; // Fixed - protected override event EventHandler MyEvent2 // Fixed + protected override sealed event EventHandler MyEvent; // Fixed + protected override sealed event EventHandler MyEvent2 // Fixed { add { } remove { } @@ -219,13 +219,15 @@ public static void M() { checked { + checked // Fixed { var z = 1 + 4; var y = unchecked(1 + - 4); // Fixed + unchecked(4)); // Fixed } } + checked // Fixed { var f = 5.5; var y = unchecked(5 + 4); @@ -242,9 +244,10 @@ public static void M() { var f = 5.5; var x = 5 + 4; - var y = 5.5 + 4; // Fixed + var y = unchecked(5.5 + 4); // Fixed } + checked // Fixed { var f = 5.5; var x = 5 + "somestring"; @@ -253,7 +256,7 @@ public static void M() unchecked { var f = 5.5; - var y = 5 + 4; // Fixed + var y = unchecked(5 + 4); // Fixed } checked @@ -262,6 +265,7 @@ public static void M() var y = (int)x; } + checked // Fixed { var x = 10; var y = (double)x; @@ -285,16 +289,19 @@ public static void M() x = -5; } + checked // Fixed { var x = 10; x = -"1"; // Error [CS0023] } + checked // Fixed { var x = 10; x = +5; } + checked // Fixed { var x = 10; var y = 5 % x; diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/CodeFixVerifier.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/CodeFixVerifier.cs index c633134c1bd..19f1563eae4 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/CodeFixVerifier.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/CodeFixVerifier.cs @@ -71,7 +71,9 @@ public void VerifyFixAllProvider(FixAllProvider fixAllProvider, ParseOptions par state.Diagnostics.Should().NotBeEmpty(); var fixAllDiagnosticProvider = new FixAllDiagnosticProvider(state.Diagnostics); - var fixAllContext = new FixAllContext(state.Document, codeFix, FixAllScope.Document, codeFixTitle, codeFix.FixableDiagnosticIds, fixAllDiagnosticProvider, default); + + var codeActionEquivalenceKey = codeFixTitle ?? RetrieveCodeFixTitle(codeFix, state); // We need to find the title of the single action to use + var fixAllContext = new FixAllContext(state.Document, codeFix, FixAllScope.Document, codeActionEquivalenceKey, codeFix.FixableDiagnosticIds, fixAllDiagnosticProvider, default); var codeActionToExecute = fixAllProvider.GetFixAsync(fixAllContext).Result; codeActionToExecute.Should().NotBeNull(); @@ -79,6 +81,9 @@ public void VerifyFixAllProvider(FixAllProvider fixAllProvider, ParseOptions par .AssertExpected(pathToExpected, $"{nameof(VerifyFixAllProvider)} runs {fixAllProvider.GetType().Name} once"); } + private string RetrieveCodeFixTitle(CodeFixProvider codeFix, State state) => + state.Diagnostics.SelectMany(diagnostic => ActionToApply(codeFix, state.Document, diagnostic)).FirstOrDefault()?.Title; + private static Document ApplyCodeFix(Document document, CodeAction codeAction) { var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result; @@ -128,22 +133,22 @@ private string ActualCodeWithReplacedComments() => .Where(x => !IssueLocationCollector.RxPreciseLocation.IsMatch(x)) .Select(ReplaceNonCompliantComment) .JoinStr(Constants.UnixLineEnding); - } - private static string ReplaceNonCompliantComment(string line) - { - var match = IssueLocationCollector.RxIssue.Match(line); - if (!match.Success) + private static string ReplaceNonCompliantComment(string line) { - return line; - } + var match = IssueLocationCollector.RxIssue.Match(line); + if (!match.Success) + { + return line; + } - if (match.Groups["issueType"].Value == "Noncompliant") - { - var startIndex = line.IndexOf(match.Groups["issueType"].Value); - return string.Concat(line.Remove(startIndex), FixedMessage); - } + if (match.Groups["issueType"].Value == "Noncompliant") + { + var startIndex = line.IndexOf(match.Groups["issueType"].Value); + return string.Concat(line.Remove(startIndex), FixedMessage); + } - return line.Replace(match.Value, string.Empty).TrimEnd(); + return line.Replace(match.Value, string.Empty).TrimEnd(); + } } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/ProjectBuilder.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/ProjectBuilder.cs index 2e613a9c6cb..365563164cc 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/ProjectBuilder.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/ProjectBuilder.cs @@ -30,6 +30,7 @@ internal readonly struct ProjectBuilder private readonly string fileExtension; public SolutionBuilder Solution => solution.Value; + public Project Project => project; private ProjectBuilder(Project project) { diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/CodeFixProviderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/CodeFixProviderTest.cs index 477c251d13e..704432308b6 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/CodeFixProviderTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/CodeFixProviderTest.cs @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using SonarAnalyzer.AnalysisContext; @@ -63,9 +62,9 @@ private class TestDuplicateLocationRuleCodeFix : SonarCodeFix { public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(TestDuplicateLocationRule.DiagnosticId); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { - context.RegisterCodeFix(CodeAction.Create("TestTitle", c => Task.FromResult(context.Document)), context.Diagnostics); + context.RegisterCodeFix("TestTitle", c => Task.FromResult(context.Document), context.Diagnostics); return Task.CompletedTask; } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyCodeFix.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyCodeFix.cs index a733fb5bbf8..3b368cd165a 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyCodeFix.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyCodeFix.cs @@ -18,9 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using SonarAnalyzer.AnalysisContext; using CS = Microsoft.CodeAnalysis.CSharp; using VB = Microsoft.CodeAnalysis.VisualBasic; @@ -44,14 +43,14 @@ internal abstract class DummyCodeFix : SonarCodeFix public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create("SDummy"); - protected override Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context) + protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context) { - context.RegisterCodeFix(CodeAction.Create("Dummy Action", _ => + context.RegisterCodeFix("Dummy Action", _ => { var oldNode = root.FindNode(context.Diagnostics.Single().Location.SourceSpan); var newRoot = root.ReplaceNode(oldNode, NewNode().WithTriviaFrom(oldNode)); return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); - }), context.Diagnostics); + }, context.Diagnostics); return Task.CompletedTask; } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyUtilityAnalyzer.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyUtilityAnalyzer.cs index 4f2ce15bdca..6efc087626d 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyUtilityAnalyzer.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/Tests/DummyUtilityAnalyzer.cs @@ -37,7 +37,7 @@ internal class DummyUtilityAnalyzerVB : DummyUtilityAnalyzer public DummyUtilityAnalyzerVB(string protobufPath, IMessage message) : base(protobufPath, message) { } } - internal class DummyUtilityAnalyzer : UtilityAnalyzerBase + internal abstract class DummyUtilityAnalyzer : UtilityAnalyzerBase { private readonly string protobufPath; private readonly IMessage message;