From c5a16ff9660957ddbc59b04c245a9961c652be4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 13:44:34 +0000 Subject: [PATCH 1/3] Initial plan From 7d28e212ce0a80796dc66188e16b118e8b8d3071 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 13:57:35 +0000 Subject: [PATCH 2/3] fix(MA0071): avoid false positive in else-if chains with reachable prior branch Agent-Logs-Url: https://github.com/meziantou/Meziantou.Analyzer/sessions/55a3c6a5-3f42-4e6e-9365-784352b50c33 Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com> --- docs/Rules/MA0071.md | 1 + .../Rules/AvoidUsingRedundantElseAnalyzer.cs | 18 +++++++++ .../AvoidUsingRedundantElseAnalyzerTests.cs | 38 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/docs/Rules/MA0071.md b/docs/Rules/MA0071.md index 4a771e7ba..72954e291 100644 --- a/docs/Rules/MA0071.md +++ b/docs/Rules/MA0071.md @@ -4,6 +4,7 @@ Sources: [AvoidUsingRedundantElseAnalyzer.cs](https://github.com/meziantou/Mezia When an `if` block contains a jump statement (`break`, `continue`, `goto`, `return`, `throw`, `yield break`), using an `else` block is redundant and needlessly maintains a higher nesting level. +In an `else if` chain, this simplification only applies when all previous `if` branches in the chain also jump unconditionally. The rule helps reduce overall nesting, as well as the total number of lines. Refer to [Computer Programming/Coding Style/Minimize nesting](https://en.wikibooks.org/wiki/Computer_Programming/Coding_Style/Minimize_nesting). diff --git a/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs b/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs index 12a631959..27ce097bd 100644 --- a/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs +++ b/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs @@ -64,12 +64,30 @@ private static void AnalyzeElseClause(SyntaxNodeAnalysisContext context) if (controlFlowAnalysis is null || !controlFlowAnalysis.Succeeded) return; + if (!CanExecuteOutsideElseIfChain(context.SemanticModel, ifStatement)) + return; + if (!controlFlowAnalysis.EndPointIsReachable) { context.ReportDiagnostic(Rule, elseClause.ElseKeyword); } } + private static bool CanExecuteOutsideElseIfChain(SemanticModel semanticModel, IfStatementSyntax ifStatement) + { + var currentIfStatement = ifStatement; + while (currentIfStatement.Parent is ElseClauseSyntax { Parent: IfStatementSyntax parentIfStatement }) + { + var controlFlowAnalysis = semanticModel.AnalyzeControlFlow(parentIfStatement.Statement); + if (controlFlowAnalysis is null || !controlFlowAnalysis.Succeeded || controlFlowAnalysis.EndPointIsReachable) + return false; + + currentIfStatement = parentIfStatement; + } + + return true; + } + private static IEnumerable FindLocalIdentifiersIn(SyntaxNode node) { foreach (var child in node.DescendantNodes()) diff --git a/tests/Meziantou.Analyzer.Test/Rules/AvoidUsingRedundantElseAnalyzerTests.cs b/tests/Meziantou.Analyzer.Test/Rules/AvoidUsingRedundantElseAnalyzerTests.cs index d5373f1ab..d6c005bab 100644 --- a/tests/Meziantou.Analyzer.Test/Rules/AvoidUsingRedundantElseAnalyzerTests.cs +++ b/tests/Meziantou.Analyzer.Test/Rules/AvoidUsingRedundantElseAnalyzerTests.cs @@ -465,6 +465,44 @@ await CreateProjectBuilder() .ValidateAsync(); } + [Fact] + public async Task Test_ElseIfChainWithReachablePreviousThenAndMethodInvocationCondition_NoDiagnosticReported() + { + var originalCode = """ + class TestClass + { + void Test() + { + var test = new TestClass(); + foreach (var cmp in new[] { "first", "second", "third" }) + { + if (test.Verify("first", cmp) is not null) + { + System.Console.WriteLine("Handled"); + } + else if (test.Verify("second", cmp) is not null) + { + System.Console.WriteLine("Handled"); + continue; + } + else + { + System.Console.WriteLine("Not handled"); + } + } + } + + int? Verify(string tag, string cmp) + { + return tag.Equals(cmp, System.StringComparison.Ordinal) ? 1 : null; + } + } + """; + await CreateProjectBuilder() + .WithSourceCode(originalCode) + .ValidateAsync(); + } + [Fact] public async Task Test_SeveralNestedIfElseBlocksWithIfsThatJump_AllProblematicElsesRemoved() { From d7776b1079e56932be401a219b2c9bbe9f2aae68 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 14:01:38 +0000 Subject: [PATCH 3/3] refactor(MA0071): clarify else-if chain safety checks Agent-Logs-Url: https://github.com/meziantou/Meziantou.Analyzer/sessions/55a3c6a5-3f42-4e6e-9365-784352b50c33 Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com> --- .../Rules/AvoidUsingRedundantElseAnalyzer.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs b/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs index 27ce097bd..c520a05d3 100644 --- a/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs +++ b/src/Meziantou.Analyzer/Rules/AvoidUsingRedundantElseAnalyzer.cs @@ -64,7 +64,7 @@ private static void AnalyzeElseClause(SyntaxNodeAnalysisContext context) if (controlFlowAnalysis is null || !controlFlowAnalysis.Succeeded) return; - if (!CanExecuteOutsideElseIfChain(context.SemanticModel, ifStatement)) + if (!AllPreviousBranchesJumpUnconditionally(context.SemanticModel, ifStatement)) return; if (!controlFlowAnalysis.EndPointIsReachable) @@ -73,13 +73,13 @@ private static void AnalyzeElseClause(SyntaxNodeAnalysisContext context) } } - private static bool CanExecuteOutsideElseIfChain(SemanticModel semanticModel, IfStatementSyntax ifStatement) + private static bool AllPreviousBranchesJumpUnconditionally(SemanticModel semanticModel, IfStatementSyntax ifStatement) { var currentIfStatement = ifStatement; while (currentIfStatement.Parent is ElseClauseSyntax { Parent: IfStatementSyntax parentIfStatement }) { var controlFlowAnalysis = semanticModel.AnalyzeControlFlow(parentIfStatement.Statement); - if (controlFlowAnalysis is null || !controlFlowAnalysis.Succeeded || controlFlowAnalysis.EndPointIsReachable) + if (!IsUnreachableEndpoint(controlFlowAnalysis)) return false; currentIfStatement = parentIfStatement; @@ -88,6 +88,11 @@ private static bool CanExecuteOutsideElseIfChain(SemanticModel semanticModel, If return true; } + private static bool IsUnreachableEndpoint(ControlFlowAnalysis? controlFlowAnalysis) + { + return controlFlowAnalysis is { Succeeded: true, EndPointIsReachable: false }; + } + private static IEnumerable FindLocalIdentifiersIn(SyntaxNode node) { foreach (var child in node.DescendantNodes())