diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraph.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraph.java index 1ed88d6fc1e..37efd161f07 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraph.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraph.java @@ -34,7 +34,7 @@ public class ControlFlowGraph extends DefaultDirectedGraph { @Getter private ExitVertex exitPoint; - ControlFlowGraph() { + public ControlFlowGraph() { super(CfgEdge.class); exitPoint = new ExitVertex(); addVertex(exitPoint); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java index a6b3daa5df3..976d8e2be08 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java @@ -21,6 +21,8 @@ */ package com.github._1c_syntax.bsl.languageserver.diagnostics; +import com.github._1c_syntax.bsl.languageserver.cfg.CfgBuildingParseTreeVisitor; +import com.github._1c_syntax.bsl.languageserver.cfg.ExitVertex; import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata; import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity; import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag; @@ -37,6 +39,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.Deque; import java.util.List; import java.util.stream.Collectors; @@ -110,6 +113,59 @@ private void savePreprocessorRange(Deque nodes, BSLParser.Preprocesso } } + @Override + public ParseTree visitSubCodeBlock(BSLParser.SubCodeBlockContext ctx) { + errorRanges.clear(); + super.visitSubCodeBlock(ctx); + appendUnreachableCode(ctx.codeBlock()); + return ctx; + } + + @Override + public ParseTree visitFileCodeBlock(BSLParser.FileCodeBlockContext ctx) { + errorRanges.clear(); + super.visitFileCodeBlock(ctx); + appendUnreachableCode(ctx.codeBlock()); + return ctx; + } + + private void appendUnreachableCode(BSLParser.CodeBlockContext ctx) { + var builder = new CfgBuildingParseTreeVisitor(); + builder.producePreprocessorConditions(true); + builder.produceLoopIterations(false); + builder.determineAdjacentDeadCode(false); + + var graph = builder.buildGraph(ctx); + var deadCode = graph.vertexSet().stream() + .filter(vertex -> vertex != graph.getEntryPoint() && vertex.getClass() != ExitVertex.class) + .filter(vertex -> graph.inDegreeOf(vertex) == 0) + .flatMap(vertex -> vertex.getAst().stream()) + .sorted(Comparator.comparingInt(bslParserRuleContext -> bslParserRuleContext.getStart().getLine())) + .map(Ranges::create) + .collect(Collectors.toList()); + + + var newRanges = new ArrayList(); + for (var range : deadCode) { + var alreadyDetected = false; + for (Range detectedRange : errorRanges) { + var pos = new Position(range.getStart().getLine(), range.getStart().getCharacter()); + if (Ranges.containsPosition(detectedRange, pos)) { + alreadyDetected = true; + break; + } + } + if(!alreadyDetected) { + newRanges.add(range); + } + } + + for (var range : newRanges) { + diagnosticStorage.addDiagnostic(range); + } + + } + @Override public ParseTree visitContinueStatement(BSLParser.ContinueStatementContext ctx) { findAndAddDiagnostic(ctx); diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java index 3f7dd30b76c..f2c5c73ff25 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java @@ -38,7 +38,7 @@ class UnreachableCodeDiagnosticTest extends AbstractDiagnosticTest diagnostics = getDiagnostics(); - assertThat(diagnostics).hasSize(15); + assertThat(diagnostics).hasSize(16); assertThat(diagnostics, true) .hasRange(12, 12, 20) .hasRange(21, 12, 20) @@ -52,9 +52,10 @@ void test() { .hasRange(102, 8, 17) .hasRange(108, 16, 111, 29) .hasRange(138, 4, 16) - .hasRange(161, 4, 13) - .hasRange(166, 4, 168, 13) - .hasRange(172, 0, 9); + .hasRange(163, 4, 22) + .hasRange(171, 4, 13) + .hasRange(176, 4, 178, 13) + .hasRange(182, 0, 9); } @Test diff --git a/src/test/resources/diagnostics/UnreachableCodeDiagnostic.bsl b/src/test/resources/diagnostics/UnreachableCodeDiagnostic.bsl index 6d4c9f5566d..fb9a163c8a8 100644 --- a/src/test/resources/diagnostics/UnreachableCodeDiagnostic.bsl +++ b/src/test/resources/diagnostics/UnreachableCodeDiagnostic.bsl @@ -154,6 +154,16 @@ КонецФункции #КонецОбласти +Функция ДосрочныйВыход() + Если А Тогда + Возврат 1; + Иначе + Возврат 2; + КонецЕсли; + + ТутОшибка = Истина; // <- недостижимый код +КонецФункции + #Если Сервер Тогда Возврат; #Иначе @@ -170,4 +180,4 @@ КонецЕсли; Возврат; -Метод2(); // Ошибка: После Возврат +Метод2(); // Ошибка: После Возврат \ No newline at end of file