Feature/dead code improve#1770
Conversation
WalkthroughПубличен конструктор ControlFlowGraph. В UnreachableCodeDiagnostic добавлен анализ недостижимого кода на основе CFG при обходе файлового и подблочного кода. Обновлены тесты: ожидаемые диапазоны и добавлен новый кейс с ранним возвратом. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client as Analyzer (BSL LS)
participant Diag as UnreachableCodeDiagnostic
participant CFGV as CfgBuildingParseTreeVisitor
participant CFG as ControlFlowGraph
participant Store as DiagnosticStorage
Client->>Diag: visitFileCodeBlock()/visitSubCodeBlock(ctx)
activate Diag
Diag->>CFGV: configure(producePreprocessorConditions, produceLoopIterations=false, determineAdjacentDeadCode=false)
Diag->>CFGV: build(ctx.codeBlock)
CFGV-->>Diag: ControlFlowGraph
Diag->>CFG: collect vertices with in-degree=0<br/>(exclude Entry, ExitVertex)
Diag->>Diag: map vertices->AST->ranges<br/>sort, deduplicate
Diag->>Store: register unreachable code ranges
deactivate Diag
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
0410b3e to
1c7beae
Compare
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraph.java (1)
36-40: Публичный конструктор: оценить необходимость расширения APIСмена видимости конструктора на public расширяет поверхность API и допускает произвольное создание графа вне пакета. Если прямой инстанс
ControlFlowGraphвнеcfgне требуется (в текущем PR используетсяCfgBuildingParseTreeVisitor#buildGraph), лучше сохранить пакетную видимость, либо добавить явную JavaDoc/аннотацию (например, «Intended for external consumers») с описанием инвариантов (наличиеexitPoint, поведениеentryPoint). Это снизит риск неправильного использования и облегчит сопровождение публичного контракта.src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java (1)
54-59: Стабилизировать проверку нового кейса раннего выхода отдельным тестомТекущие жестко прошитые координаты остаются чувствительными к правкам тестового BSL-файла. Рекомендую вынести сценарий «раннего выхода» в отдельный метод-тест с более локальными проверками (например, по границам внутри функции или по уникальной метке-комментарию), чтобы уменьшить хрупкость набора координат.
Готов предложить заготовку теста с более устойчивой проверкой при необходимости.
src/test/resources/diagnostics/UnreachableCodeDiagnostic.bsl (2)
124-127: Опечатки в комментарииНебольшие опечатки в пользовательском (пусть и тестовом) комментарии — лучше поправить для читаемости.
Предлагаемый патч:
- #КонецЕсли - - Метод2(); // <-- Ошибка: ренее были Возврат и Вызватьисключение, ка не ловим + #КонецЕсли + + Метод2(); // <-- Ошибка: ранее были Возврат и ВызватьИсключение, но не ловим
157-165: Новый кейс «ДосрочныйВыход» — удачно покрывает ранний возвратДобавленная функция хорошо валидирует недостижимость кода после возврата из обеих веток. В качестве расширения можно добавить аналогичный кейс с цепочкой
ИначеЕслии/или с препроцессором внутри веток, чтобы проверить устойчивость анализа на составных ветвлениях.src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java (2)
132-146: CFG: улучшить точность фильтра и порядок сортировки
- Для исключения узла выхода лучше использовать
instanceof, а не сравнение классов (на будущее, если появятся наследники):- .filter(vertex -> vertex != graph.getEntryPoint() && vertex.getClass() != ExitVertex.class) + .filter(vertex -> vertex != graph.getEntryPoint() && !(vertex instanceof ExitVertex))
- Сортировку стоит детализировать по позиции в строке — так стабильнее при нескольких узлах на одной строке:
- .sorted(Comparator.comparingInt(bslParserRuleContext -> bslParserRuleContext.getStart().getLine())) + .sorted( + Comparator.comparingInt((BSLParserRuleContext r) -> r.getStart().getLine()) + .thenComparingInt(r -> r.getStart().getCharPositionInLine()) + )
- Метод выделяет только вершины с
inDegree == 0. Это гарантированно включает «корневые» куски недостижимого кода, но может пропустить узлы, достижимые только из уже недостижимых (например, тело цикла/условия, расположенное после точки отсечения). В перспективе можно рассмотреть подход «все вершины − достижимые из entry» (поиск в ширину/глубину отentryPoint) — он даст полный набор недостижимых узлов. Это необязательная доработка в рамках «chill»-ревью, текущий подход решает заявленную проблему раннего выхода.
148-166: Дедупликация: учесть пересечения и среди «новых» диапазонов; обновлять кэшСейчас проверка исключает только диапазоны, уже обнаруженные старым алгоритмом. При нескольких узлах в одном BasicBlock возможны дубли/пересечения внутри
deadCode. Предлагаю:
- дедуплицировать также по уже отобранным «новым» диапазонам;
- после регистрации добавить их в
errorRangesдля симметрии и защиты от повторной регистрации в соседних обходах.Патч:
- var newRanges = new ArrayList<Range>(); + var acceptedRanges = new ArrayList<Range>(); 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); + if (!alreadyDetected) { + // проверим пересечения и с уже принятыми новыми диапазонами + for (Range accepted : acceptedRanges) { + var pos = new Position(range.getStart().getLine(), range.getStart().getCharacter()); + if (Ranges.containsPosition(accepted, pos)) { + alreadyDetected = true; + break; + } + } + } + if (!alreadyDetected) { + acceptedRanges.add(range); } } - for (var range : newRanges) { + // обновим кэш для последующих проверок + errorRanges.addAll(acceptedRanges); + + for (var range : acceptedRanges) { diagnosticStorage.addDiagnostic(range); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraph.java(1 hunks)src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java(3 hunks)src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java(2 hunks)src/test/resources/diagnostics/UnreachableCodeDiagnostic.bsl(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java (2)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java (1)
CfgBuildingParseTreeVisitor(34-643)src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/ExitVertex.java (1)
ExitVertex(24-29)
🔇 Additional comments (5)
src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnosticTest.java (1)
41-41: Обновление ожидаемого количества диагностик — выглядит корректноУвеличение с 15 до 17 согласуется с добавленным кейсом раннего выхода и расширенным покрытием CFG.
src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/UnreachableCodeDiagnostic.java (4)
24-26: Импорты для CFG-анализа — уместноНовые импорты (
CfgBuildingParseTreeVisitor,ExitVertex,Comparator) соответствуют добавленной логике и выглядят корректно.Also applies to: 42-42
116-122: Порядок вызовов и очистка кэша — окОчистка
errorRangesпередsuper.visitSubCodeBlock(ctx)и последующий вызовappendUnreachableCodeобеспечивает дедупликацию «новых» находок относительно «старого» алгоритма. Логика вызовов выглядит правильной.
124-130: Аналогично для FileCodeBlock — выглядит консистентноТа же последовательность шагов для файлового блока поддерживает единое поведение.
169-251: Совместимость с препроцессором и кэшированием — поведение согласованоПроверка на вхождение в ранее зафиксированные диапазоны, а также учет препроцессорных блоков при вычислении конца текущего блока выглядят корректно и совместимы с новой веткой CFG-анализа.



Описание
Предыдущий вариант UnreachableCode не отлавливал досрочный выход из процедуры
Связанные задачи
нет связанной задачи
Чеклист
Общие
gradlew precommit)Для диагностик
Дополнительно
на голом Cfg сделать не удалось, т.е. UnreachableCode детектирует повторные недостижимые участки на уровне блока кода, а в текущей реализации Cfg нет информации о блоках кода. Диагностика работает по предыдущему алгоритму, затем строит CFG для мертвого кода, и те узлы, которые уже обнаружил старый алгоритм - фильтрует. Оставшиеся после фильра недостижимые узлы - это будут те, которые нашел только CFG, но не старая диагностика.