Skip to content

test ReturnOutsideLoop#3625

Merged
nixel2007 merged 5 commits intodevelopfrom
fix/cfgBulder
Dec 5, 2025
Merged

test ReturnOutsideLoop#3625
nixel2007 merged 5 commits intodevelopfrom
fix/cfgBulder

Conversation

@nixel2007
Copy link
Member

@nixel2007 nixel2007 commented Nov 27, 2025

Описание

Связанные задачи

Closes

Чеклист

Общие

  • Ветка PR обновлена из develop
  • Отладочные, закомментированные и прочие, не имеющие смысла участки кода удалены
  • Изменения покрыты тестами
  • Обязательные действия перед коммитом выполнены (запускал команду gradlew precommit)

Для диагностик

  • Описание диагностики заполнено для обоих языков (присутствуют файлы для обоих языков, для русского заполнено все подробно, перевод на английский можно опустить)

Дополнительно

Summary by CodeRabbit

  • Tests

    • Added a test covering break/continue outside loops to increase coverage of control-flow graph building.
  • Bug Fixes

    • Control-flow handling for break/continue/return updated so jumps are only emitted when valid targets exist, preventing incorrect jumps.
  • Chores

    • Applied nullability annotations to improve static null-safety checks.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings November 27, 2025 10:28
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Added a test for break/continue outside loops and updated CFG visitor and a writer with nullability annotations and guarded jump emission so break/continue/return only generate jumps when their targets exist.

Changes

Cohort / File(s) Change Summary
Test Addition
src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java
Added testBreakContinueOutsideLoop() to build a small BSL snippet, parse it, construct a CFG, traverse vertices into an ordered list, and assert the list is non-empty.
CFG Visitor behavior
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java
Applied @NullUnmarked to the class; swapped/adjusted visitor logic for break/return/continue statements so jumps (loopContinue, loopBreak, methodReturn) are emitted only when corresponding jump targets are non-null, otherwise statements are treated as plain statements.
Nullability annotation
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/StatementsBlockWriter.java
Applied @NullUnmarked to the class (import added); no signature or behavior changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect CfgBuildingParseTreeVisitor changes closely: confirm correct mapping of contexts to jump targets after the swap and that null-guards preserve intended control flow.
  • Verify no unintended semantic regressions for nested loops, returns inside methods, and labeled breaks.
  • Run/validate the new test and related CFG tests to ensure behavior across cases.

Possibly related PRs

  • Fix/cfg bulder #3616 — Related fixes to CfgBuildingParseTreeVisitor loop subgraph handling and null checks; likely addresses similar control-flow scenarios.

Poem

🐰 I hopped through code to check each jump,
If targets are missing I stay in my stump.
Breaks and returns now wait in line,
The CFG's tidy — hopping fine! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'test ReturnOutsideLoop' is vague and does not clearly reflect the actual changes made. The actual changeset adds a test for Break/Continue outside loops, modifies control flow handling in CfgBuildingParseTreeVisitor, and adds nullability annotations—none of which are accurately captured by the title. Revise the title to accurately describe the main changes, such as 'Handle Break/Continue outside loops with null checks' or 'Add null-guarded jump handling for loop control statements'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/cfgBulder

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ac3e9d and 09cea06.

📒 Files selected for processing (1)
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.java: Follow the Style Guide provided in docs/en/contributing/StyleGuide.md
Use Lombok annotations to reduce boilerplate code and enable annotation processing in your IDE
Optimize imports before committing but do NOT optimize imports across the entire project unless specifically working on that task
Follow Java naming conventions with meaningful, descriptive names; keep class and method names concise but clear
Write JavaDoc for public APIs and include comments for complex logic
Use Target Java 17 as the language version

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java
**/test/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use appropriate test frameworks (JUnit, AssertJ, Mockito) for testing

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java
🪛 GitHub Actions: Java CI
src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java

[error] 56-56: Test 'ReturnOutsideLoop' failed with NullPointerException.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Analyse
  • GitHub Check: build (21, ubuntu-latest)
  • GitHub Check: build (17, windows-latest)
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build (21, macOS-latest)
  • GitHub Check: build (25, macOS-latest)
  • GitHub Check: build (25, ubuntu-latest)
  • GitHub Check: build (17, macOS-latest)
  • GitHub Check: build (21, windows-latest)
  • GitHub Check: build (17, ubuntu-latest)
  • GitHub Check: Analyze the repo with CodeSee
  • GitHub Check: build
  • GitHub Check: CodeQL analysis (java)
  • GitHub Check: Agent
  • GitHub Check: Benchmark
