diff --git a/ChangeLog.md b/ChangeLog.md index c5cf396474..9ebe4b54b2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add SECURITY.md ([#1147](https://github.com/josefpihrt/roslynator/pull/1147)) +- [RCS1211](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1211) will suggest removing unecessary 'else if' clauses ([#1155](https://github.com/josefpihrt/roslynator/pull/1155)) ### Fixed diff --git a/src/Analyzers/CSharp/Analysis/RemoveUnnecessaryElseAnalyzer.cs b/src/Analyzers/CSharp/Analysis/RemoveUnnecessaryElseAnalyzer.cs index f1d104c584..db3cc9c8fd 100644 --- a/src/Analyzers/CSharp/Analysis/RemoveUnnecessaryElseAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/RemoveUnnecessaryElseAnalyzer.cs @@ -47,9 +47,6 @@ public static void Analyze(SyntaxNodeAnalysisContext context) private static bool IsFixable(ElseClauseSyntax elseClause, SemanticModel semanticModel) { - if (elseClause.Statement?.IsKind(SyntaxKind.IfStatement) != false) - return false; - if (elseClause.Parent is not IfStatementSyntax ifStatement) return false; @@ -61,22 +58,19 @@ private static bool IsFixable(ElseClauseSyntax elseClause, SemanticModel semanti if (ifStatementStatement is not BlockSyntax ifBlock) return CSharpFacts.IsJumpStatement(ifStatementStatement.Kind()); - if (elseClause.Statement is BlockSyntax elseBlock) - { - if (LocalDeclaredVariablesOverlap(elseBlock, ifBlock, semanticModel)) - return false; - - if (ifStatement.Parent is SwitchSectionSyntax { Parent: SwitchStatementSyntax switchStatement } - && SwitchLocallyDeclaredVariablesHelper.BlockDeclaredVariablesOverlapWithOtherSwitchSections(elseBlock, switchStatement, semanticModel)) - { - return false; - } - } - StatementSyntax lastStatementInIf = ifBlock.Statements.LastOrDefault(); - return lastStatementInIf is not null - && CSharpFacts.IsJumpStatement(lastStatementInIf.Kind()); + if (lastStatementInIf is null || !CSharpFacts.IsJumpStatement(lastStatementInIf.Kind())) + return false; + + if (elseClause.Statement is not BlockSyntax elseBlock) + return true; + + if (LocalDeclaredVariablesOverlap(elseBlock, ifBlock, semanticModel)) + return false; + + return ifStatement.Parent is not SwitchSectionSyntax { Parent: SwitchStatementSyntax switchStatement } + || !SwitchLocallyDeclaredVariablesHelper.BlockDeclaredVariablesOverlapWithOtherSwitchSections(elseBlock, switchStatement, semanticModel); } private static bool LocalDeclaredVariablesOverlap(BlockSyntax elseBlock, BlockSyntax ifBlock, SemanticModel semanticModel) diff --git a/src/Tests/Analyzers.Tests/RCS1211RemoveUnnecessaryElseTests.cs b/src/Tests/Analyzers.Tests/RCS1211RemoveUnnecessaryElseTests.cs index a96f4d595d..e45ec31a0a 100644 --- a/src/Tests/Analyzers.Tests/RCS1211RemoveUnnecessaryElseTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1211RemoveUnnecessaryElseTests.cs @@ -46,6 +46,47 @@ int M(bool flag) "); } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.RemoveUnnecessaryElse)] + public async Task Test_UnnecessaryElseIf_Removed() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + int M(bool flag, bool flag2) + { + if (flag) + { + return 1; + } + [|else|] if (flag2) + { + return 0; + } + + return 2; + } +} +", @" +class C +{ + int M(bool flag, bool flag2) + { + if (flag) + { + return 1; + } + + if (flag2) + { + return 0; + } + + return 2; + } +} +"); + } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.RemoveUnnecessaryElse)] public async Task TestNoDiagnostic_OverlappingLocalVariables() {