Allow Locator#slice to take Ranged (#6922)

## Summary

As a small quality-of-life improvement, the locator can now slice like
`locator.slice(stmt)` instead of requiring
`locator.slice(stmt.range())`.

## Test Plan

`cargo test`
This commit is contained in:
Charlie Marsh 2023-08-28 11:08:39 -04:00 committed by GitHub
parent 58f5f27dc3
commit aea7500c1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 89 additions and 96 deletions

View file

@ -8,7 +8,6 @@ use libcst_native::{
use ruff_python_ast::Stmt;
use ruff_python_codegen::Stylist;
use ruff_source_file::Locator;
use ruff_text_size::Ranged;
use crate::cst::helpers::compose_module_path;
use crate::cst::matchers::match_statement;
@ -39,7 +38,7 @@ pub(crate) fn remove_imports<'a>(
locator: &Locator,
stylist: &Stylist,
) -> Result<Option<String>> {
let module_text = locator.slice(stmt.range());
let module_text = locator.slice(stmt);
let mut tree = match_statement(module_text)?;
let Statement::Simple(body) = &mut tree else {
@ -118,7 +117,7 @@ pub(crate) fn retain_imports(
locator: &Locator,
stylist: &Stylist,
) -> Result<String> {
let module_text = locator.slice(stmt.range());
let module_text = locator.slice(stmt);
let mut tree = match_statement(module_text)?;
let Statement::Simple(body) = &mut tree else {

View file

@ -163,9 +163,9 @@ pub(crate) fn definitions(checker: &mut Checker) {
continue;
};
let contents = checker.locator.slice(expr.range());
let contents = checker.locator().slice(expr);
let indentation = checker.locator.slice(TextRange::new(
let indentation = checker.locator().slice(TextRange::new(
checker.locator.line_start(expr.start()),
expr.start(),
));

View file

@ -76,7 +76,7 @@ impl StatementVisitor<'_> for StringLinesVisitor<'_> {
}) = value.as_ref()
{
for line in UniversalNewlineIterator::with_offset(
self.locator.slice(value.range()),
self.locator.slice(value.as_ref()),
value.start(),
) {
self.string_lines.push(line.start());

View file

@ -319,7 +319,7 @@ impl<'a> Importer<'a> {
/// Add the given member to an existing `Stmt::ImportFrom` statement.
fn add_member(&self, stmt: &Stmt, member: &str) -> Result<Edit> {
let mut statement = match_statement(self.locator.slice(stmt.range()))?;
let mut statement = match_statement(self.locator.slice(stmt))?;
let import_from = match_import_from(&mut statement)?;
let aliases = match_aliases(import_from)?;
aliases.push(ImportAlias {

View file

@ -81,7 +81,7 @@ pub(crate) fn getattr_with_constant(
let mut diagnostic = Diagnostic::new(GetAttrWithConstant, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
format!("{}.{}", checker.locator().slice(obj.range()), value),
format!("{}.{}", checker.locator().slice(obj), value),
expr.range(),
)));
}

View file

@ -84,7 +84,7 @@ pub(crate) fn unreliable_callable_check(
if id == "hasattr" {
if checker.semantic().is_builtin("callable") {
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
format!("callable({})", checker.locator().slice(obj.range())),
format!("callable({})", checker.locator().slice(obj)),
expr.range(),
)));
}

View file

@ -31,7 +31,7 @@ pub(crate) fn fix_unnecessary_generator_list(
expr: &Expr,
) -> Result<Edit> {
// Expr(Call(GeneratorExp)))) -> Expr(ListComp)))
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -63,7 +63,7 @@ pub(crate) fn fix_unnecessary_generator_set(checker: &Checker, expr: &Expr) -> R
let stylist = checker.stylist();
// Expr(Call(GeneratorExp)))) -> Expr(SetComp)))
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -97,7 +97,7 @@ pub(crate) fn fix_unnecessary_generator_dict(checker: &Checker, expr: &Expr) ->
let locator = checker.locator();
let stylist = checker.stylist();
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -141,7 +141,7 @@ pub(crate) fn fix_unnecessary_list_comprehension_set(
let stylist = checker.stylist();
// Expr(Call(ListComp)))) ->
// Expr(SetComp)))
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -176,7 +176,7 @@ pub(crate) fn fix_unnecessary_list_comprehension_dict(
let locator = checker.locator();
let stylist = checker.stylist();
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -261,7 +261,7 @@ pub(crate) fn fix_unnecessary_literal_set(checker: &Checker, expr: &Expr) -> Res
let stylist = checker.stylist();
// Expr(Call(List|Tuple)))) -> Expr(Set)))
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -302,7 +302,7 @@ pub(crate) fn fix_unnecessary_literal_dict(checker: &Checker, expr: &Expr) -> Re
let stylist = checker.stylist();
// Expr(Call(List|Tuple)))) -> Expr(Dict)))
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -371,7 +371,7 @@ pub(crate) fn fix_unnecessary_collection_call(checker: &Checker, expr: &Expr) ->
let stylist = checker.stylist();
// Expr(Call("list" | "tuple" | "dict")))) -> Expr(List|Tuple|Dict)
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call(&tree)?;
let name = match_name(&call.func)?;
@ -522,7 +522,7 @@ pub(crate) fn fix_unnecessary_literal_within_tuple_call(
stylist: &Stylist,
expr: &Expr,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -572,7 +572,7 @@ pub(crate) fn fix_unnecessary_literal_within_list_call(
stylist: &Stylist,
expr: &Expr,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -625,7 +625,7 @@ pub(crate) fn fix_unnecessary_list_call(
expr: &Expr,
) -> Result<Edit> {
// Expr(Call(List|Tuple)))) -> Expr(List|Tuple)))
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -646,7 +646,7 @@ pub(crate) fn fix_unnecessary_call_around_sorted(
stylist: &Stylist,
expr: &Expr,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let outer_call = match_call_mut(&mut tree)?;
let inner_call = match &outer_call.args[..] {
@ -758,7 +758,7 @@ pub(crate) fn fix_unnecessary_double_cast_or_process(
stylist: &Stylist,
expr: &Expr,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let outer_call = match_call_mut(&mut tree)?;
@ -789,7 +789,7 @@ pub(crate) fn fix_unnecessary_comprehension(
stylist: &Stylist,
expr: &Expr,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
match &tree {
@ -878,7 +878,7 @@ pub(crate) fn fix_unnecessary_map(
parent: Option<&Expr>,
object_type: ObjectType,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -1021,7 +1021,7 @@ pub(crate) fn fix_unnecessary_literal_within_dict_call(
stylist: &Stylist,
expr: &Expr,
) -> Result<Edit> {
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;
let arg = match_arg(call)?;
@ -1041,7 +1041,7 @@ pub(crate) fn fix_unnecessary_comprehension_any_all(
expr: &Expr,
) -> Result<Fix> {
// Expr(ListComp) -> Expr(GeneratorExp)
let module_text = locator.slice(expr.range());
let module_text = locator.slice(expr);
let mut tree = match_expression(module_text)?;
let call = match_call_mut(&mut tree)?;

View file

@ -55,7 +55,7 @@ pub(crate) fn duplicate_union_member<'a>(checker: &mut Checker, expr: &'a Expr)
// Replace the parent with its non-duplicate child.
let child = if expr == left.as_ref() { right } else { left };
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
checker.locator().slice(child.range()).to_string(),
checker.locator().slice(child.as_ref()).to_string(),
parent.range(),
)));
}

View file

@ -88,7 +88,7 @@ pub(crate) fn redundant_literal_union<'a>(checker: &mut Checker, union: &'a Expr
if builtin_types_in_union.contains(&constant_type) {
checker.diagnostics.push(Diagnostic::new(
RedundantLiteralUnion {
literal: checker.locator().slice(literal_expr.range()).to_string(),
literal: checker.locator().slice(literal_expr).to_string(),
builtin_type: constant_type,
},
literal_expr.range(),

View file

@ -249,7 +249,7 @@ fn is_valid_default_value_with_annotation(
..
}) = left.as_ref()
{
return locator.slice(left.range()).len() <= 10;
return locator.slice(left.as_ref()).len() <= 10;
} else if let Expr::UnaryOp(ast::ExprUnaryOp {
op: UnaryOp::USub,
operand,
@ -262,7 +262,7 @@ fn is_valid_default_value_with_annotation(
..
}) = operand.as_ref()
{
return locator.slice(operand.range()).len() <= 10;
return locator.slice(operand.as_ref()).len() <= 10;
}
}
}

View file

@ -63,7 +63,7 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp
UnnecessaryLiteralUnion {
members: literal_exprs
.into_iter()
.map(|literal_expr| checker.locator().slice(literal_expr.range()).to_string())
.map(|expr| checker.locator().slice(expr.as_ref()).to_string())
.collect(),
},
expr.range(),

View file

@ -78,7 +78,7 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr)
UnnecessaryTypeUnion {
members: type_exprs
.into_iter()
.map(|type_expr| checker.locator().slice(type_expr.range()).to_string())
.map(|type_expr| checker.locator().slice(type_expr.as_ref()).to_string())
.collect(),
is_pep604_union,
},

View file

@ -411,7 +411,7 @@ fn to_pytest_raises_args<'a>(
"assertRaises" | "failUnlessRaises" => {
match (arguments.args.as_slice(), arguments.keywords.as_slice()) {
// Ex) `assertRaises(Exception)`
([arg], []) => Cow::Borrowed(checker.locator().slice(arg.range())),
([arg], []) => Cow::Borrowed(checker.locator().slice(arg)),
// Ex) `assertRaises(expected_exception=Exception)`
([], [kwarg])
if kwarg
@ -429,8 +429,8 @@ fn to_pytest_raises_args<'a>(
// Ex) `assertRaisesRegex(Exception, regex)`
([arg1, arg2], []) => Cow::Owned(format!(
"{}, match={}",
checker.locator().slice(arg1.range()),
checker.locator().slice(arg2.range())
checker.locator().slice(arg1),
checker.locator().slice(arg2)
)),
// Ex) `assertRaisesRegex(Exception, expected_regex=regex)`
([arg], [kwarg])
@ -441,7 +441,7 @@ fn to_pytest_raises_args<'a>(
{
Cow::Owned(format!(
"{}, match={}",
checker.locator().slice(arg.range()),
checker.locator().slice(arg),
checker.locator().slice(kwarg.value.range())
))
}

View file

@ -537,7 +537,7 @@ fn unnecessary_assign(checker: &mut Checker, stack: &Stack) {
edits::delete_stmt(stmt, None, checker.locator(), checker.indexer());
// Replace the `x = 1` statement with `return 1`.
let content = checker.locator().slice(assign.range());
let content = checker.locator().slice(assign);
let equals_index = content
.find('=')
.ok_or(anyhow::anyhow!("expected '=' in assignment statement"))?;

View file

@ -238,10 +238,10 @@ pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
let expected = format!(
"{}({})",
checker.locator().slice(func.range()),
checker.locator().slice(key.range())
checker.locator().slice(func.as_ref()),
checker.locator().slice(key)
);
let original = checker.locator().slice(expr.range()).to_string();
let original = checker.locator().slice(expr).to_string();
let mut diagnostic = Diagnostic::new(
DictGetWithNoneDefault {

View file

@ -155,7 +155,7 @@ pub(crate) fn explicit_true_false_in_ifexpr(
if checker.patch(diagnostic.kind.rule()) {
if test.is_compare_expr() {
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
checker.locator().slice(test.range()).to_string(),
checker.locator().slice(test).to_string(),
expr.range(),
)));
} else if checker.semantic().is_builtin("bool") {

View file

@ -273,7 +273,7 @@ pub(crate) fn double_negation(checker: &mut Checker, expr: &Expr, op: UnaryOp, o
if checker.patch(diagnostic.kind.rule()) {
if checker.semantic().in_boolean_test() {
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
checker.locator().slice(operand.range()).to_string(),
checker.locator().slice(operand.as_ref()).to_string(),
expr.range(),
)));
} else if checker.semantic().is_builtin("bool") {

View file

@ -13,7 +13,7 @@ pub(super) fn trailing_comma(
locator: &Locator,
source_type: PySourceType,
) -> TrailingComma {
let contents = locator.slice(stmt.range());
let contents = locator.slice(stmt);
let mut count = 0u32;
let mut trailing_comma = TrailingComma::Absent;
for (tok, _) in lexer::lex_starts_at(contents, source_type.as_mode(), stmt.start()).flatten() {

View file

@ -103,7 +103,7 @@ pub(crate) fn incorrect_dict_iterator(checker: &mut Checker, stmt_for: &ast::Stm
if checker.patch(diagnostic.kind.rule()) {
let replace_attribute = Edit::range_replacement("values".to_string(), attr.range());
let replace_target = Edit::range_replacement(
checker.locator().slice(value.range()).to_string(),
checker.locator().slice(value).to_string(),
stmt_for.target.range(),
);
diagnostic.set_fix(Fix::suggested_edits(replace_attribute, [replace_target]));
@ -121,7 +121,7 @@ pub(crate) fn incorrect_dict_iterator(checker: &mut Checker, stmt_for: &ast::Stm
if checker.patch(diagnostic.kind.rule()) {
let replace_attribute = Edit::range_replacement("keys".to_string(), attr.range());
let replace_target = Edit::range_replacement(
checker.locator().slice(key.range()).to_string(),
checker.locator().slice(key).to_string(),
stmt_for.target.range(),
);
diagnostic.set_fix(Fix::suggested_edits(replace_attribute, [replace_target]));

View file

@ -17,7 +17,7 @@ pub(super) fn remove_unused_format_arguments_from_dict(
locator: &Locator,
stylist: &Stylist,
) -> Result<Edit> {
let source_code = locator.slice(dict.range());
let source_code = locator.slice(dict);
transform_expression(source_code, stylist, |mut expression| {
let dict = match_dict(&mut expression)?;
@ -41,7 +41,7 @@ pub(super) fn remove_unused_keyword_arguments_from_format_call(
locator: &Locator,
stylist: &Stylist,
) -> Result<Edit> {
let source_code = locator.slice(call.range());
let source_code = locator.slice(call);
transform_expression(source_code, stylist, |mut expression| {
let call = match_call_mut(&mut expression)?;
@ -69,7 +69,7 @@ pub(crate) fn remove_unused_positional_arguments_from_format_call(
locator: &Locator,
stylist: &Stylist,
) -> Result<Edit> {
let source_code = locator.slice(call.range());
let source_code = locator.slice(call);
transform_expression(source_code, stylist, |mut expression| {
let call = match_call_mut(&mut expression)?;

View file

@ -53,7 +53,7 @@ fn find_useless_f_strings<'a>(
locator: &'a Locator,
source_type: PySourceType,
) -> impl Iterator<Item = (TextRange, TextRange)> + 'a {
let contents = locator.slice(expr.range());
let contents = locator.slice(expr);
lexer::lex_starts_at(contents, source_type.as_mode(), expr.start())
.flatten()
.filter_map(|(tok, range)| match tok {

View file

@ -135,7 +135,7 @@ pub(crate) fn repeated_keys(checker: &mut Checker, keys: &[Option<Expr>], values
if checker.enabled(Rule::MultiValueRepeatedKeyLiteral) {
let mut diagnostic = Diagnostic::new(
MultiValueRepeatedKeyLiteral {
name: checker.locator().slice(key.range()).to_string(),
name: checker.locator().slice(key).to_string(),
},
key.range(),
);
@ -154,7 +154,7 @@ pub(crate) fn repeated_keys(checker: &mut Checker, keys: &[Option<Expr>], values
if checker.enabled(Rule::MultiValueRepeatedKeyVariable) {
let mut diagnostic = Diagnostic::new(
MultiValueRepeatedKeyVariable {
name: checker.locator().slice(key.range()).to_string(),
name: checker.locator().slice(key).to_string(),
},
key.range(),
);

View file

@ -94,12 +94,8 @@ pub(crate) fn call(checker: &mut Checker, string: &str, range: TextRange) {
pub(crate) fn percent(checker: &mut Checker, expr: &Expr) {
// Grab each string segment (in case there's an implicit concatenation).
let mut strings: Vec<TextRange> = vec![];
for (tok, range) in lexer::lex_starts_at(
checker.locator().slice(expr.range()),
Mode::Module,
expr.start(),
)
.flatten()
for (tok, range) in
lexer::lex_starts_at(checker.locator().slice(expr), Mode::Module, expr.start()).flatten()
{
if tok.is_string() {
strings.push(range);

View file

@ -211,7 +211,7 @@ fn is_valid_dict(
/// PLE1307
pub(crate) fn bad_string_format_type(checker: &mut Checker, expr: &Expr, right: &Expr) {
// Grab each string segment (in case there's an implicit concatenation).
let content = checker.locator().slice(expr.range());
let content = checker.locator().slice(expr);
let mut strings: Vec<TextRange> = vec![];
for (tok, range) in
lexer::lex_starts_at(content, checker.source_type.as_mode(), expr.start()).flatten()

View file

@ -187,10 +187,10 @@ fn merged_membership_test(
BoolOp::Or => "in",
BoolOp::And => "not in",
};
let left = locator.slice(left.range());
let left = locator.slice(left);
let members = comparators
.iter()
.map(|comparator| locator.slice(comparator.range()))
.map(|comparator| locator.slice(comparator))
.join(", ");
format!("{left} {op} ({members})",)
}

View file

@ -45,7 +45,7 @@ where
{
let mut diagnostic = Diagnostic::new(DeprecatedCElementTree, node.range());
if checker.patch(diagnostic.kind.rule()) {
let contents = checker.locator().slice(node.range());
let contents = checker.locator().slice(node);
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
contents.replacen("cElementTree", "ElementTree", 1),
node.range(),

View file

@ -150,7 +150,7 @@ fn format_import(
locator: &Locator,
stylist: &Stylist,
) -> Result<String> {
let module_text = locator.slice(stmt.range());
let module_text = locator.slice(stmt);
let mut tree = match_statement(module_text)?;
let import = match_import(&mut tree)?;
@ -177,7 +177,7 @@ fn format_import_from(
locator: &Locator,
stylist: &Stylist,
) -> Result<String> {
let module_text = locator.slice(stmt.range());
let module_text = locator.slice(stmt);
let mut tree = match_statement(module_text).unwrap();
let import = match_import_from(&mut tree)?;

View file

@ -74,7 +74,7 @@ impl<'a> FormatSummaryValues<'a> {
for arg in &call.arguments.args {
if matches!(arg, Expr::Starred(..))
|| contains_quotes(locator.slice(arg.range()))
|| contains_quotes(locator.slice(arg))
|| locator.contains_line_break(arg.range())
{
return None;
@ -90,9 +90,7 @@ impl<'a> FormatSummaryValues<'a> {
let Some(key) = arg else {
return None;
};
if contains_quotes(locator.slice(value.range()))
|| locator.contains_line_break(value.range())
{
if contains_quotes(locator.slice(value)) || locator.contains_line_break(value.range()) {
return None;
}
extracted_kwargs.insert(key, value);
@ -142,7 +140,7 @@ enum FormatContext {
/// Given an [`Expr`], format it for use in a formatted expression within an f-string.
fn formatted_expr<'a>(expr: &Expr, context: FormatContext, locator: &Locator<'a>) -> Cow<'a, str> {
let text = locator.slice(expr.range());
let text = locator.slice(expr);
let parenthesize = match (context, expr) {
// E.g., `x + y` should be parenthesized in `f"{(x + y)[0]}"`.
(
@ -373,7 +371,7 @@ pub(crate) fn f_strings(
return;
}
let mut contents = String::with_capacity(checker.locator().slice(call.range()).len());
let mut contents = String::with_capacity(checker.locator().slice(call).len());
let mut prev_end = call.start();
for (range, fstring) in patches {
contents.push_str(

View file

@ -206,7 +206,7 @@ fn generate_call(
locator: &Locator,
stylist: &Stylist,
) -> Result<String> {
let source_code = locator.slice(call.range());
let source_code = locator.slice(call);
let output = transform_expression_text(source_code, |source_code| {
let mut expression = match_expression(&source_code)?;

View file

@ -211,7 +211,7 @@ pub(crate) fn native_literals(
return;
}
let arg_code = checker.locator().slice(arg.range());
let arg_code = checker.locator().slice(arg);
// Attribute access on an integer requires the integer to be parenthesized to disambiguate from a float
// Ex) `(7).denominator` is valid but `7.denominator` is not

View file

@ -163,7 +163,7 @@ fn percent_to_format(format_string: &CFormatString) -> String {
/// If a tuple has one argument, remove the comma; otherwise, return it as-is.
fn clean_params_tuple(checker: &mut Checker, right: &Expr, locator: &Locator) -> String {
let mut contents = checker.locator().slice(right.range()).to_string();
let mut contents = checker.locator().slice(right).to_string();
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &right {
if elts.len() == 1 {
if !locator.contains_line_break(right.range()) {
@ -224,7 +224,7 @@ fn clean_params_dictionary(
}
}
let value_string = checker.locator().slice(value.range());
let value_string = checker.locator().slice(value);
arguments.push(format!("{key_string}={value_string}"));
} else {
// If there are any non-string keys, abort.
@ -232,7 +232,7 @@ fn clean_params_dictionary(
}
}
None => {
let value_string = checker.locator().slice(value.range());
let value_string = checker.locator().slice(value);
arguments.push(format!("**{value_string}"));
}
}
@ -343,7 +343,7 @@ pub(crate) fn printf_string_formatting(
let mut strings: Vec<TextRange> = vec![];
let mut extension = None;
for (tok, range) in lexer::lex_starts_at(
checker.locator().slice(expr.range()),
checker.locator().slice(expr),
checker.source_type.as_mode(),
expr.start(),
)
@ -404,16 +404,16 @@ pub(crate) fn printf_string_formatting(
// Parse the parameters.
let params_string = match right {
Expr::Constant(_) | Expr::FString(_) => {
format!("({})", checker.locator().slice(right.range()))
format!("({})", checker.locator().slice(right))
}
Expr::Name(_) | Expr::Attribute(_) | Expr::Subscript(_) | Expr::Call(_) => {
if num_keyword_arguments > 0 {
// If we have _any_ named fields, assume the right-hand side is a mapping.
format!("(**{})", checker.locator().slice(right.range()))
format!("(**{})", checker.locator().slice(right))
} else if num_positional_arguments > 1 {
// If we have multiple fields, but no named fields, assume the right-hand side is a
// tuple.
format!("(*{})", checker.locator().slice(right.range()))
format!("(*{})", checker.locator().slice(right))
} else {
// Otherwise, if we have a single field, we can't make any assumptions about the
// right-hand side. It _could_ be a tuple, but it could also be a single value,

View file

@ -204,7 +204,7 @@ fn create_remove_param_fix<T: Ranged>(
mode_param: &Expr,
source_type: PySourceType,
) -> Result<Edit> {
let content = locator.slice(expr.range());
let content = locator.slice(expr);
// Find the last comma before mode_param and create a deletion fix
// starting from the comma and ending after mode_param.
let mut fix_start: Option<TextSize> = None;

View file

@ -125,7 +125,7 @@ fn replace_with_bytes_literal(
source_type: PySourceType,
) -> Fix {
// Build up a replacement string by prefixing all string tokens with `b`.
let contents = locator.slice(call.range());
let contents = locator.slice(call);
let mut replacement = String::with_capacity(contents.len() + 1);
let mut prev = call.start();
for (tok, range) in

View file

@ -68,7 +68,7 @@ pub(crate) fn unpacked_list_comprehension(checker: &mut Checker, targets: &[Expr
let mut diagnostic = Diagnostic::new(UnpackedListComprehension, value.range());
if checker.patch(diagnostic.kind.rule()) {
let existing = checker.locator().slice(value.range());
let existing = checker.locator().slice(value);
let mut content = String::with_capacity(existing.len());
content.push('(');

View file

@ -100,7 +100,7 @@ pub(crate) fn use_pep604_annotation(
_ => {
// Single argument.
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
checker.locator().slice(slice.range()).to_string(),
checker.locator().slice(slice).to_string(),
expr.range(),
)));
}
@ -113,7 +113,7 @@ pub(crate) fn use_pep604_annotation(
/// Format the expression as a PEP 604-style optional.
fn optional(expr: &Expr, locator: &Locator) -> String {
format!("{} | None", locator.slice(expr.range()))
format!("{} | None", locator.slice(expr))
}
/// Format the expressions as a PEP 604-style union.
@ -128,7 +128,7 @@ fn union(elts: &[Expr], locator: &Locator) -> String {
if elts.peek().is_none() {
"()".to_string()
} else {
elts.map(|expr| locator.slice(expr.range())).join(" | ")
elts.map(|expr| locator.slice(expr)).join(" | ")
}
}

View file

@ -103,7 +103,7 @@ pub(crate) fn yield_in_for_loop(checker: &mut Checker, stmt_for: &ast::StmtFor)
let mut diagnostic = Diagnostic::new(YieldInForLoop, stmt_for.range());
if checker.patch(diagnostic.kind.rule()) {
let contents = checker.locator().slice(iter.range());
let contents = checker.locator().slice(iter.as_ref());
let contents = format!("yield from {contents}");
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
contents,

View file

@ -139,7 +139,7 @@ fn convert_call_to_conversion_flag(
locator: &Locator,
stylist: &Stylist,
) -> Result<Fix> {
let source_code = locator.slice(expr.range());
let source_code = locator.slice(expr);
transform_expression(source_code, stylist, |mut expression| {
// Replace the formatted call expression at `index` with a conversion flag.
let formatted_string_expression = match_part(index, &mut expression)?;

View file

@ -99,7 +99,7 @@ fn convert_to_reduce(iterable: &Expr, call: &ast::ExprCall, checker: &Checker) -
checker.semantic(),
)?;
let iterable = checker.locator().slice(iterable.range());
let iterable = checker.locator().slice(iterable);
Ok(Fix::suggested_edits(
Edit::range_replacement(

View file

@ -45,7 +45,7 @@ pub(crate) fn static_key_dict_comprehension(checker: &mut Checker, key: &Expr) {
if is_constant(key) {
checker.diagnostics.push(Diagnostic::new(
StaticKeyDictComprehension {
key: checker.locator().slice(key.range()).to_string(),
key: checker.locator().slice(key).to_string(),
},
key.range(),
));

View file

@ -788,12 +788,12 @@ fn format_docstring(string_part: &FormatStringPart, f: &mut PyFormatter) -> Form
let locator = f.context().locator();
// Black doesn't change the indentation of docstrings that contain an escaped newline
if locator.slice(string_part.range()).contains("\\\n") {
if locator.slice(string_part).contains("\\\n") {
return string_part.fmt(f);
}
let (normalized, _) = normalize_string(
locator.slice(string_part.range()),
locator.slice(string_part),
string_part.preferred_quotes,
string_part.is_raw_string,
);

View file

@ -2,7 +2,7 @@ use std::cmp::Ordering;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use ruff_text_size::{TextRange, TextSize};
use ruff_text_size::{Ranged, TextRange, TextSize};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@ -56,8 +56,8 @@ impl<'src, 'index> SourceCode<'src, 'index> {
}
/// Take the source code between the given [`TextRange`].
pub fn slice(&self, range: TextRange) -> &'src str {
&self.text[range]
pub fn slice<T: Ranged>(&self, ranged: T) -> &'src str {
&self.text[ranged.range()]
}
pub fn line_start(&self, line: OneIndexed) -> TextSize {

View file

@ -4,7 +4,7 @@ use std::ops::Add;
use memchr::{memchr2, memrchr2};
use once_cell::unsync::OnceCell;
use ruff_text_size::{TextLen, TextRange, TextSize};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::newlines::find_newline;
use crate::{LineIndex, OneIndexed, SourceCode, SourceLocation};
@ -390,8 +390,8 @@ impl<'a> Locator<'a> {
/// Take the source code between the given [`TextRange`].
#[inline]
pub fn slice(&self, range: TextRange) -> &'a str {
&self.contents[range]
pub fn slice<T: Ranged>(&self, ranged: T) -> &'a str {
&self.contents[ranged.range()]
}
/// Return the underlying source code.