🔇 Additional comments (1)
src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java (1)

54-57: Potential NullPointerException with break/continue outside loops — code analysis confirms risk, but pipeline failure claim is unverified.

The CFG builder lacks defensive null checks when processing break/continue statements outside loops. Code analysis shows the execution path:

  • visitContinueStatement() / visitBreakStatement() call makeJump(jumps.loopContinue) or makeJump(jumps.loopBreak)
  • When outside loops, these jump targets may be null
  • makeJump() passes the null directly to connectGraphTail(), which attempts graph.addEdge(currentBlock.end(), vertex) with a null vertex, causing NPE

However, the original comment claims "pipeline reports" failure without providing evidence (no logs, stack traces, or execution output). This cannot be verified from the repository state.

The test's weak assertion (assertThat(vertices).isNotEmpty() // or empty...) is also problematic and suggests uncertainty about expected behavior.

To resolve:

  1. Either add null-safety checks in the CFG builder to gracefully handle break/continue outside loops, or
  2. Document this as invalid BSL syntax and ensure proper error handling with meaningful diagnostics
  3. Improve the test assertion to clearly specify expected behavior
  4. Verify actual test execution status rather than assuming pipeline failure

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new test case to ControlFlowGraphBuilderTest that validates the Control Flow Graph builder's behavior when loop control statements (Прервать/Break and Продолжить/Continue) are used outside of loops - an edge case in 1C BSL code.

Key Changes:

  • Added test method ReturnOutsideLoop() to verify CFG construction with break/continue statements outside loop context

var builder = new CfgBuildingParseTreeVisitor();
var graph = builder.buildGraph(parseTree);
var vertices = traverseToOrderedList(graph);
assertThat(vertices).isNotEmpty(); // or empty...
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion assertThat(vertices).isNotEmpty(); // or empty... is too weak and unclear. The comment "or empty..." suggests uncertainty about the expected behavior.

Looking at similar tests in this file (e.g., linearBlockCanBeBuilt, whileLoopTest), they use specific assertions to verify the CFG structure. This test should either:

  1. Have a specific assertion about what vertices should exist when Прервать and Продолжить are used outside loops
  2. Verify that the builder handles this invalid case gracefully (e.g., by checking for specific error handling or expected graph structure)

Consider adding more specific assertions that validate the actual expected behavior of the control flow graph in this edge case.

