Skip to content

Commit 6d9205e

Browse files
authored
[ruff_linter] - Use LibCST in adjust_indentation for mixed whitespace (#12740)
1 parent df7345e commit 6d9205e

File tree

4 files changed

+50
-4
lines changed

4 files changed

+50
-4
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_return/RET505.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,9 @@ def indent(x, y, w, z):
238238
# comment
239239
c = 3
240240
return z
241+
242+
def f():
243+
if True:
244+
return True
245+
else:
246+
return False

crates/ruff_linter/src/fix/edits.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,25 @@ pub(crate) fn adjust_indentation(
300300
indexer: &Indexer,
301301
stylist: &Stylist,
302302
) -> Result<String> {
303+
let contents = locator.slice(range);
304+
303305
// If the range includes a multi-line string, use LibCST to ensure that we don't adjust the
304306
// whitespace _within_ the string.
305-
if indexer.multiline_ranges().intersects(range) || indexer.fstring_ranges().intersects(range) {
306-
let contents = locator.slice(range);
307+
let contains_multiline_string =
308+
indexer.multiline_ranges().intersects(range) || indexer.fstring_ranges().intersects(range);
309+
310+
// If the range has mixed indentation, we will use LibCST as well.
311+
let mixed_indentation = contents.universal_newlines().any(|line| {
312+
let trimmed = line.trim_whitespace_start();
313+
if trimmed.is_empty() {
314+
return false;
315+
}
316+
317+
let line_indentation: &str = &line[..line.len() - trimmed.len()];
318+
line_indentation.contains('\t') && line_indentation.contains(' ')
319+
});
307320

321+
if contains_multiline_string || mixed_indentation {
308322
let module_text = format!("def f():{}{contents}", stylist.line_ending().as_str());
309323

310324
let mut tree = match_statement(&module_text)?;
@@ -322,7 +336,6 @@ pub(crate) fn adjust_indentation(
322336
Ok(module_text)
323337
} else {
324338
// Otherwise, we can do a simple adjustment ourselves.
325-
let contents = locator.slice(range);
326339
Ok(dedent_to(contents, indentation))
327340
}
328341
}

crates/ruff_linter/src/rules/flake8_return/snapshots/ruff_linter__rules__flake8_return__tests__RET505_RET505.py.snap

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,12 @@ RET505.py:237:5: RET505 Unnecessary `else` after `return` statement
215215
|
216216
= help: Remove unnecessary `else`
217217

218-
218+
RET505.py:245:2: RET505 Unnecessary `else` after `return` statement
219+
|
220+
243 | if True:
221+
244 | return True
222+
245 | else:
223+
| ^^^^ RET505
224+
246 | return False
225+
|
226+
= help: Remove unnecessary `else`

crates/ruff_linter/src/rules/flake8_return/snapshots/ruff_linter__rules__flake8_return__tests__preview__RET505_RET505.py.snap

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,5 +460,24 @@ RET505.py:237:5: RET505 [*] Unnecessary `else` after `return` statement
460460
240 |- return z
461461
238 |+ c = 3
462462
239 |+ return z
463+
241 240 |
464+
242 241 | def f():
465+
243 242 | if True:
463466

467+
RET505.py:245:2: RET505 [*] Unnecessary `else` after `return` statement
468+
|
469+
243 | if True:
470+
244 | return True
471+
245 | else:
472+
| ^^^^ RET505
473+
246 | return False
474+
|
475+
= help: Remove unnecessary `else`
464476

477+
Safe fix
478+
242 242 | def f():
479+
243 243 | if True:
480+
244 244 | return True
481+
245 |- else:
482+
246 |- return False
483+
245 |+ return False

0 commit comments

Comments
 (0)