From 5897adbb902a72010835299e2f8554969e224065 Mon Sep 17 00:00:00 2001 From: augustelalande Date: Mon, 15 Apr 2024 16:32:50 -0400 Subject: [PATCH] Always close the loop --- ...les__unreachable__tests__assert.py.md.snap | 20 +- ...__unreachable__tests__async-for.py.md.snap | 144 ++++--- ..._rules__unreachable__tests__for.py.md.snap | 196 +++++---- ...ules__unreachable__tests__while.py.md.snap | 372 ++++++++++-------- .../src/rules/ruff/rules/unreachable.rs | 49 ++- 5 files changed, 432 insertions(+), 349 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__assert.py.md.snap b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__assert.py.md.snap index a0eb6f24a6a6dd..c3cfd2fce92a6e 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__assert.py.md.snap +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__assert.py.md.snap @@ -140,16 +140,18 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1[["Exception raised"]] - block2["assert i < x\n"] - block3["for i in range(3): + block1[["Loop continue"]] + block2[["Exception raised"]] + block3["assert i < x\n"] + block4["for i in range(3): assert i < x\n"] - start --> block3 - block3 -- "range(3)" --> block2 - block3 -- "else" --> block0 - block2 -- "i < x" --> block3 - block2 -- "else" --> block1 - block1 --> return + start --> block4 + block4 -- "range(3)" --> block3 + block4 -- "else" --> block0 + block3 -- "i < x" --> block1 + block3 -- "else" --> block2 + block2 --> return + block1 --> block4 block0 --> return ``` diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__async-for.py.md.snap b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__async-for.py.md.snap index 4c42ac1d55af96..a9351e73df17af 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__async-for.py.md.snap +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__async-for.py.md.snap @@ -16,14 +16,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["print(i)\n"] - block2["async for i in range(5): + block1[["Loop continue"]] + block2["print(i)\n"] + block3["async for i in range(5): print(i)\n"] - start --> block2 - block2 -- "range(5)" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "range(5)" --> block2 + block3 -- "else" --> block0 + block2 --> block1 + block1 --> block3 block0 --> return ``` @@ -43,18 +45,20 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["print(i)\n"] - block2["return 0\n"] - block3["async for i in range(20): + block1[["Loop continue"]] + block2["print(i)\n"] + block3["return 0\n"] + block4["async for i in range(20): print(i) else: return 0\n"] - start --> block3 - block3 -- "range(20)" --> block1 - block3 -- "else" --> block2 - block2 --> return - block1 --> block3 + start --> block4 + block4 -- "range(20)" --> block2 + block4 -- "else" --> block3 + block3 --> return + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -74,19 +78,21 @@ flowchart TD start(("Start")) return(("End")) block0["return 0\n"] - block1["return 1\n"] - block2["if i == 5: + block1[["Loop continue"]] + block2["return 1\n"] + block3["if i == 5: return 1\n"] - block3["async for i in range(10): + block4["async for i in range(10): if i == 5: return 1\n"] - start --> block3 - block3 -- "range(10)" --> block2 - block3 -- "else" --> block0 - block2 -- "i == 5" --> block1 - block2 -- "else" --> block3 - block1 --> return + start --> block4 + block4 -- "range(10)" --> block3 + block4 -- "else" --> block0 + block3 -- "i == 5" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block4 block0 --> return ``` @@ -108,23 +114,25 @@ flowchart TD start(("Start")) return(("End")) block0["return 2\n"] - block1["return 1\n"] - block2["if i == 5: + block1[["Loop continue"]] + block2["return 1\n"] + block3["if i == 5: return 1\n"] - block3["return 0\n"] - block4["async for i in range(111): + block4["return 0\n"] + block5["async for i in range(111): if i == 5: return 1 else: return 0\n"] - start --> block4 - block4 -- "range(111)" --> block2 - block4 -- "else" --> block3 - block3 --> return - block2 -- "i == 5" --> block1 - block2 -- "else" --> block4 - block1 --> return + start --> block5 + block5 -- "range(111)" --> block3 + block5 -- "else" --> block4 + block4 --> return + block3 -- "i == 5" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block5 block0 --> return ``` @@ -142,14 +150,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["async for i in range(12): + block1[["Loop continue"]] + block2["continue\n"] + block3["async for i in range(12): continue\n"] - start --> block2 - block2 -- "range(12)" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "range(12)" --> block2 + block3 -- "else" --> block0 + block2 --> block3 + block1 --> block3 block0 --> return ``` @@ -168,19 +178,21 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["if True: + block1[["Loop continue"]] + block2["continue\n"] + block3["if True: continue\n"] - block3["async for i in range(1110): + block4["async for i in range(1110): if True: continue\n"] - start --> block3 - block3 -- "range(1110)" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> block3 + start --> block4 + block4 -- "range(1110)" --> block3 + block4 -- "else" --> block0 + block3 -- "True" --> block2 + block3 -- "else" --> block1 + block2 --> block4 + block1 --> block4 block0 --> return ``` @@ -198,14 +210,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["async for i in range(13): + block1[["Loop continue"]] + block2["break\n"] + block3["async for i in range(13): break\n"] - start --> block2 - block2 -- "range(13)" --> block1 - block2 -- "else" --> block0 - block1 --> return + start --> block3 + block3 -- "range(13)" --> block2 + block3 -- "else" --> block0 + block2 --> return + block1 --> block3 block0 --> return ``` @@ -224,18 +238,20 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["if True: + block1[["Loop continue"]] + block2["break\n"] + block3["if True: break\n"] - block3["async for i in range(1110): + block4["async for i in range(1110): if True: break\n"] - start --> block3 - block3 -- "range(1110)" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> return + start --> block4 + block4 -- "range(1110)" --> block3 + block4 -- "else" --> block0 + block3 -- "True" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block4 block0 --> return ``` diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap index 540d64db2bea36..ecb91c76b63dad 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap @@ -16,14 +16,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["print(i)\n"] - block2["for i in range(5): + block1[["Loop continue"]] + block2["print(i)\n"] + block3["for i in range(5): print(i)\n"] - start --> block2 - block2 -- "range(5)" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "range(5)" --> block2 + block3 -- "else" --> block0 + block2 --> block1 + block1 --> block3 block0 --> return ``` @@ -43,18 +45,20 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["print(i)\n"] - block2["return 0\n"] - block3["for i in range(20): + block1[["Loop continue"]] + block2["print(i)\n"] + block3["return 0\n"] + block4["for i in range(20): print(i) else: return 0\n"] - start --> block3 - block3 -- "range(20)" --> block1 - block3 -- "else" --> block2 - block2 --> return - block1 --> block3 + start --> block4 + block4 -- "range(20)" --> block2 + block4 -- "else" --> block3 + block3 --> return + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -74,19 +78,21 @@ flowchart TD start(("Start")) return(("End")) block0["return 0\n"] - block1["return 1\n"] - block2["if i == 5: + block1[["Loop continue"]] + block2["return 1\n"] + block3["if i == 5: return 1\n"] - block3["for i in range(10): + block4["for i in range(10): if i == 5: return 1\n"] - start --> block3 - block3 -- "range(10)" --> block2 - block3 -- "else" --> block0 - block2 -- "i == 5" --> block1 - block2 -- "else" --> block3 - block1 --> return + start --> block4 + block4 -- "range(10)" --> block3 + block4 -- "else" --> block0 + block3 -- "i == 5" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block4 block0 --> return ``` @@ -108,23 +114,25 @@ flowchart TD start(("Start")) return(("End")) block0["return 2\n"] - block1["return 1\n"] - block2["if i == 5: + block1[["Loop continue"]] + block2["return 1\n"] + block3["if i == 5: return 1\n"] - block3["return 0\n"] - block4["for i in range(111): + block4["return 0\n"] + block5["for i in range(111): if i == 5: return 1 else: return 0\n"] - start --> block4 - block4 -- "range(111)" --> block2 - block4 -- "else" --> block3 - block3 --> return - block2 -- "i == 5" --> block1 - block2 -- "else" --> block4 - block1 --> return + start --> block5 + block5 -- "range(111)" --> block3 + block5 -- "else" --> block4 + block4 --> return + block3 -- "i == 5" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block5 block0 --> return ``` @@ -142,14 +150,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["for i in range(12): + block1[["Loop continue"]] + block2["continue\n"] + block3["for i in range(12): continue\n"] - start --> block2 - block2 -- "range(12)" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "range(12)" --> block2 + block3 -- "else" --> block0 + block2 --> block3 + block1 --> block3 block0 --> return ``` @@ -168,19 +178,21 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["if True: + block1[["Loop continue"]] + block2["continue\n"] + block3["if True: continue\n"] - block3["for i in range(1110): + block4["for i in range(1110): if True: continue\n"] - start --> block3 - block3 -- "range(1110)" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> block3 + start --> block4 + block4 -- "range(1110)" --> block3 + block4 -- "else" --> block0 + block3 -- "True" --> block2 + block3 -- "else" --> block1 + block2 --> block4 + block1 --> block4 block0 --> return ``` @@ -198,14 +210,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["for i in range(13): + block1[["Loop continue"]] + block2["break\n"] + block3["for i in range(13): break\n"] - start --> block2 - block2 -- "range(13)" --> block1 - block2 -- "else" --> block0 - block1 --> return + start --> block3 + block3 -- "range(13)" --> block2 + block3 -- "else" --> block0 + block2 --> return + block1 --> block3 block0 --> return ``` @@ -224,19 +238,21 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["if True: + block1[["Loop continue"]] + block2["break\n"] + block3["if True: break\n"] - block3["for i in range(1110): + block4["for i in range(1110): if True: break\n"] - start --> block3 - block3 -- "range(1110)" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> return + start --> block4 + block4 -- "range(1110)" --> block3 + block4 -- "else" --> block0 + block3 -- "True" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block4 block0 --> return ``` @@ -256,18 +272,20 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["pass\n"] - block2["return 1\n"] - block3["for i in range(5): + block1[["Loop continue"]] + block2["pass\n"] + block3["return 1\n"] + block4["for i in range(5): pass else: return 1\n"] - start --> block3 - block3 -- "range(5)" --> block1 - block3 -- "else" --> block2 - block2 --> return - block1 --> block3 + start --> block4 + block4 -- "range(5)" --> block2 + block4 -- "else" --> block3 + block3 --> return + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -288,18 +306,20 @@ flowchart TD start(("Start")) return(("End")) block0["x = 1\n"] - block1["pass\n"] - block2["return 1\n"] - block3["for i in range(5): + block1[["Loop continue"]] + block2["pass\n"] + block3["return 1\n"] + block4["for i in range(5): pass else: return 1\n"] - start --> block3 - block3 -- "range(5)" --> block1 - block3 -- "else" --> block2 - block2 --> return - block1 --> block3 + start --> block4 + block4 -- "range(5)" --> block2 + block4 -- "else" --> block3 + block3 --> return + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -319,17 +339,19 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["pass\n"] + block1[["Loop continue"]] block2["pass\n"] - block3["for i in range(5): + block3["pass\n"] + block4["for i in range(5): pass else: pass\n"] - start --> block3 - block3 -- "range(5)" --> block1 - block3 -- "else" --> block2 - block2 --> block0 - block1 --> block3 + start --> block4 + block4 -- "range(5)" --> block2 + block4 -- "else" --> block3 + block3 --> block0 + block2 --> block1 + block1 --> block4 block0 --> return ``` diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__while.py.md.snap b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__while.py.md.snap index ace0171c0c09cc..504ab0b6b4d2bd 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__while.py.md.snap +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__while.py.md.snap @@ -17,14 +17,16 @@ flowchart TD start(("Start")) return(("End")) block0["return 1\n"] - block1["return #quot;unreachable#quot;\n"] - block2["while False: + block1[["Loop continue"]] + block2["return #quot;unreachable#quot;\n"] + block3["while False: return #quot;unreachable#quot;\n"] - start --> block2 - block2 -- "False" --> block1 - block2 -- "else" --> block0 - block1 --> return + start --> block3 + block3 -- "False" --> block2 + block3 -- "else" --> block0 + block2 --> return + block1 --> block3 block0 --> return ``` @@ -44,18 +46,20 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["return #quot;unreachable#quot;\n"] - block2["return 1\n"] - block3["while False: + block1[["Loop continue"]] + block2["return #quot;unreachable#quot;\n"] + block3["return 1\n"] + block4["while False: return #quot;unreachable#quot; else: return 1\n"] - start --> block3 - block3 -- "False" --> block1 - block3 -- "else" --> block2 + start --> block4 + block4 -- "False" --> block2 + block4 -- "else" --> block3 + block3 --> return block2 --> return - block1 --> return + block1 --> block4 block0 --> return ``` @@ -76,18 +80,20 @@ flowchart TD start(("Start")) return(("End")) block0["return #quot;also unreachable#quot;\n"] - block1["return #quot;unreachable#quot;\n"] - block2["return 1\n"] - block3["while False: + block1[["Loop continue"]] + block2["return #quot;unreachable#quot;\n"] + block3["return 1\n"] + block4["while False: return #quot;unreachable#quot; else: return 1\n"] - start --> block3 - block3 -- "False" --> block1 - block3 -- "else" --> block2 + start --> block4 + block4 -- "False" --> block2 + block4 -- "else" --> block3 + block3 --> return block2 --> return - block1 --> return + block1 --> block4 block0 --> return ``` @@ -106,14 +112,16 @@ flowchart TD start(("Start")) return(("End")) block0["return #quot;unreachable#quot;\n"] - block1["return 1\n"] - block2["while True: + block1[["Loop continue"]] + block2["return 1\n"] + block3["while True: return 1\n"] - start --> block2 - block2 -- "True" --> block1 - block2 -- "else" --> block0 - block1 --> return + start --> block3 + block3 -- "True" --> block2 + block3 -- "else" --> block0 + block2 --> return + block1 --> block3 block0 --> return ``` @@ -133,18 +141,20 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["return 1\n"] - block2["return #quot;unreachable#quot;\n"] - block3["while True: + block1[["Loop continue"]] + block2["return 1\n"] + block3["return #quot;unreachable#quot;\n"] + block4["while True: return 1 else: return #quot;unreachable#quot;\n"] - start --> block3 - block3 -- "True" --> block1 - block3 -- "else" --> block2 + start --> block4 + block4 -- "True" --> block2 + block4 -- "else" --> block3 + block3 --> return block2 --> return - block1 --> return + block1 --> block4 block0 --> return ``` @@ -165,18 +175,20 @@ flowchart TD start(("Start")) return(("End")) block0["return #quot;also unreachable#quot;\n"] - block1["return 1\n"] - block2["return #quot;unreachable#quot;\n"] - block3["while True: + block1[["Loop continue"]] + block2["return 1\n"] + block3["return #quot;unreachable#quot;\n"] + block4["while True: return 1 else: return #quot;unreachable#quot;\n"] - start --> block3 - block3 -- "True" --> block1 - block3 -- "else" --> block2 + start --> block4 + block4 -- "True" --> block2 + block4 -- "else" --> block3 + block3 --> return block2 --> return - block1 --> return + block1 --> block4 block0 --> return ``` @@ -196,14 +208,16 @@ flowchart TD start(("Start")) return(("End")) block0["return i\n"] - block1["i += 1\n"] - block2["i = 0\nwhile False: + block1[["Loop continue"]] + block2["i += 1\n"] + block3["i = 0\nwhile False: i += 1\n"] - start --> block2 - block2 -- "False" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "False" --> block2 + block3 -- "else" --> block0 + block2 --> block1 + block1 --> block3 block0 --> return ``` @@ -223,14 +237,16 @@ flowchart TD start(("Start")) return(("End")) block0["return i\n"] - block1["i += 1\n"] - block2["i = 0\nwhile True: + block1[["Loop continue"]] + block2["i += 1\n"] + block3["i = 0\nwhile True: i += 1\n"] - start --> block2 - block2 -- "True" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "True" --> block2 + block3 -- "else" --> block0 + block2 --> block1 + block1 --> block3 block0 --> return ``` @@ -249,14 +265,16 @@ flowchart TD start(("Start")) return(("End")) block0["return 1\n"] - block1["pass\n"] - block2["while True: + block1[["Loop continue"]] + block2["pass\n"] + block3["while True: pass\n"] - start --> block2 - block2 -- "True" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "True" --> block2 + block3 -- "else" --> block0 + block2 --> block1 + block1 --> block3 block0 --> return ``` @@ -278,22 +296,24 @@ flowchart TD start(("Start")) return(("End")) block0["return i\n"] - block1["i += 1\n"] - block2["print(#quot;ok#quot;)\n"] - block3["if True: + block1[["Loop continue"]] + block2["i += 1\n"] + block3["print(#quot;ok#quot;)\n"] + block4["if True: print(#quot;ok#quot;)\n"] - block4["i = 0\nwhile True: + block5["i = 0\nwhile True: if True: print(#quot;ok#quot;) i += 1\n"] - start --> block4 + start --> block5 + block5 -- "True" --> block4 + block5 -- "else" --> block0 block4 -- "True" --> block3 - block4 -- "else" --> block0 - block3 -- "True" --> block2 - block3 -- "else" --> block1 + block4 -- "else" --> block2 + block3 --> block2 block2 --> block1 - block1 --> block4 + block1 --> block5 block0 --> return ``` @@ -315,22 +335,24 @@ flowchart TD start(("Start")) return(("End")) block0["return i\n"] - block1["i += 1\n"] - block2["print(#quot;ok#quot;)\n"] - block3["if False: + block1[["Loop continue"]] + block2["i += 1\n"] + block3["print(#quot;ok#quot;)\n"] + block4["if False: print(#quot;ok#quot;)\n"] - block4["i = 0\nwhile True: + block5["i = 0\nwhile True: if False: print(#quot;ok#quot;) i += 1\n"] - start --> block4 - block4 -- "True" --> block3 - block4 -- "else" --> block0 - block3 -- "False" --> block2 - block3 -- "else" --> block1 + start --> block5 + block5 -- "True" --> block4 + block5 -- "else" --> block0 + block4 -- "False" --> block3 + block4 -- "else" --> block2 + block3 --> block2 block2 --> block1 - block1 --> block4 + block1 --> block5 block0 --> return ``` @@ -350,19 +372,21 @@ flowchart TD start(("Start")) return(("End")) block0["return 0\n"] - block1["return 1\n"] - block2["if True: + block1[["Loop continue"]] + block2["return 1\n"] + block3["if True: return 1\n"] - block3["while True: + block4["while True: if True: return 1\n"] - start --> block3 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> return + block3 -- "else" --> block1 + block2 --> return + block1 --> block4 block0 --> return ``` @@ -380,14 +404,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["while True: + block1[["Loop continue"]] + block2["continue\n"] + block3["while True: continue\n"] - start --> block2 - block2 -- "True" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "True" --> block2 + block3 -- "else" --> block0 + block2 --> block3 + block1 --> block3 block0 --> return ``` @@ -405,14 +431,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["while False: + block1[["Loop continue"]] + block2["continue\n"] + block3["while False: continue\n"] - start --> block2 - block2 -- "False" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "False" --> block2 + block3 -- "else" --> block0 + block2 --> block3 + block1 --> block3 block0 --> return ``` @@ -430,14 +458,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["while True: + block1[["Loop continue"]] + block2["break\n"] + block3["while True: break\n"] - start --> block2 - block2 -- "True" --> block1 - block2 -- "else" --> block0 - block1 --> return + start --> block3 + block3 -- "True" --> block2 + block3 -- "else" --> block0 + block2 --> return + block1 --> block3 block0 --> return ``` @@ -455,14 +485,16 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["while False: + block1[["Loop continue"]] + block2["break\n"] + block3["while False: break\n"] - start --> block2 - block2 -- "False" --> block1 - block2 -- "else" --> block0 - block1 --> return + start --> block3 + block3 -- "False" --> block2 + block3 -- "else" --> block0 + block2 --> return + block1 --> block3 block0 --> return ``` @@ -481,19 +513,21 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["continue\n"] - block2["if True: + block1[["Loop continue"]] + block2["continue\n"] + block3["if True: continue\n"] - block3["while True: + block4["while True: if True: continue\n"] - start --> block3 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> block3 + block3 -- "else" --> block1 + block2 --> block4 + block1 --> block4 block0 --> return ``` @@ -512,19 +546,21 @@ flowchart TD start(("Start")) return(("End")) block0[["`*(empty)*`"]] - block1["break\n"] - block2["if True: + block1[["Loop continue"]] + block2["break\n"] + block3["if True: break\n"] - block3["while True: + block4["while True: if True: break\n"] - start --> block3 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 -- "True" --> block1 - block2 -- "else" --> block3 - block1 --> return + block3 -- "else" --> block1 + block2 --> return + block1 --> block4 block0 --> return ``` @@ -546,19 +582,21 @@ flowchart TD start(("Start")) return(("End")) block0["x = 3\n"] - block1["x = 2\n"] - block2["x = 0\nx = 1\nbreak\n"] - block3["while True: + block1[["Loop continue"]] + block2["x = 2\n"] + block3["x = 0\nx = 1\nbreak\n"] + block4["while True: x = 0 x = 1 break x = 2\n"] - start --> block3 - block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 --> block0 - block1 --> block0 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 + block3 --> block0 + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -580,19 +618,21 @@ flowchart TD start(("Start")) return(("End")) block0["x = 3\n"] - block1["x = 2\n"] - block2["x = 0\nx = 1\ncontinue\n"] - block3["while True: + block1[["Loop continue"]] + block2["x = 2\n"] + block3["x = 0\nx = 1\ncontinue\n"] + block4["while True: x = 0 x = 1 continue x = 2\n"] - start --> block3 - block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 --> block3 - block1 --> block0 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 + block3 --> block4 + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -614,19 +654,21 @@ flowchart TD start(("Start")) return(("End")) block0["x = 3\n"] - block1["x = 2\n"] - block2["x = 0\nx = 1\nreturn\n"] - block3["while True: + block1[["Loop continue"]] + block2["x = 2\n"] + block3["x = 0\nx = 1\nreturn\n"] + block4["while True: x = 0 x = 1 return x = 2\n"] - start --> block3 - block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 --> return - block1 --> block0 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 + block3 --> return + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -648,19 +690,21 @@ flowchart TD start(("Start")) return(("End")) block0["x = 3\n"] - block1["x = 2\n"] - block2["x = 0\nx = 1\nraise Exception\n"] - block3["while True: + block1[["Loop continue"]] + block2["x = 2\n"] + block3["x = 0\nx = 1\nraise Exception\n"] + block4["while True: x = 0 x = 1 raise Exception x = 2\n"] - start --> block3 - block3 -- "True" --> block2 - block3 -- "else" --> block0 - block2 --> return - block1 --> block0 + start --> block4 + block4 -- "True" --> block3 + block4 -- "else" --> block0 + block3 --> return + block2 --> block1 + block1 --> block4 block0 --> return ``` @@ -688,7 +732,8 @@ flowchart TD start(("Start")) return(("End")) block0["self.thread = threading.Thread(target=self._run_web_server)\n"] - block1["try: + block1[["Loop continue"]] + block2["try: self.server = HTTPServer((host, port), HtmlOnlyHandler) self.host = host self.port = port @@ -696,7 +741,7 @@ flowchart TD except OSError: log.debug(f#quot;port {port} is in use, trying to next one#quot;) port += 1\n"] - block2["self.stop_serving = False\nwhile True: + block3["self.stop_serving = False\nwhile True: try: self.server = HTTPServer((host, port), HtmlOnlyHandler) self.host = host @@ -706,9 +751,10 @@ flowchart TD log.debug(f#quot;port {port} is in use, trying to next one#quot;) port += 1\n"] - start --> block2 - block2 -- "True" --> block1 - block2 -- "else" --> block0 - block1 --> block2 + start --> block3 + block3 -- "True" --> block2 + block3 -- "else" --> block0 + block2 --> block1 + block1 --> block3 block0 --> return ``` diff --git a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs index 58dc55e6c376ae..e3a5bdf5de528e 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs @@ -3,7 +3,7 @@ use std::{fmt, iter, usize}; use log::error; use ruff_python_ast::{ Expr, ExprBooleanLiteral, Identifier, MatchCase, Pattern, PatternMatchAs, PatternMatchOr, Stmt, - StmtFor, StmtMatch, StmtReturn, StmtTry, StmtWhile, StmtWith, + StmtContinue, StmtFor, StmtMatch, StmtReturn, StmtTry, StmtWhile, StmtWith, }; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -263,14 +263,14 @@ impl<'stmt> From<&'stmt [Stmt]> for BasicBlocks<'stmt> { /// Basic code block, sequence of statements unconditionally executed /// "together". -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] struct BasicBlock<'stmt> { stmts: &'stmt [Stmt], next: NextBlock<'stmt>, } /// Edge between basic blocks (in the control-flow graph). -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] enum NextBlock<'stmt> { /// Always continue with a block. Always(BlockIndex), @@ -339,9 +339,16 @@ impl<'stmt> BasicBlock<'stmt> { next: NextBlock::Terminate, }; + const LOOP_CONTINUE: BasicBlock<'static> = BasicBlock { + stmts: &[Stmt::Continue(StmtContinue { + range: TextRange::new(TextSize::new(0), TextSize::new(0)), + })], + next: NextBlock::Terminate, + }; + /// Return true if the block is a sentinel or fake block. fn is_sentinel(&self) -> bool { - self.is_empty() || self.is_exception() + self.is_empty() || self.is_exception() || self.is_loop_continue() } /// Returns an empty block that terminates. @@ -353,6 +360,10 @@ impl<'stmt> BasicBlock<'stmt> { fn is_exception(&self) -> bool { matches!(self.next, NextBlock::Terminate) && BasicBlock::EXCEPTION.stmts == self.stmts } + + fn is_loop_continue(&self) -> bool { + self.stmts == BasicBlock::LOOP_CONTINUE.stmts + } } /// Handle a loop block, such as a `while`, `for` or `async for` statement. @@ -364,28 +375,13 @@ fn loop_block<'stmt>( after: Option, ) -> NextBlock<'stmt> { let after_block = blocks.maybe_next_block_index(after, || true); + let loop_continue_index = blocks.blocks.push(BasicBlock::LOOP_CONTINUE.clone()); // NOTE: a while loop's body must not be empty, so we can safely // create at least one block from it. - let last_statement_index = blocks.append_blocks(body, after); + let last_statement_index = blocks.append_blocks(body, Some(loop_continue_index)); let last_orelse_statement = blocks.append_blocks_if_not_empty(orelse, after_block); - // `create_blocks` always continues to the next block by - // default. However in a while loop we want to continue with the - // while block (we're about to create) to create the loop. - // NOTE: `blocks.len()` is an invalid index at time of creation - // as it points to the block which we're about to create. - // - // FIXME: This should check the last block, not the first block. - blocks.change_next_block( - last_statement_index, - after_block, - blocks.blocks.next_index(), - |block| { - // For `break` statements we don't want to continue with the - // loop, but instead with the statement after the loop (i.e. - // not change anything). - !block.stmts.last().is_some_and(Stmt::is_break_stmt) - }, - ); + + blocks.blocks[loop_continue_index].next = NextBlock::Always(blocks.blocks.next_index()); NextBlock::If { condition, next: last_statement_index, @@ -491,12 +487,11 @@ impl<'stmt> BasicBlocksBuilder<'stmt> { | Stmt::Assign(_) | Stmt::AugAssign(_) | Stmt::AnnAssign(_) - | Stmt::Break(_) | Stmt::TypeAlias(_) | Stmt::IpyEscapeCommand(_) | Stmt::Pass(_) => self.unconditional_next_block(after), - Stmt::Continue(_) => { - // NOTE: the next branch gets fixed up in `change_next_block`. + Stmt::Break(_) | Stmt::Continue(_) => { + // NOTE: These are handled in post_processing. self.unconditional_next_block(after) } // Statements that (can) divert the control flow. @@ -1029,6 +1024,8 @@ impl<'stmt, 'source> fmt::Display for MermaidGraph<'stmt, 'source> { write!(f, "`*(empty)*`")?; } else if block.is_exception() { write!(f, "Exception raised")?; + } else if block.is_loop_continue() { + write!(f, "Loop continue")?; } else { for stmt in block.stmts { let code_line = &self.source[stmt.range()].trim();