Copilot uses AI. Check for mistakes.
class ControlFlowGraphBuilderTest {

@Test
void ReturnOutsideLoop() {
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name "ReturnOutsideLoop" is misleading. The test code uses Прервать (Break) and Продолжить (Continue) statements, not return statements.

Suggestion: Rename to breakContinueOutsideLoop or loopControlStatementsOutsideLoop to accurately reflect what's being tested.

Suggested change
void ReturnOutsideLoop() {
void breakContinueOutsideLoop() {

Copilot uses AI. Check for mistakes.
EvilBeaver and others added 2 commits December 5, 2025 18:07
…trolFlowGraphBuilderTest.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java (2)

45-59: Add documentation explaining the test's purpose and expected behavior.

This test validates an edge case (Break/Continue outside loops), but lacks documentation. Based on the guarded jump behavior in CfgBuildingParseTreeVisitor, Break/Continue outside loops are now treated as plain statements without creating jumps. The test should document:

  1. What scenario is being tested (Break/Continue outside loops)
  2. Expected CFG behavior (graceful handling, no jumps created)
  3. Why this test matters (validates guard logic, prevents NPE)

Consider adding JavaDoc:

+  /**
+   * Tests that Break and Continue statements outside loops are handled gracefully.
+   * With guarded jump logic, these statements should be treated as plain statements
+   * without creating jumps, since loopBreak and loopContinue targets don't exist.
+   */
   @Test
   void testBreakContinueOutsideLoop() {

58-58: Strengthen assertion to verify expected CFG structure.

The assertion assertThat(vertices).isNotEmpty(); // or empty... is too weak and the comment indicates uncertainty. Based on the guarded jump logic, the CFG should contain specific vertices: an entry basic block (with the Break and Continue statements) and an exit vertex.

Replace the weak assertion with specific structural verification:

-    assertThat(vertices).isNotEmpty(); // or empty...
+    // CFG should contain basic blocks with statements and exit point
+    assertThat(vertices).hasSize(2);
+    assertThat(vertices.get(0)).isInstanceOf(BasicBlockVertex.class);
+    assertThat(vertices.get(1)).isInstanceOf(ExitVertex.class);
+    
+    // Verify no jump edges were created (Break/Continue outside loops don't jump)
+    var basicBlock = (BasicBlockVertex) vertices.get(0);
+    assertThat(basicBlock.statements()).hasSize(2); // Прервать and Продолжить
+    assertThat(graph.outgoingEdgesOf(basicBlock)).hasSize(1);
+    assertThat(graph.outgoingEdgesOf(basicBlock).iterator().next().getType())
+      .isEqualTo(CfgEdgeType.DIRECT);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09cea06 and a66cf55.

📒 Files selected for processing (3)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java (2 hunks)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/StatementsBlockWriter.java (1 hunks)
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.java: Follow the Style Guide provided in docs/en/contributing/StyleGuide.md
Use Lombok annotations to reduce boilerplate code and enable annotation processing in your IDE
Optimize imports before committing but do NOT optimize imports across the entire project unless specifically working on that task
Follow Java naming conventions with meaningful, descriptive names; keep class and method names concise but clear
Write JavaDoc for public APIs and include comments for complex logic
Use Target Java 17 as the language version

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/StatementsBlockWriter.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java
**/test/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use appropriate test frameworks (JUnit, AssertJ, Mockito) for testing

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/cfg/ControlFlowGraphBuilderTest.java
🧠 Learnings (1)
📚 Learning: 2025-04-18T22:46:43.245Z
Learnt from: nixel2007
Repo: 1c-syntax/bsl-language-server PR: 3449
File: src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/expressiontree/ExpressionTreeBuildingVisitor.java:192-203
Timestamp: 2025-04-18T22:46:43.245Z
Learning: В проекте bsl-language-server класс BSLParser.ExpressionContext наследуется от BSLParserRuleContext, а не напрямую от ParserRuleContext. При работе с ним нужно учитывать специфичные методы BSLParserRuleContext.

Applied to files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java
🧬 Code graph analysis (2)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/StatementsBlockWriter.java (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java (1)
  • NullUnmarked (37-697)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/StatementsBlockWriter.java (1)
  • NullUnmarked (31-145)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: build (25, ubuntu-latest)
  • GitHub Check: build (21, ubuntu-latest)
  • GitHub Check: build (17, ubuntu-latest)
  • GitHub Check: build (21, macOS-latest)
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build
🔇 Additional comments (5)
src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/StatementsBlockWriter.java (1)

26-31: LGTM! Null-safety annotation added.

The @NullUnmarked annotation has been correctly applied at the class level, consistent with the same annotation in CfgBuildingParseTreeVisitor.java. This opt-out annotation helps define null-safety boundaries in the CFG building infrastructure without altering behavior.

src/main/java/com/github/_1c_syntax/bsl/languageserver/cfg/CfgBuildingParseTreeVisitor.java (4)

29-37: LGTM! Null-safety annotation added.

The @NullUnmarked annotation has been correctly applied at the class level, consistent with the parallel change in StatementsBlockWriter.java. This helps establish clear null-safety boundaries across the CFG building infrastructure.


341-354: LGTM! Guard prevents NPE for Continue outside loops.

The null check if (jumps.loopContinue != null) correctly handles syntactically invalid code where Continue appears outside a loop. When the guard fails, the statement is treated as a plain statement without creating a jump, preventing a NullPointerException in makeJump().


357-371: LGTM! Guard prevents NPE for Break outside loops.

The null check if (jumps.loopBreak != null) correctly handles syntactically invalid code where Break appears outside a loop. When the guard fails, the statement is treated as a plain statement without creating a jump, preventing a NullPointerException in makeJump().


375-382: No guard needed for Return—methodReturn is always initialized.

Unlike visitContinueStatement and visitBreakStatement, this method doesn't guard against null because jumps.methodReturn is always initialized in buildGraph() (line 70: exitPoints.methodReturn = graph.getExitPoint()). Since every method has an exit point, methodReturn is never null, making the guard unnecessary. The guards for Break/Continue are needed because loopBreak/loopContinue are only set when entering a loop context (line 615-617 in buildLoopSubgraph()).

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 5, 2025

@nixel2007 nixel2007 merged commit 1d36403 into develop Dec 5, 2025
47 of 49 checks passed
@nixel2007 nixel2007 deleted the fix/cfgBulder branch December 5, 2025 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants