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 29fb86e
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 29 deletions.
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(b_range) => (*a_range, b_range),
None => continue,
}
}
(Tok::FStringEnd, Tok::String { .. }) => {
match indexer.fstring_ranges().innermost(a_range.start()) {
Some(a_range) => (a_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
4 changes: 3 additions & 1 deletion crates/ruff_python_index/src/fstring_ranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ 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.
///
/// Note that the ranges for all unterminated f-strings are not stored.
#[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,6 @@ impl FStringRangesBuilder {
}

pub(crate) fn finish(self) -> FStringRanges {
debug_assert!(self.start_locations.is_empty());
FStringRanges { raw: self.raw }
}
}

0 comments on commit 29fb86e

Please sign in to comment.