Skip to content

SONARPY-4544 Count terminal raises as exits - #2296

Closed
erwan-leforestier-sonarsource wants to merge 6 commits into
masterfrom
fix/sonarpy-4544-treat-terminal-raise-as-exit
Closed

SONARPY-4544 Count terminal raises as exits#2296
erwan-leforestier-sonarsource wants to merge 6 commits into
masterfrom
fix/sonarpy-4544-treat-terminal-raise-as-exit

Conversation

@erwan-leforestier-sonarsource

@erwan-leforestier-sonarsource erwan-leforestier-sonarsource commented Aug 17, 2026

Copy link
Copy Markdown

Summary

Treat terminal raise CFG edges as exits for S3516, preventing reports on validator-style methods that either return a common value or raise.

Changes

  • Preserve terminal raise predecessors when collecting S3516 exit paths.
  • Cover both the existing raised exit and a return/raise/return validator pattern.

Functional Validation

Artifact: sonarpy-4544-fv.zip

Once the file is attached to the PR description, unzip and run:
./run.sh

Expected output:

******************* MASTER *******************
Analyzing "sample.py"...
Results:
    - Rule "S3516" -> L.2
****** Branch "fix/sonarpy-4544-treat-terminal-raise-as-exit" ******
Analyzing "sample.py"...
Results:
    (none)

@erwan-leforestier-sonarsource
erwan-leforestier-sonarsource marked this pull request as ready for review August 17, 2026 12:14

@asya-vorobeva asya-vorobeva left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM, with a minor suggestion.

}

private static void collectBranchingBlock(List<LatestExecutedBlock> collectedBlocks, PythonCfgBranchingBlock branchingBlock) {
private static Set<CfgBlock> reachableBlocks(CfgBlock start) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why we don't extract this method to existing CfgUtils (and reuse it in unreachableBlocks)?

@guillaume-dequenne

Copy link
Copy Markdown
Contributor

Hey there,
FYI @erwan-leforestier-sonarsource and @erwan-leforestier-sonarsource, this repository is a public mirror. You should never open PRs or merge changes directly against it.

@gitar-bot

gitar-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 resolved / 1 findings

Treats terminal raise control flow graph edges as exits for rule S3516, addressing the missing reachability filter on except/finally predecessors. No issues found.

✅ 1 resolved
Edge Case: Reachability filter not applied to except/finally predecessors

📄 python-checks/src/main/java/org/sonar/python/checks/InvariantReturnCheck.java:83-93 📄 python-checks/src/main/java/org/sonar/python/checks/InvariantReturnCheck.java:127-137
In collectLatestExecutedBlocks the reachableBlocks set gates only the direct predecessors of cfg.end() (line 85). The recursive collectBlocksHavingReturnBeforeExceptOrFinallyBlock walks branchingBlock.predecessors() and adds any block ending in RETURN_STMT/RAISE_STMT without re-checking reachability. If a reachable except/finally branching block has an unreachable predecessor that ends in a raise, that raise would still be collected and could suppress an otherwise valid S3516 report (false negative). This is hard to construct with normal control flow, so it is low risk; consider passing the reachableBlocks set into the recursion and skipping unreachable predecessors for consistency.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

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.

3 participants