mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:16 +00:00
[internal
] Return statements in finally block point to end block for unreachable
(PLW0101
) (#15276)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Note: `PLW0101` remains in testing rather than preview, so this PR does not modify any public behavior (hence the title beginning with `internal` rather than `pylint`, for the sake of the changelog.) Fixes an error in the processing of `try` statements in the control flow graph builder. When processing a try statement, the block following a `return` was forced to point to the `finally` block. However, if the return was _in_ the `finally` block, this caused the block to point to itself. In the case where the whole `try-finally` statement was also included inside of a loop, this caused an infinite loop in the builder for the control flow graph as it attempted to resolve edges. Closes #15248 ## Test function ### Source ```python def l(): while T: try: while (): if 3: break finally: return ``` ### Control Flow Graph ```mermaid flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] block1[["Loop continue"]] block2["return\n"] block3[["Loop continue"]] block4["break\n"] block5["if 3: break\n"] block6["while (): if 3: break\n"] block7[["Exception raised"]] block8["try: while (): if 3: break finally: return\n"] block9["while T: try: while (): if 3: break finally: return\n"] start --> block9 block9 -- "T" --> block8 block9 -- "else" --> block0 block8 -- "Exception raised" --> block7 block8 -- "else" --> block6 block7 --> block2 block6 -- "()" --> block5 block6 -- "else" --> block2 block5 -- "3" --> block4 block5 -- "else" --> block3 block4 --> block2 block3 --> block6 block2 --> return block1 --> block9 block0 --> return ```
This commit is contained in:
parent
e4139568b8
commit
a876090715
3 changed files with 77 additions and 0 deletions
9
crates/ruff_linter/resources/test/fixtures/control-flow-graph/try-finally-nested-if-while.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/control-flow-graph/try-finally-nested-if-while.py
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
def l():
|
||||
while T:
|
||||
try:
|
||||
while ():
|
||||
if 3:
|
||||
break
|
||||
finally:
|
||||
return
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pylint/rules/unreachable.rs
|
||||
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
|
||||
---
|
||||
## Function 0
|
||||
### Source
|
||||
```python
|
||||
def l():
|
||||
while T:
|
||||
try:
|
||||
while ():
|
||||
if 3:
|
||||
break
|
||||
finally:
|
||||
return
|
||||
```
|
||||
|
||||
### Control Flow Graph
|
||||
```mermaid
|
||||
flowchart TD
|
||||
start(("Start"))
|
||||
return(("End"))
|
||||
block0[["`*(empty)*`"]]
|
||||
block1[["Loop continue"]]
|
||||
block2["return\n"]
|
||||
block3[["Loop continue"]]
|
||||
block4["break\n"]
|
||||
block5["if 3:
|
||||
break\n"]
|
||||
block6["while ():
|
||||
if 3:
|
||||
break\n"]
|
||||
block7[["Exception raised"]]
|
||||
block8["try:
|
||||
while ():
|
||||
if 3:
|
||||
break
|
||||
finally:
|
||||
return\n"]
|
||||
block9["while T:
|
||||
try:
|
||||
while ():
|
||||
if 3:
|
||||
break
|
||||
finally:
|
||||
return\n"]
|
||||
|
||||
start --> block9
|
||||
block9 -- "T" --> block8
|
||||
block9 -- "else" --> block0
|
||||
block8 -- "Exception raised" --> block7
|
||||
block8 -- "else" --> block6
|
||||
block7 --> block2
|
||||
block6 -- "()" --> block5
|
||||
block6 -- "else" --> block2
|
||||
block5 -- "3" --> block4
|
||||
block5 -- "else" --> block3
|
||||
block4 --> block2
|
||||
block3 --> block6
|
||||
block2 --> return
|
||||
block1 --> block9
|
||||
block0 --> return
|
||||
```
|
|
@ -665,6 +665,10 @@ fn post_process_try(
|
|||
NextBlock::Terminate => {
|
||||
match block.stmts.last() {
|
||||
Some(Stmt::Return(_)) => {
|
||||
// if we are already in a `finally` block, terminate
|
||||
if Some(idx) == finally_index {
|
||||
return;
|
||||
}
|
||||
// re-route to finally if present and not already re-routed
|
||||
if let Some(finally_index) = finally_index {
|
||||
blocks.blocks[idx].next = NextBlock::Always(finally_index);
|
||||
|
@ -1064,6 +1068,7 @@ mod tests {
|
|||
#[test_case("raise.py")]
|
||||
#[test_case("assert.py")]
|
||||
#[test_case("match.py")]
|
||||
#[test_case("try-finally-nested-if-while.py")]
|
||||
fn control_flow_graph(filename: &str) {
|
||||
let path = PathBuf::from_iter(["resources/test/fixtures/control-flow-graph", filename]);
|
||||
let source = fs::read_to_string(path).expect("failed to read file");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue