Fallback to end-of-file if ends in trailing continuation (#6789)

## Summary

Given:

```python
def end_of_file():
    if False:
        return 1
    x = 2 \

```

Then when searching for the end of the `x = 2` statement, we'd reach a
panic as we'd hit the last line (`\\`) and abort, since the universal
iterator doesn't return trailing newlines. Instead, we should just use
the end of the file as the fallback.

Closes https://github.com/astral-sh/ruff/issues/6787.

## Test Plan

`cargo test`
This commit is contained in:
Charlie Marsh
2023-08-22 15:12:26 -04:00
committed by GitHub
parent 2e00983762
commit ca2bb20063
3 changed files with 30 additions and 13 deletions

View File

@@ -320,3 +320,9 @@ def end_of_statement():
if True:
return "" \
; # type: ignore
def end_of_file():
if False:
return 1
x = 2 \

View File

@@ -25,19 +25,11 @@ pub(super) fn result_exists(returns: &[&ast::StmtReturn]) -> bool {
/// This method assumes that the statement is the last statement in its body; specifically, that
/// the statement isn't followed by a semicolon, followed by a multi-line statement.
pub(super) fn end_of_last_statement(stmt: &Stmt, locator: &Locator) -> TextSize {
if stmt.end() == locator.text_len() {
// End-of-file, so just return the end of the statement.
stmt.end()
} else {
// Otherwise, find the end of the last line that's "part of" the statement.
let contents = locator.after(stmt.end());
for line in contents.universal_newlines() {
if !line.ends_with('\\') {
return stmt.end() + line.end();
}
// Find the end of the last line that's "part of" the statement.
for line in locator.after(stmt.end()).universal_newlines() {
if !line.ends_with('\\') {
return stmt.end() + line.end();
}
unreachable!("Expected to find end-of-statement")
}
locator.text_len()
}

View File

@@ -380,5 +380,24 @@ RET503.py:320:9: RET503 [*] Missing explicit `return` at the end of function abl
321 321 | return "" \
322 322 | ; # type: ignore
323 |+ return None
323 324 |
324 325 |
325 326 | def end_of_file():
RET503.py:328:5: RET503 [*] Missing explicit `return` at the end of function able to return non-`None` value
|
326 | if False:
327 | return 1
328 | x = 2 \
| ^^^^^ RET503
|
= help: Add explicit `return` statement
Suggested fix
326 326 | if False:
327 327 | return 1
328 328 | x = 2 \
329 |+
330 |+ return None