Skip to content

Commit

Permalink
Allow unterminated f-strings in the indexer
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvmanila committed Oct 24, 2023
1 parent 7f4ea66 commit 7880903
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 29 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,27 @@ pub(crate) fn implicit(
{
let (a_range, b_range) = match (a_tok, b_tok) {
(Tok::String { .. }, Tok::String { .. }) => (*a_range, *b_range),
(Tok::String { .. }, Tok::FStringStart) => (
*a_range,
indexer.fstring_ranges().innermost(b_range.start()).unwrap(),
),
(Tok::FStringEnd, Tok::String { .. }) => (
indexer.fstring_ranges().innermost(a_range.start()).unwrap(),
*b_range,
),
(Tok::FStringEnd, Tok::FStringStart) => (
indexer.fstring_ranges().innermost(a_range.start()).unwrap(),
indexer.fstring_ranges().innermost(b_range.start()).unwrap(),
),
(Tok::String { .. }, Tok::FStringStart) => {
match indexer.fstring_ranges().innermost(b_range.start()) {
Some(range) => (*a_range, range),
None => continue,
}
}
(Tok::FStringEnd, Tok::String { .. }) => {
match indexer.fstring_ranges().innermost(a_range.start()) {
Some(range) => (range, *b_range),
None => continue,
}
}
(Tok::FStringEnd, Tok::FStringStart) => {
match (
indexer.fstring_ranges().innermost(a_range.start()),
indexer.fstring_ranges().innermost(b_range.start()),
) {
(Some(a_range), Some(b_range)) => (a_range, b_range),
_ => continue,
}
}
_ => continue,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,21 @@ pub(crate) fn invalid_escape_sequence(
token: &Tok,
token_range: TextRange,
) {
let token_source_code = match token {
let (token_source_code, string_start_location) = match token {
Tok::FStringMiddle { value, is_raw } => {
if *is_raw {
return;
}
value.as_str()
let Some(range) = indexer.fstring_ranges().innermost(token_range.start()) else {
return;
};
(value.as_str(), range.start())
}
Tok::String { kind, .. } => {
if kind.is_raw() {
return;
}
locator.slice(token_range)
(locator.slice(token_range), token_range.start())
}
_ => return,
};
Expand Down Expand Up @@ -166,25 +169,14 @@ pub(crate) fn invalid_escape_sequence(
)));
}
} else {
let tok_start = if token.is_f_string_middle() {
// SAFETY: If this is a `FStringMiddle` token, then the indexer
// must have the f-string range.
indexer
.fstring_ranges()
.innermost(token_range.start())
.unwrap()
.start()
} else {
token_range.start()
};
// Turn into raw string.
for diagnostic in &mut invalid_escape_sequence {
// If necessary, add a space between any leading keyword (`return`, `yield`,
// `assert`, etc.) and the string. For example, `return"foo"` is valid, but
// `returnr"foo"` is not.
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
pad_start("r".to_string(), tok_start, locator),
tok_start,
pad_start("r".to_string(), string_start_location, locator),
string_start_location,
)));
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_index/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ ruff_source_file = { path = "../ruff_source_file" }
ruff_text_size = { path = "../ruff_text_size" }

itertools = { workspace = true }
log = { workspace = true }

[dev-dependencies]
10 changes: 9 additions & 1 deletion crates/ruff_python_index/src/fstring_ranges.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use std::collections::BTreeMap;

use log::debug;

use ruff_python_parser::Tok;
use ruff_text_size::{TextRange, TextSize};

/// Stores the ranges of all f-strings in a file sorted by [`TextRange::start`].
/// There can be multiple overlapping ranges for nested f-strings.
#[derive(Debug)]
pub struct FStringRanges {
// Mapping from the f-string start location to its range.
raw: BTreeMap<TextSize, TextRange>,
}

Expand Down Expand Up @@ -89,7 +92,12 @@ impl FStringRangesBuilder {
}

pub(crate) fn finish(self) -> FStringRanges {
debug_assert!(self.start_locations.is_empty());
if !self.start_locations.is_empty() {
debug!(
"Unterminated f-strings detected at: {:?}",
self.start_locations
);
}
FStringRanges { raw: self.raw }
}
}

0 comments on commit 7880903

Please sign in to comment.