Skip to content

Commit

Permalink
Revert "Remove unreachable-code feature (astral-sh#9463)"
Browse files Browse the repository at this point in the history
This reverts commit f9dd7bb.
  • Loading branch information
augustelalande committed Apr 16, 2024
1 parent 6dccbd2 commit 8f68125
Show file tree
Hide file tree
Showing 15 changed files with 4,275 additions and 0 deletions.
185 changes: 185 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF014.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
def after_return():
return "reachable"
return "unreachable"

async def also_works_on_async_functions():
return "reachable"
return "unreachable"

def if_always_true():
if True:
return "reachable"
return "unreachable"

def if_always_false():
if False:
return "unreachable"
return "reachable"

def if_elif_always_false():
if False:
return "unreachable"
elif False:
return "also unreachable"
return "reachable"

def if_elif_always_true():
if False:
return "unreachable"
elif True:
return "reachable"
return "also unreachable"

def ends_with_if():
if False:
return "unreachable"
else:
return "reachable"

def infinite_loop():
while True:
continue
return "unreachable"

''' TODO: we could determine these, but we don't yet.
def for_range_return():
for i in range(10):
if i == 5:
return "reachable"
return "unreachable"
def for_range_else():
for i in range(111):
if i == 5:
return "reachable"
else:
return "unreachable"
return "also unreachable"
def for_range_break():
for i in range(13):
return "reachable"
return "unreachable"
def for_range_if_break():
for i in range(1110):
if True:
return "reachable"
return "unreachable"
'''

def match_wildcard(status):
match status:
case _:
return "reachable"
return "unreachable"

def match_case_and_wildcard(status):
match status:
case 1:
return "reachable"
case _:
return "reachable"
return "unreachable"

def raise_exception():
raise Exception
return "unreachable"

def while_false():
while False:
return "unreachable"
return "reachable"

def while_false_else():
while False:
return "unreachable"
else:
return "reachable"

def while_false_else_return():
while False:
return "unreachable"
else:
return "reachable"
return "also unreachable"

def while_true():
while True:
return "reachable"
return "unreachable"

def while_true_else():
while True:
return "reachable"
else:
return "unreachable"

def while_true_else_return():
while True:
return "reachable"
else:
return "unreachable"
return "also unreachable"

def while_false_var_i():
i = 0
while False:
i += 1
return i

def while_true_var_i():
i = 0
while True:
i += 1
return i

def while_infinite():
while True:
pass
return "unreachable"

def while_if_true():
while True:
if True:
return "reachable"
return "unreachable"

# Test case found in the Bokeh repository that trigger a false positive.
def bokeh1(self, obj: BytesRep) -> bytes:
data = obj["data"]

if isinstance(data, str):
return base64.b64decode(data)
elif isinstance(data, Buffer):
buffer = data
else:
id = data["id"]

if id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f"can't resolve buffer '{id}'")

return buffer.data

'''
TODO: because `try` statements aren't handled this triggers a false positive as
the last statement is reached, but the rules thinks it isn't (it doesn't
see/process the break statement).
# Test case found in the Bokeh repository that trigger a false positive.
def bokeh2(self, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> None:
self.stop_serving = False
while True:
try:
self.server = HTTPServer((host, port), HtmlOnlyHandler)
self.host = host
self.port = port
break
except OSError:
log.debug(f"port {port} is in use, trying to next one")
port += 1
self.thread = threading.Thread(target=self._run_web_server)
'''
5 changes: 5 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::TrioAsyncFunctionWithTimeout) {
flake8_trio::rules::async_function_with_timeout(checker, function_def);
}
if checker.enabled(Rule::UnreachableCode) {
checker
.diagnostics
.extend(ruff::rules::unreachable::in_function(name, body));
}
if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &function_def.into());
}
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff_linter/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "011") => (RuleGroup::Removed, rules::ruff::rules::RuffStaticKeyDictComprehension),
(Ruff, "012") => (RuleGroup::Stable, rules::ruff::rules::MutableClassDefault),
(Ruff, "013") => (RuleGroup::Stable, rules::ruff::rules::ImplicitOptional),
#[allow(deprecated)]
(Ruff, "014") => (RuleGroup::Nursery, rules::ruff::rules::UnreachableCode),
(Ruff, "015") => (RuleGroup::Stable, rules::ruff::rules::UnnecessaryIterableAllocationForFirstElement),
(Ruff, "016") => (RuleGroup::Stable, rules::ruff::rules::InvalidIndexType),
(Ruff, "017") => (RuleGroup::Stable, rules::ruff::rules::QuadraticListSummation),
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff_linter/src/rules/ruff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ mod tests {
Path::new("RUF015.py")
)]
#[test_case(Rule::InvalidIndexType, Path::new("RUF016.py"))]
#[cfg_attr(
feature = "unreachable-code",
test_case(Rule::UnreachableCode, Path::new("RUF014.py"))
)]
#[test_case(Rule::QuadraticListSummation, Path::new("RUF017_1.py"))]
#[test_case(Rule::QuadraticListSummation, Path::new("RUF017_0.py"))]
#[test_case(Rule::AssignmentInAssert, Path::new("RUF018.py"))]
Expand Down
4 changes: 4 additions & 0 deletions crates/ruff_linter/src/rules/ruff/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub(crate) use test_rules::*;
pub(crate) use unnecessary_dict_comprehension_for_iterable::*;
pub(crate) use unnecessary_iterable_allocation_for_first_element::*;
pub(crate) use unnecessary_key_check::*;
#[cfg(feature = "unreachable-code")]
pub(crate) use unreachable::*;
pub(crate) use unused_noqa::*;

mod ambiguous_unicode_character;
Expand Down Expand Up @@ -58,6 +60,8 @@ pub(crate) mod test_rules;
mod unnecessary_dict_comprehension_for_iterable;
mod unnecessary_iterable_allocation_for_first_element;
mod unnecessary_key_check;
#[cfg(feature = "unreachable-code")]
pub(crate) mod unreachable;
mod unused_noqa;

#[derive(Clone, Copy)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
source: crates/ruff_linter/src/rules/ruff/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 func():
assert True
```

### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert True\n"]
start --> block2
block2 -- "True" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```

## Function 1
### Source
```python
def func():
assert False
```

### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert False\n"]
start --> block2
block2 -- "False" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```

## Function 2
### Source
```python
def func():
assert True, "oops"
```

### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert True, #quot;oops#quot;\n"]
start --> block2
block2 -- "True" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```

## Function 3
### Source
```python
def func():
assert False, "oops"
```

### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert False, #quot;oops#quot;\n"]
start --> block2
block2 -- "False" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```


Loading

0 comments on commit 8f68125

Please sign in to comment.