From db1c5565083fe16b3e2c8892a39412e464b320a1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 17 Aug 2023 11:22:39 -0400 Subject: [PATCH] Implement `Ranged` on more structs (#6639) ## Summary I noticed some inconsistencies around uses of `.range.start()`, structs that have a `TextRange` field but don't implement `Ranged`, etc. ## Test Plan `cargo test` --- .../ruff/src/checkers/ast/analyze/bindings.rs | 3 +- .../checkers/ast/analyze/deferred_scopes.rs | 11 ++--- crates/ruff/src/checkers/ast/mod.rs | 2 +- crates/ruff/src/checkers/logical_lines.rs | 6 +-- crates/ruff/src/docstrings/mod.rs | 32 +++++---------- crates/ruff/src/docstrings/sections.rs | 7 ++++ crates/ruff/src/importer/mod.rs | 2 +- crates/ruff/src/renamer.rs | 9 ++-- .../rules/unused_loop_control_variable.rs | 2 +- .../rules/unconventional_import_alias.rs | 3 +- .../unaliased_collections_abc_set_import.rs | 3 +- .../rules/unused_private_type_definition.rs | 10 ++--- .../src/rules/flake8_return/rules/function.rs | 2 +- .../src/rules/flake8_simplify/rules/ast_if.rs | 4 +- .../runtime_import_in_type_checking_block.rs | 13 ++++-- .../rules/typing_only_runtime_import.rs | 13 ++++-- .../rules/unused_arguments.rs | 4 +- crates/ruff/src/rules/isort/comments.rs | 15 +++---- .../perflint/rules/incorrect_dict_iterator.rs | 2 +- .../rules/invalid_escape_sequence.rs | 2 +- .../logical_lines/extraneous_whitespace.rs | 1 + .../rules/logical_lines/missing_whitespace.rs | 4 +- .../missing_whitespace_after_keyword.rs | 1 + .../missing_whitespace_around_operator.rs | 1 + .../pycodestyle/rules/logical_lines/mod.rs | 18 ++------ .../logical_lines/space_around_operator.rs | 4 +- .../whitespace_around_keywords.rs | 4 +- ...hitespace_around_named_parameter_equals.rs | 4 +- .../whitespace_before_comment.rs | 4 +- .../whitespace_before_parameters.rs | 4 +- .../src/rules/pydocstyle/rules/backslashes.rs | 1 + .../pydocstyle/rules/blank_after_summary.rs | 1 + .../pydocstyle/rules/ends_with_period.rs | 1 + .../pydocstyle/rules/ends_with_punctuation.rs | 1 + .../ruff/src/rules/pydocstyle/rules/indent.rs | 4 +- .../rules/pydocstyle/rules/no_signature.rs | 1 + .../rules/no_surrounding_whitespace.rs | 4 +- .../pydocstyle/rules/non_imperative_mood.rs | 1 + .../src/rules/pydocstyle/rules/not_empty.rs | 1 + .../src/rules/pydocstyle/rules/one_liner.rs | 1 + .../src/rules/pydocstyle/rules/sections.rs | 10 ++--- .../pydocstyle/rules/starts_with_this.rs | 1 + .../rules/pydocstyle/rules/triple_quotes.rs | 1 + crates/ruff/src/rules/pyflakes/fixes.rs | 10 ++--- .../rules/pyflakes/rules/undefined_local.rs | 1 + .../rules/pyflakes/rules/unused_annotation.rs | 3 +- .../src/rules/pyflakes/rules/unused_import.rs | 11 ++++- .../rules/pyflakes/rules/unused_variable.rs | 2 +- .../rules/pylint/rules/invalid_all_format.rs | 3 +- .../rules/pylint/rules/invalid_all_object.rs | 3 +- .../pyupgrade/rules/outdated_version_block.rs | 8 ++-- crates/ruff_python_ast/src/stmt_if.rs | 6 +++ .../src/comments/format.rs | 2 +- .../src/comments/placement.rs | 21 ++++------ .../src/expression/expr_slice.rs | 41 +++++++++++-------- .../src/expression/expr_unary_op.rs | 2 +- .../src/expression/string.rs | 20 +++++---- .../src/other/comprehension.rs | 2 +- .../src/other/match_case.rs | 2 +- .../src/other/parameters.rs | 2 +- .../src/type_param/type_params.rs | 4 +- crates/ruff_python_parser/src/function.rs | 2 +- crates/ruff_python_parser/src/string.rs | 5 +-- crates/ruff_python_semantic/src/binding.rs | 6 +++ crates/ruff_python_semantic/src/reference.rs | 13 +++--- crates/ruff_shrinking/src/main.rs | 6 +-- 66 files changed, 219 insertions(+), 174 deletions(-) diff --git a/crates/ruff/src/checkers/ast/analyze/bindings.rs b/crates/ruff/src/checkers/ast/analyze/bindings.rs index 7a474640a7e32..face2218220c7 100644 --- a/crates/ruff/src/checkers/ast/analyze/bindings.rs +++ b/crates/ruff/src/checkers/ast/analyze/bindings.rs @@ -1,4 +1,5 @@ use ruff_diagnostics::{Diagnostic, Fix}; +use ruff_python_ast::Ranged; use crate::checkers::ast::Checker; use crate::codes::Rule; @@ -29,7 +30,7 @@ pub(crate) fn bindings(checker: &mut Checker) { pyflakes::rules::UnusedVariable { name: binding.name(checker.locator).to_string(), }, - binding.range, + binding.range(), ); if checker.patch(Rule::UnusedVariable) { diagnostic.try_set_fix(|| { diff --git a/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs b/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs index 779b8d3ffe31c..2dc19c2cb2ad6 100644 --- a/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs +++ b/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs @@ -1,4 +1,5 @@ use ruff_diagnostics::Diagnostic; +use ruff_python_ast::Ranged; use ruff_python_semantic::analyze::{branch_detection, visibility}; use ruff_python_semantic::{Binding, BindingKind, ScopeKind}; @@ -81,7 +82,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) { pylint::rules::GlobalVariableNotAssigned { name: (*name).to_string(), }, - binding.range, + binding.range(), )); } } @@ -122,14 +123,14 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) { } #[allow(deprecated)] - let line = checker.locator.compute_line_index(shadowed.range.start()); + let line = checker.locator.compute_line_index(shadowed.start()); checker.diagnostics.push(Diagnostic::new( pyflakes::rules::ImportShadowedByLoopVar { name: name.to_string(), line, }, - binding.range, + binding.range(), )); } } @@ -218,13 +219,13 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) { } #[allow(deprecated)] - let line = checker.locator.compute_line_index(shadowed.range.start()); + let line = checker.locator.compute_line_index(shadowed.start()); let mut diagnostic = Diagnostic::new( pyflakes::rules::RedefinedWhileUnused { name: (*name).to_string(), line, }, - binding.range, + binding.range(), ); if let Some(range) = binding.parent_range(&checker.semantic) { diagnostic.set_parent(range.start()); diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index fce7af9fbe710..4cb93819cbd8e 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -1855,7 +1855,7 @@ impl<'a> Checker<'a> { .map(|binding_id| &self.semantic.bindings[binding_id]) .filter_map(|binding| match &binding.kind { BindingKind::Export(Export { names }) => { - Some(names.iter().map(|name| (*name, binding.range))) + Some(names.iter().map(|name| (*name, binding.range()))) } _ => None, }) diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 95cad2f647015..b02514ab65364 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -1,10 +1,10 @@ -use ruff_python_parser::lexer::LexResult; -use ruff_text_size::TextRange; - use ruff_diagnostics::{Diagnostic, DiagnosticKind}; +use ruff_python_ast::Ranged; use ruff_python_codegen::Stylist; +use ruff_python_parser::lexer::LexResult; use ruff_python_parser::TokenKind; use ruff_source_file::Locator; +use ruff_text_size::TextRange; use crate::registry::{AsRule, Rule}; use crate::rules::pycodestyle::rules::logical_lines::{ diff --git a/crates/ruff/src/docstrings/mod.rs b/crates/ruff/src/docstrings/mod.rs index 46db0dcf35b41..92726c8d97aa0 100644 --- a/crates/ruff/src/docstrings/mod.rs +++ b/crates/ruff/src/docstrings/mod.rs @@ -2,9 +2,8 @@ use std::fmt::{Debug, Formatter}; use std::ops::Deref; use ruff_python_ast::{Expr, Ranged}; -use ruff_text_size::{TextRange, TextSize}; - use ruff_python_semantic::Definition; +use ruff_text_size::TextRange; pub(crate) mod extraction; pub(crate) mod google; @@ -28,21 +27,15 @@ impl<'a> Docstring<'a> { DocstringBody { docstring: self } } - pub(crate) fn start(&self) -> TextSize { - self.expr.start() - } - - pub(crate) fn end(&self) -> TextSize { - self.expr.end() + pub(crate) fn leading_quote(&self) -> &'a str { + &self.contents[TextRange::up_to(self.body_range.start())] } +} - pub(crate) fn range(&self) -> TextRange { +impl Ranged for Docstring<'_> { + fn range(&self) -> TextRange { self.expr.range() } - - pub(crate) fn leading_quote(&self) -> &'a str { - &self.contents[TextRange::up_to(self.body_range.start())] - } } #[derive(Copy, Clone)] @@ -51,18 +44,15 @@ pub(crate) struct DocstringBody<'a> { } impl<'a> DocstringBody<'a> { - #[inline] - pub(crate) fn start(self) -> TextSize { - self.range().start() + pub(crate) fn as_str(self) -> &'a str { + &self.docstring.contents[self.docstring.body_range] } +} - pub(crate) fn range(self) -> TextRange { +impl Ranged for DocstringBody<'_> { + fn range(&self) -> TextRange { self.docstring.body_range + self.docstring.start() } - - pub(crate) fn as_str(self) -> &'a str { - &self.docstring.contents[self.docstring.body_range] - } } impl Deref for DocstringBody<'_> { diff --git a/crates/ruff/src/docstrings/sections.rs b/crates/ruff/src/docstrings/sections.rs index 5a3ea88642531..58d8339e101c1 100644 --- a/crates/ruff/src/docstrings/sections.rs +++ b/crates/ruff/src/docstrings/sections.rs @@ -2,6 +2,7 @@ use std::fmt::{Debug, Formatter}; use std::iter::FusedIterator; use ruff_python_ast::docstrings::{leading_space, leading_words}; +use ruff_python_ast::Ranged; use ruff_text_size::{TextLen, TextRange, TextSize}; use strum_macros::EnumIter; @@ -366,6 +367,12 @@ impl<'a> SectionContext<'a> { } } +impl Ranged for SectionContext<'_> { + fn range(&self) -> TextRange { + self.range() + } +} + impl Debug for SectionContext<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("SectionContext") diff --git a/crates/ruff/src/importer/mod.rs b/crates/ruff/src/importer/mod.rs index 0fcdff9b55c5b..08c0f25e935c0 100644 --- a/crates/ruff/src/importer/mod.rs +++ b/crates/ruff/src/importer/mod.rs @@ -194,7 +194,7 @@ impl<'a> Importer<'a> { // import and the current location, and thus the symbol would not be available). It's also // unclear whether should add an import statement at the start of the file, since it could // be shadowed between the import and the current location. - if imported_name.range().start() > at { + if imported_name.start() > at { return Some(Err(ResolutionError::ImportAfterUsage)); } diff --git a/crates/ruff/src/renamer.rs b/crates/ruff/src/renamer.rs index d3f3e6fc925a2..2671cd63fe466 100644 --- a/crates/ruff/src/renamer.rs +++ b/crates/ruff/src/renamer.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, Result}; use itertools::Itertools; use ruff_diagnostics::Edit; +use ruff_python_ast::Ranged; use ruff_python_semantic::{Binding, BindingKind, Scope, ScopeId, SemanticModel}; pub(crate) struct Renamer; @@ -220,12 +221,12 @@ impl Renamer { BindingKind::Import(_) | BindingKind::FromImport(_) => { if binding.is_alias() { // Ex) Rename `import pandas as alias` to `import pandas as pd`. - Some(Edit::range_replacement(target.to_string(), binding.range)) + Some(Edit::range_replacement(target.to_string(), binding.range())) } else { // Ex) Rename `import pandas` to `import pandas as pd`. Some(Edit::range_replacement( format!("{name} as {target}"), - binding.range, + binding.range(), )) } } @@ -234,7 +235,7 @@ impl Renamer { let module_name = import.call_path.first().unwrap(); Some(Edit::range_replacement( format!("{module_name} as {target}"), - binding.range, + binding.range(), )) } // Avoid renaming builtins and other "special" bindings. @@ -254,7 +255,7 @@ impl Renamer { | BindingKind::FunctionDefinition(_) | BindingKind::Deletion | BindingKind::UnboundException(_) => { - Some(Edit::range_replacement(target.to_string(), binding.range)) + Some(Edit::range_replacement(target.to_string(), binding.range())) } } } diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs b/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs index 8ab410ecd4df6..295a9c18e4e99 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs @@ -163,7 +163,7 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, if scope .get_all(name) .map(|binding_id| checker.semantic().binding(binding_id)) - .filter(|binding| binding.range.start() >= expr.range().start()) + .filter(|binding| binding.start() >= expr.start()) .all(|binding| !binding.is_used()) { diagnostic.set_fix(Fix::suggested(Edit::range_replacement( diff --git a/crates/ruff/src/rules/flake8_import_conventions/rules/unconventional_import_alias.rs b/crates/ruff/src/rules/flake8_import_conventions/rules/unconventional_import_alias.rs index 6a009f3834ad0..3c6da9ea42cae 100644 --- a/crates/ruff/src/rules/flake8_import_conventions/rules/unconventional_import_alias.rs +++ b/crates/ruff/src/rules/flake8_import_conventions/rules/unconventional_import_alias.rs @@ -2,6 +2,7 @@ use rustc_hash::FxHashMap; use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::{Binding, Imported}; use crate::checkers::ast::Checker; @@ -76,7 +77,7 @@ pub(crate) fn unconventional_import_alias( name: qualified_name, asname: expected_alias.to_string(), }, - binding.range, + binding.range(), ); if checker.patch(diagnostic.kind.rule()) { if checker.semantic().is_available(expected_alias) { diff --git a/crates/ruff/src/rules/flake8_pyi/rules/unaliased_collections_abc_set_import.rs b/crates/ruff/src/rules/flake8_pyi/rules/unaliased_collections_abc_set_import.rs index 90f6481255e33..a272e18385ab6 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/unaliased_collections_abc_set_import.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/unaliased_collections_abc_set_import.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::Imported; use ruff_python_semantic::{Binding, BindingKind}; @@ -63,7 +64,7 @@ pub(crate) fn unaliased_collections_abc_set_import( return None; } - let mut diagnostic = Diagnostic::new(UnaliasedCollectionsAbcSetImport, binding.range); + let mut diagnostic = Diagnostic::new(UnaliasedCollectionsAbcSetImport, binding.range()); if checker.patch(diagnostic.kind.rule()) { if checker.semantic().is_available("AbstractSet") { diagnostic.try_set_fix(|| { diff --git a/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs b/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs index 481aa886716f7..3a306d064923e 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr, Stmt}; +use ruff_python_ast::{self as ast, Expr, Ranged, Stmt}; use ruff_python_semantic::Scope; use crate::checkers::ast::Checker; @@ -192,7 +192,7 @@ pub(crate) fn unused_private_type_var( UnusedPrivateTypeVar { name: id.to_string(), }, - binding.range, + binding.range(), )); } } @@ -234,7 +234,7 @@ pub(crate) fn unused_private_protocol( UnusedPrivateProtocol { name: class_def.name.to_string(), }, - binding.range, + binding.range(), )); } } @@ -280,7 +280,7 @@ pub(crate) fn unused_private_type_alias( UnusedPrivateTypeAlias { name: id.to_string(), }, - binding.range, + binding.range(), )); } } @@ -321,7 +321,7 @@ pub(crate) fn unused_private_typed_dict( UnusedPrivateTypedDict { name: class_def.name.to_string(), }, - binding.range, + binding.range(), )); } } diff --git a/crates/ruff/src/rules/flake8_return/rules/function.rs b/crates/ruff/src/rules/flake8_return/rules/function.rs index cb470bde8711d..5d604c6e4a60e 100644 --- a/crates/ruff/src/rules/flake8_return/rules/function.rs +++ b/crates/ruff/src/rules/flake8_return/rules/function.rs @@ -558,7 +558,7 @@ fn unnecessary_assign(checker: &mut Checker, stack: &Stack) { // Replace from the start of the assignment statement to the end of the equals // sign. TextRange::new( - assign.range().start(), + assign.start(), assign .range() .start() diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs index be12732220d26..7d463baac2714 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs @@ -693,7 +693,7 @@ pub(crate) fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt) { fn body_range(branch: &IfElifBranch, locator: &Locator) -> TextRange { TextRange::new( locator.line_end(branch.test.end()), - locator.line_end(branch.range.end()), + locator.line_end(branch.end()), ) } @@ -731,7 +731,7 @@ pub(crate) fn if_with_same_arms(checker: &mut Checker, locator: &Locator, stmt_i checker.diagnostics.push(Diagnostic::new( IfWithSameArms, - TextRange::new(current_branch.range.start(), following_branch.range.end()), + TextRange::new(current_branch.start(), following_branch.end()), )); } } diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs b/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs index f26f4fe929f9c..0dd50ab22ee49 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs @@ -5,6 +5,7 @@ use rustc_hash::FxHashMap; use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::{AnyImport, Imported, ResolvedReferenceId, Scope, StatementId}; use ruff_text_size::TextRange; @@ -101,11 +102,11 @@ pub(crate) fn runtime_import_in_type_checking_block( let import = ImportBinding { import, reference_id, - range: binding.range, + range: binding.range(), parent_range: binding.parent_range(checker.semantic()), }; - if checker.rule_is_ignored(Rule::RuntimeImportInTypeCheckingBlock, import.range.start()) + if checker.rule_is_ignored(Rule::RuntimeImportInTypeCheckingBlock, import.start()) || import.parent_range.is_some_and(|parent_range| { checker.rule_is_ignored( Rule::RuntimeImportInTypeCheckingBlock, @@ -192,6 +193,12 @@ struct ImportBinding<'a> { parent_range: Option, } +impl Ranged for ImportBinding<'_> { + fn range(&self) -> TextRange { + self.range + } +} + /// Generate a [`Fix`] to remove runtime imports from a type-checking block. fn fix_imports( checker: &Checker, @@ -211,7 +218,7 @@ fn fix_imports( let at = imports .iter() .map(|ImportBinding { reference_id, .. }| { - checker.semantic().reference(*reference_id).range().start() + checker.semantic().reference(*reference_id).start() }) .min() .expect("Expected at least one import"); diff --git a/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index 3d9d96843132e..f9fc0a42a7c29 100644 --- a/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -5,6 +5,7 @@ use rustc_hash::FxHashMap; use ruff_diagnostics::{AutofixKind, Diagnostic, DiagnosticKind, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::{AnyImport, Binding, Imported, ResolvedReferenceId, Scope, StatementId}; use ruff_text_size::TextRange; @@ -308,11 +309,11 @@ pub(crate) fn typing_only_runtime_import( let import = ImportBinding { import, reference_id, - range: binding.range, + range: binding.range(), parent_range: binding.parent_range(checker.semantic()), }; - if checker.rule_is_ignored(rule_for(import_type), import.range.start()) + if checker.rule_is_ignored(rule_for(import_type), import.start()) || import.parent_range.is_some_and(|parent_range| { checker.rule_is_ignored(rule_for(import_type), parent_range.start()) }) @@ -390,6 +391,12 @@ struct ImportBinding<'a> { parent_range: Option, } +impl Ranged for ImportBinding<'_> { + fn range(&self) -> TextRange { + self.range + } +} + /// Return the [`Rule`] for the given import type. fn rule_for(import_type: ImportType) -> Rule { match import_type { @@ -456,7 +463,7 @@ fn fix_imports( let at = imports .iter() .map(|ImportBinding { reference_id, .. }| { - checker.semantic().reference(*reference_id).range().start() + checker.semantic().reference(*reference_id).start() }) .min() .expect("Expected at least one import"); diff --git a/crates/ruff/src/rules/flake8_unused_arguments/rules/unused_arguments.rs b/crates/ruff/src/rules/flake8_unused_arguments/rules/unused_arguments.rs index 60be99a590d84..f5801839825de 100644 --- a/crates/ruff/src/rules/flake8_unused_arguments/rules/unused_arguments.rs +++ b/crates/ruff/src/rules/flake8_unused_arguments/rules/unused_arguments.rs @@ -2,7 +2,7 @@ use std::iter; use regex::Regex; use ruff_python_ast as ast; -use ruff_python_ast::{Parameter, Parameters}; +use ruff_python_ast::{Parameter, Parameters, Ranged}; use ruff_diagnostics::DiagnosticKind; use ruff_diagnostics::{Diagnostic, Violation}; @@ -303,7 +303,7 @@ fn call<'a>( { Some(Diagnostic::new( argumentable.check_for(arg.name.to_string()), - binding.range, + binding.range(), )) } else { None diff --git a/crates/ruff/src/rules/isort/comments.rs b/crates/ruff/src/rules/isort/comments.rs index e2c05fccc3847..1bfe1cacee5c0 100644 --- a/crates/ruff/src/rules/isort/comments.rs +++ b/crates/ruff/src/rules/isort/comments.rs @@ -1,10 +1,9 @@ use std::borrow::Cow; -use ruff_python_ast::PySourceType; +use ruff_python_ast::{PySourceType, Ranged}; use ruff_python_parser::{lexer, AsMode, Tok}; -use ruff_text_size::{TextRange, TextSize}; - use ruff_source_file::Locator; +use ruff_text_size::TextRange; #[derive(Debug)] pub(crate) struct Comment<'a> { @@ -12,13 +11,9 @@ pub(crate) struct Comment<'a> { pub(crate) range: TextRange, } -impl Comment<'_> { - pub(crate) const fn start(&self) -> TextSize { - self.range.start() - } - - pub(crate) const fn end(&self) -> TextSize { - self.range.end() +impl Ranged for Comment<'_> { + fn range(&self) -> TextRange { + self.range } } diff --git a/crates/ruff/src/rules/perflint/rules/incorrect_dict_iterator.rs b/crates/ruff/src/rules/perflint/rules/incorrect_dict_iterator.rs index 0419d1790b05d..8dd641694a2ba 100644 --- a/crates/ruff/src/rules/perflint/rules/incorrect_dict_iterator.rs +++ b/crates/ruff/src/rules/perflint/rules/incorrect_dict_iterator.rs @@ -173,7 +173,7 @@ fn is_unused(expr: &Expr, semantic: &SemanticModel) -> bool { scope .get_all(id) .map(|binding_id| semantic.binding(binding_id)) - .filter(|binding| binding.range.start() >= expr.range().start()) + .filter(|binding| binding.start() >= expr.start()) .all(|binding| !binding.is_used()) } _ => false, diff --git a/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs b/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs index 0a8898b172702..2cea1ad2f15d9 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs @@ -129,7 +129,7 @@ pub(crate) fn invalid_escape_sequence( for diagnostic in &mut invalid_escape_sequence { diagnostic.set_fix(Fix::automatic(Edit::insertion( r"\".to_string(), - diagnostic.range().start() + TextSize::from(1), + diagnostic.start() + TextSize::from(1), ))); } } else { diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs index 58a7446e72048..94bbd34e2f4b8 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs @@ -3,6 +3,7 @@ use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Edit; use ruff_diagnostics::Fix; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; use ruff_text_size::TextRange; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs index 7cd363ac44a82..05129879c2035 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace.rs @@ -1,9 +1,9 @@ -use ruff_text_size::TextSize; - use ruff_diagnostics::Edit; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; +use ruff_text_size::TextSize; use crate::checkers::logical_lines::LogicalLinesContext; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs index 0fac3492a6014..8d72744bebfca 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_after_keyword.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; use crate::checkers::logical_lines::LogicalLinesContext; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_around_operator.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_around_operator.rs index a32a4e4bd90e3..ea1764daf0ba2 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_around_operator.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/missing_whitespace_around_operator.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{DiagnosticKind, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; use crate::checkers::logical_lines::LogicalLinesContext; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index e20fad75aee10..60fbb03998271 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -13,6 +13,7 @@ use std::fmt::{Debug, Formatter}; use std::iter::FusedIterator; use bitflags::bitflags; +use ruff_python_ast::Ranged; use ruff_python_parser::lexer::LexResult; use ruff_text_size::{TextLen, TextRange, TextSize}; @@ -310,22 +311,11 @@ impl LogicalLineToken { pub(crate) const fn kind(&self) -> TokenKind { self.kind } +} - /// Returns the token's start location - #[inline] - pub(crate) const fn start(&self) -> TextSize { - self.range.start() - } - - /// Returns the token's end location - #[inline] - pub(crate) const fn end(&self) -> TextSize { - self.range.end() - } - +impl Ranged for LogicalLineToken { /// Returns a tuple with the token's `(start, end)` locations - #[inline] - pub(crate) const fn range(&self) -> TextRange { + fn range(&self) -> TextRange { self.range } } diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs index c6c4b7dcdea59..e8347d18c7624 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/space_around_operator.rs @@ -1,8 +1,8 @@ -use ruff_text_size::TextRange; - use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; +use ruff_text_size::TextRange; use crate::checkers::logical_lines::LogicalLinesContext; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs index 5c87d7df30c88..2a2af9a0f1db4 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs @@ -1,7 +1,7 @@ -use ruff_text_size::TextRange; - use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; +use ruff_text_size::TextRange; use crate::checkers::logical_lines::LogicalLinesContext; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs index 1b6a8f14a98e5..ca0f6814e63d0 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs @@ -1,8 +1,8 @@ -use ruff_text_size::{TextRange, TextSize}; - use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; +use ruff_text_size::{TextRange, TextSize}; use crate::checkers::logical_lines::LogicalLinesContext; use crate::rules::pycodestyle::rules::logical_lines::{LogicalLine, LogicalLineToken}; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs index efe20a42f44fe..f6b1a9f4f72a7 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs @@ -1,10 +1,10 @@ -use ruff_text_size::{TextLen, TextRange, TextSize}; - use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; use ruff_python_trivia::PythonWhitespace; use ruff_source_file::Locator; +use ruff_text_size::{TextLen, TextRange, TextSize}; use crate::checkers::logical_lines::LogicalLinesContext; use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs index 1fea887220343..0d3c6fe32f58c 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_parameters.rs @@ -1,8 +1,8 @@ -use ruff_text_size::{TextRange, TextSize}; - use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_parser::TokenKind; +use ruff_text_size::{TextRange, TextSize}; use crate::checkers::logical_lines::LogicalLinesContext; use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; diff --git a/crates/ruff/src/rules/pydocstyle/rules/backslashes.rs b/crates/ruff/src/rules/pydocstyle/rules/backslashes.rs index 88cbdf2b5818d..508d0dd85ce5d 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/backslashes.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/backslashes.rs @@ -2,6 +2,7 @@ use memchr::memchr_iter; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/blank_after_summary.rs b/crates/ruff/src/rules/pydocstyle/rules/blank_after_summary.rs index 32bbb59845472..b4d7f4531566a 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/blank_after_summary.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/blank_after_summary.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pydocstyle/rules/ends_with_period.rs b/crates/ruff/src/rules/pydocstyle/rules/ends_with_period.rs index 0fb03df11a476..7d16b5bcce52e 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/ends_with_period.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/ends_with_period.rs @@ -3,6 +3,7 @@ use strum::IntoEnumIterator; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pydocstyle/rules/ends_with_punctuation.rs b/crates/ruff/src/rules/pydocstyle/rules/ends_with_punctuation.rs index 5649479de27ca..aa06dafc5f87b 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/ends_with_punctuation.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/ends_with_punctuation.rs @@ -3,6 +3,7 @@ use strum::IntoEnumIterator; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_source_file::{UniversalNewlineIterator, UniversalNewlines}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pydocstyle/rules/indent.rs b/crates/ruff/src/rules/pydocstyle/rules/indent.rs index f97bdf88b0473..663ee9cae3fde 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/indent.rs @@ -1,10 +1,10 @@ -use ruff_text_size::{TextLen, TextRange}; - use ruff_diagnostics::{AlwaysAutofixableViolation, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::docstrings::{clean_space, leading_space}; +use ruff_python_ast::Ranged; use ruff_source_file::NewlineWithTrailingNewline; +use ruff_text_size::{TextLen, TextRange}; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/no_signature.rs b/crates/ruff/src/rules/pydocstyle/rules/no_signature.rs index e5a5a9d167de1..5ba744a56b6de 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/no_signature.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/no_signature.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_source_file::UniversalNewlines; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs b/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs index cf01e3fee8351..d2a30fee7119c 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/no_surrounding_whitespace.rs @@ -1,8 +1,8 @@ -use ruff_text_size::{TextLen, TextRange}; - use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_source_file::NewlineWithTrailingNewline; +use ruff_text_size::{TextLen, TextRange}; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs b/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs index 2f2c0b02d10c7..fc61f13a6dc09 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/non_imperative_mood.rs @@ -6,6 +6,7 @@ use once_cell::sync::Lazy; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::{from_qualified_name, CallPath}; +use ruff_python_ast::Ranged; use ruff_python_semantic::analyze::visibility::{is_property, is_test}; use ruff_source_file::UniversalNewlines; diff --git a/crates/ruff/src/rules/pydocstyle/rules/not_empty.rs b/crates/ruff/src/rules/pydocstyle/rules/not_empty.rs index 3c89974b37133..c8b893fe173b8 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/not_empty.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/not_empty.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/one_liner.rs b/crates/ruff/src/rules/pydocstyle/rules/one_liner.rs index 560f3ab0e114e..6610c41754c4e 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/one_liner.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/one_liner.rs @@ -1,6 +1,7 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::str::{leading_quote, trailing_quote}; +use ruff_python_ast::Ranged; use ruff_source_file::NewlineWithTrailingNewline; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pydocstyle/rules/sections.rs b/crates/ruff/src/rules/pydocstyle/rules/sections.rs index da87a98256f73..44da66e7076f9 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/sections.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/sections.rs @@ -8,7 +8,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::docstrings::{clean_space, leading_space}; use ruff_python_ast::identifier::Identifier; -use ruff_python_ast::ParameterWithDefault; +use ruff_python_ast::{ParameterWithDefault, Ranged}; use ruff_python_semantic::analyze::visibility::is_staticmethod; use ruff_python_trivia::{textwrap::dedent, PythonWhitespace}; use ruff_source_file::NewlineWithTrailingNewline; @@ -1640,7 +1640,7 @@ fn common_section( if checker.patch(diagnostic.kind.rule()) { // Replace the existing indentation with whitespace of the appropriate length. let content = clean_space(docstring.indentation); - let fix_range = TextRange::at(context.range().start(), leading_space.text_len()); + let fix_range = TextRange::at(context.start(), leading_space.text_len()); diagnostic.set_fix(Fix::automatic(if content.is_empty() { Edit::range_deletion(fix_range) @@ -1667,7 +1667,7 @@ fn common_section( // Add a newline at the beginning of the next section. diagnostic.set_fix(Fix::automatic(Edit::insertion( line_end.to_string(), - next.range().start(), + next.start(), ))); } checker.diagnostics.push(diagnostic); @@ -1684,7 +1684,7 @@ fn common_section( // Add a newline after the section. diagnostic.set_fix(Fix::automatic(Edit::insertion( format!("{}{}", line_end, docstring.indentation), - context.range().end(), + context.end(), ))); } checker.diagnostics.push(diagnostic); @@ -1704,7 +1704,7 @@ fn common_section( // Add a blank line before the section. diagnostic.set_fix(Fix::automatic(Edit::insertion( line_end.to_string(), - context.range().start(), + context.start(), ))); } checker.diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/pydocstyle/rules/starts_with_this.rs b/crates/ruff/src/rules/pydocstyle/rules/starts_with_this.rs index 4e73aa0ed3937..f5f36da599f2a 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/starts_with_this.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/starts_with_this.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use crate::checkers::ast::Checker; use crate::docstrings::Docstring; diff --git a/crates/ruff/src/rules/pydocstyle/rules/triple_quotes.rs b/crates/ruff/src/rules/pydocstyle/rules/triple_quotes.rs index 1f054c628c0b0..28a8604393059 100644 --- a/crates/ruff/src/rules/pydocstyle/rules/triple_quotes.rs +++ b/crates/ruff/src/rules/pydocstyle/rules/triple_quotes.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_codegen::Quote; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pyflakes/fixes.rs b/crates/ruff/src/rules/pyflakes/fixes.rs index 59d8c1491038f..370541ed6612a 100644 --- a/crates/ruff/src/rules/pyflakes/fixes.rs +++ b/crates/ruff/src/rules/pyflakes/fixes.rs @@ -96,11 +96,9 @@ pub(crate) fn remove_exception_handler_assignment( locator: &Locator, ) -> Result { // Lex backwards, to the token just before the `as`. - let mut tokenizer = SimpleTokenizer::up_to_without_back_comment( - bound_exception.range.start(), - locator.contents(), - ) - .skip_trivia(); + let mut tokenizer = + SimpleTokenizer::up_to_without_back_comment(bound_exception.start(), locator.contents()) + .skip_trivia(); // Eat the `as` token. let preceding = tokenizer @@ -114,7 +112,7 @@ pub(crate) fn remove_exception_handler_assignment( .context("expected the exception name to be preceded by a token")?; // Lex forwards, to the `:` token. - let following = SimpleTokenizer::starts_at(bound_exception.range.end(), locator.contents()) + let following = SimpleTokenizer::starts_at(bound_exception.end(), locator.contents()) .skip_trivia() .next() .context("expected the exception name to be followed by a colon")?; diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs index e4f931a7bc985..7e2d9fb8827e0 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs @@ -2,6 +2,7 @@ use std::string::ToString; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::{Scope, ScopeId}; use crate::checkers::ast::Checker; diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs index b71d048d20d3e..4b7e56c1bf3a4 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::Scope; use crate::checkers::ast::Checker; @@ -44,7 +45,7 @@ pub(crate) fn unused_annotation( && !binding.is_used() && !checker.settings.dummy_variable_rgx.is_match(name) { - Some((name.to_string(), binding.range)) + Some((name.to_string(), binding.range())) } else { None } diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff/src/rules/pyflakes/rules/unused_import.rs index 6f1413d55578b..72e57ee1c4d0b 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_import.rs @@ -5,6 +5,7 @@ use rustc_hash::FxHashMap; use ruff_diagnostics::{AutofixKind, Diagnostic, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::{AnyImport, Exceptions, Imported, Scope, StatementId}; use ruff_text_size::TextRange; @@ -124,11 +125,11 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut let import = ImportBinding { import, - range: binding.range, + range: binding.range(), parent_range: binding.parent_range(checker.semantic()), }; - if checker.rule_is_ignored(Rule::UnusedImport, import.range.start()) + if checker.rule_is_ignored(Rule::UnusedImport, import.start()) || import.parent_range.is_some_and(|parent_range| { checker.rule_is_ignored(Rule::UnusedImport, parent_range.start()) }) @@ -226,6 +227,12 @@ struct ImportBinding<'a> { parent_range: Option, } +impl Ranged for ImportBinding<'_> { + fn range(&self) -> TextRange { + self.range + } +} + /// Generate a [`Fix`] to remove unused imports from a statement. fn fix_imports( checker: &Checker, diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs index 4e723160be15d..53e176730e884 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_variable.rs @@ -320,7 +320,7 @@ pub(crate) fn unused_variable(checker: &Checker, scope: &Scope, diagnostics: &mu | "__debuggerskip__" ) { - return Some((name.to_string(), binding.range, binding.source)); + return Some((name.to_string(), binding.range(), binding.source)); } None diff --git a/crates/ruff/src/rules/pylint/rules/invalid_all_format.rs b/crates/ruff/src/rules/pylint/rules/invalid_all_format.rs index dc0903428bd2f..8af36075dc4a6 100644 --- a/crates/ruff/src/rules/pylint/rules/invalid_all_format.rs +++ b/crates/ruff/src/rules/pylint/rules/invalid_all_format.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::Binding; /// ## What it does @@ -37,7 +38,7 @@ impl Violation for InvalidAllFormat { /// PLE0605 pub(crate) fn invalid_all_format(binding: &Binding) -> Option { if binding.is_invalid_all_format() { - Some(Diagnostic::new(InvalidAllFormat, binding.range)) + Some(Diagnostic::new(InvalidAllFormat, binding.range())) } else { None } diff --git a/crates/ruff/src/rules/pylint/rules/invalid_all_object.rs b/crates/ruff/src/rules/pylint/rules/invalid_all_object.rs index 378302c4e48dc..2a1fdffe434d2 100644 --- a/crates/ruff/src/rules/pylint/rules/invalid_all_object.rs +++ b/crates/ruff/src/rules/pylint/rules/invalid_all_object.rs @@ -1,5 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Ranged; use ruff_python_semantic::Binding; /// ## What it does @@ -37,7 +38,7 @@ impl Violation for InvalidAllObject { /// PLE0604 pub(crate) fn invalid_all_object(binding: &Binding) -> Option { if binding.is_invalid_all_object() { - Some(Diagnostic::new(InvalidAllObject, binding.range)) + Some(Diagnostic::new(InvalidAllObject, binding.range())) } else { None } diff --git a/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs b/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs index 25fecdf62887a..d8c5fdcb8203f 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs @@ -201,10 +201,10 @@ fn fix_py2_block(checker: &Checker, stmt_if: &StmtIf, branch: &IfElifBranch) -> .elif_else_clauses .iter() .map(Ranged::start) - .find(|start| *start > branch.range.start()); + .find(|start| *start > branch.start()); Some(Fix::suggested(Edit::deletion( - branch.range.start(), - next_start.unwrap_or(branch.range.end()), + branch.start(), + next_start.unwrap_or(branch.end()), ))) } } @@ -256,7 +256,7 @@ fn fix_py3_block(checker: &mut Checker, stmt_if: &StmtIf, branch: &IfElifBranch) .slice(TextRange::new(branch.test.end(), end.end())); Some(Fix::suggested(Edit::range_replacement( format!("else{text}"), - TextRange::new(branch.range.start(), stmt_if.end()), + TextRange::new(branch.start(), stmt_if.end()), ))) } } diff --git a/crates/ruff_python_ast/src/stmt_if.rs b/crates/ruff_python_ast/src/stmt_if.rs index 0acc04a40535f..77a0164badcc6 100644 --- a/crates/ruff_python_ast/src/stmt_if.rs +++ b/crates/ruff_python_ast/src/stmt_if.rs @@ -24,6 +24,12 @@ pub struct IfElifBranch<'a> { pub range: TextRange, } +impl Ranged for IfElifBranch<'_> { + fn range(&self) -> TextRange { + self.range + } +} + pub fn if_elif_branches(stmt_if: &StmtIf) -> impl Iterator { iter::once(IfElifBranch { kind: BranchKind::If, diff --git a/crates/ruff_python_formatter/src/comments/format.rs b/crates/ruff_python_formatter/src/comments/format.rs index fdcf4c5d812cb..902521b94b89d 100644 --- a/crates/ruff_python_formatter/src/comments/format.rs +++ b/crates/ruff_python_formatter/src/comments/format.rs @@ -327,7 +327,7 @@ impl Format> for FormatComment<'_> { } let start = slice.start() + start_offset; - let end = slice.range().end() - trailing_whitespace_len; + let end = slice.end() - trailing_whitespace_len; write!( f, diff --git a/crates/ruff_python_formatter/src/comments/placement.rs b/crates/ruff_python_formatter/src/comments/placement.rs index d0d6d71524ebb..df2a0a1cfc2b4 100644 --- a/crates/ruff_python_formatter/src/comments/placement.rs +++ b/crates/ruff_python_formatter/src/comments/placement.rs @@ -445,7 +445,7 @@ fn handle_own_line_comment_between_branches<'a>( // It depends on the indentation level of the comment if it is a leading comment for the // following branch or if it a trailing comment of the previous body's last statement. - let comment_indentation = indentation_at_offset(comment.slice().range().start(), locator) + let comment_indentation = indentation_at_offset(comment.slice().start(), locator) .unwrap_or_default() .len(); @@ -529,7 +529,7 @@ fn handle_own_line_comment_after_branch<'a>( // We only care about the length because indentations with mixed spaces and tabs are only valid if // the indent-level doesn't depend on the tab width (the indent level must be the same if the tab width is 1 or 8). - let comment_indentation = indentation_at_offset(comment.slice().range().start(), locator) + let comment_indentation = indentation_at_offset(comment.slice().start(), locator) .unwrap_or_default() .len(); @@ -1314,7 +1314,7 @@ fn handle_comprehension_comment<'a>( // b in c // ] // ``` - if comment.slice().end() < comprehension.target.range().start() { + if comment.slice().end() < comprehension.target.start() { return if is_own_line { // own line comments are correctly assigned as leading the target CommentPlacement::Default(comment) @@ -1325,10 +1325,7 @@ fn handle_comprehension_comment<'a>( } let in_token = find_only_token_in_range( - TextRange::new( - comprehension.target.range().end(), - comprehension.iter.range().start(), - ), + TextRange::new(comprehension.target.end(), comprehension.iter.start()), SimpleTokenKind::In, locator, ); @@ -1361,7 +1358,7 @@ fn handle_comprehension_comment<'a>( // c // ] // ``` - if comment.slice().start() < comprehension.iter.range().start() { + if comment.slice().start() < comprehension.iter.start() { return if is_own_line { CommentPlacement::Default(comment) } else { @@ -1370,7 +1367,7 @@ fn handle_comprehension_comment<'a>( }; } - let mut last_end = comprehension.iter.range().end(); + let mut last_end = comprehension.iter.end(); for if_node in &comprehension.ifs { // ```python @@ -1391,7 +1388,7 @@ fn handle_comprehension_comment<'a>( // ] // ``` let if_token = find_only_token_in_range( - TextRange::new(last_end, if_node.range().start()), + TextRange::new(last_end, if_node.start()), SimpleTokenKind::If, locator, ); @@ -1400,11 +1397,11 @@ fn handle_comprehension_comment<'a>( return CommentPlacement::dangling(if_node, comment); } } else if if_token.start() < comment.slice().start() - && comment.slice().start() < if_node.range().start() + && comment.slice().start() < if_node.start() { return CommentPlacement::dangling(if_node, comment); } - last_end = if_node.range().end(); + last_end = if_node.end(); } CommentPlacement::Default(comment) diff --git a/crates/ruff_python_formatter/src/expression/expr_slice.rs b/crates/ruff_python_formatter/src/expression/expr_slice.rs index c26cd0508fc2f..1a83c6ebe566f 100644 --- a/crates/ruff_python_formatter/src/expression/expr_slice.rs +++ b/crates/ruff_python_formatter/src/expression/expr_slice.rs @@ -1,4 +1,4 @@ -use ruff_python_ast::{Expr, ExprSlice, ExprUnaryOp, Ranged, UnaryOp}; +use ruff_python_ast::{Expr, ExprSlice, ExprUnaryOp, UnaryOp}; use ruff_text_size::TextRange; use ruff_formatter::prelude::{hard_line_break, line_suffix_boundary, space, text}; @@ -20,13 +20,18 @@ impl FormatNodeRule for FormatExprSlice { fn fmt_fields(&self, item: &ExprSlice, f: &mut PyFormatter) -> FormatResult<()> { // `[lower:upper:step]` let ExprSlice { - range, lower, upper, step, + range, } = item; - let (first_colon, second_colon) = find_colons(f.context().source(), *range, lower, upper)?; + let (first_colon, second_colon) = find_colons( + f.context().source(), + *range, + lower.as_deref(), + upper.as_deref(), + )?; // Handle comment placement // In placements.rs, we marked comment for None nodes a dangling and associated all others @@ -36,14 +41,14 @@ impl FormatNodeRule for FormatExprSlice { let comments = f.context().comments().clone(); let slice_dangling_comments = comments.dangling_comments(item.as_any_node_ref()); // Put the dangling comments (where the nodes are missing) into buckets - let first_colon_partition_index = slice_dangling_comments - .partition_point(|x| x.slice().start() < first_colon.range.start()); + let first_colon_partition_index = + slice_dangling_comments.partition_point(|x| x.slice().start() < first_colon.start()); let (dangling_lower_comments, dangling_upper_step_comments) = slice_dangling_comments.split_at(first_colon_partition_index); let (dangling_upper_comments, dangling_step_comments) = if let Some(second_colon) = &second_colon { let second_colon_partition_index = dangling_upper_step_comments - .partition_point(|x| x.slice().start() < second_colon.range.start()); + .partition_point(|x| x.slice().start() < second_colon.start()); dangling_upper_step_comments.split_at(second_colon_partition_index) } else { // Without a second colon they remaining dangling comments belong between the first @@ -153,27 +158,27 @@ impl FormatNodeRule for FormatExprSlice { pub(crate) fn find_colons( contents: &str, range: TextRange, - lower: &Option>, - upper: &Option>, + lower: Option<&Expr>, + upper: Option<&Expr>, ) -> FormatResult<(SimpleToken, Option)> { let after_lower = lower .as_ref() - .map_or(range.start(), |lower| lower.range().end()); + .map_or(range.start(), ruff_python_ast::Ranged::end); let mut tokens = SimpleTokenizer::new(contents, TextRange::new(after_lower, range.end())) .skip_trivia() .skip_while(|token| token.kind == SimpleTokenKind::RParen); let first_colon = tokens.next().ok_or(FormatError::syntax_error( - "Din't find any token for slice first colon", + "Didn't find any token for slice first colon", ))?; if first_colon.kind != SimpleTokenKind::Colon { return Err(FormatError::syntax_error( - "slice first colon token was not a colon", + "Slice first colon token was not a colon", )); } let after_upper = upper .as_ref() - .map_or(first_colon.end(), |upper| upper.range().end()); + .map_or(first_colon.end(), ruff_python_ast::Ranged::end); let mut tokens = SimpleTokenizer::new(contents, TextRange::new(after_upper, range.end())) .skip_trivia() .skip_while(|token| token.kind == SimpleTokenKind::RParen); @@ -206,6 +211,7 @@ fn is_simple_expr(expr: &Expr) -> bool { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum ExprSliceCommentSection { Lower, Upper, @@ -229,21 +235,22 @@ pub(crate) fn assign_comment_in_slice( expr_slice: &ExprSlice, ) -> ExprSliceCommentSection { let ExprSlice { - range, lower, upper, step: _, + range, } = expr_slice; - let (first_colon, second_colon) = find_colons(contents, *range, lower, upper) - .expect("SyntaxError when trying to parse slice"); + let (first_colon, second_colon) = + find_colons(contents, *range, lower.as_deref(), upper.as_deref()) + .expect("SyntaxError when trying to parse slice"); - if comment.start() < first_colon.range.start() { + if comment.start() < first_colon.start() { ExprSliceCommentSection::Lower } else { // We are to the right of the first colon if let Some(second_colon) = second_colon { - if comment.start() < second_colon.range.start() { + if comment.start() < second_colon.start() { ExprSliceCommentSection::Upper } else { ExprSliceCommentSection::Step diff --git a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs index 2e1919e180b98..48ce15255593c 100644 --- a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs @@ -91,7 +91,7 @@ fn is_operand_parenthesized(unary: &ExprUnaryOp, source: &str) -> bool { UnaryOp::USub => '-'.text_len(), }; - let trivia_range = TextRange::new(unary.range.start() + operator_len, unary.operand.start()); + let trivia_range = TextRange::new(unary.start() + operator_len, unary.operand.start()); if let Some(token) = SimpleTokenizer::new(source, trivia_range) .skip_trivia() diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index 4d56ad66cbe2f..a19e405c1d712 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -269,6 +269,12 @@ struct FormatStringPart { is_raw_string: bool, } +impl Ranged for FormatStringPart { + fn range(&self) -> TextRange { + self.range + } +} + impl FormatStringPart { fn new(range: TextRange, quoting: Quoting, locator: &Locator, quote_style: QuoteStyle) -> Self { let string_content = locator.slice(range); @@ -317,10 +323,10 @@ impl Format> for FormatStringPart { write!(f, [self.prefix, self.preferred_quotes])?; match normalized { Cow::Borrowed(_) => { - source_text_slice(self.range, contains_newlines).fmt(f)?; + source_text_slice(self.range(), contains_newlines).fmt(f)?; } Cow::Owned(normalized) => { - dynamic_text(&normalized, Some(self.range.start())).fmt(f)?; + dynamic_text(&normalized, Some(self.start())).fmt(f)?; } } self.preferred_quotes.fmt(f) @@ -781,12 +787,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.range()).contains("\\\n") { return string_part.fmt(f); } let (normalized, _) = normalize_string( - locator.slice(string_part.range), + locator.slice(string_part.range()), string_part.preferred_quotes, string_part.is_raw_string, ); @@ -799,13 +805,13 @@ fn format_docstring(string_part: &FormatStringPart, f: &mut PyFormatter) -> Form write!( f, [ - source_position(string_part.range.start()), + source_position(string_part.start()), string_part.prefix, string_part.preferred_quotes ] )?; // We track where in the source docstring we are (in source code byte offsets) - let mut offset = string_part.range.start(); + let mut offset = string_part.start(); // The first line directly after the opening quotes has different rules than the rest, mainly // that we remove all leading whitespace as there's no indentation @@ -892,7 +898,7 @@ fn format_docstring(string_part: &FormatStringPart, f: &mut PyFormatter) -> Form f, [ string_part.preferred_quotes, - source_position(string_part.range.end()) + source_position(string_part.end()) ] ) } diff --git a/crates/ruff_python_formatter/src/other/comprehension.rs b/crates/ruff_python_formatter/src/other/comprehension.rs index 951e6f71cb912..c80679d2d0ea2 100644 --- a/crates/ruff_python_formatter/src/other/comprehension.rs +++ b/crates/ruff_python_formatter/src/other/comprehension.rs @@ -39,7 +39,7 @@ impl FormatNodeRule for FormatComprehension { let dangling_item_comments = comments.dangling_comments(item); let (before_target_comments, before_in_comments) = dangling_item_comments.split_at( dangling_item_comments - .partition_point(|comment| comment.slice().end() < target.range().start()), + .partition_point(|comment| comment.slice().end() < target.start()), ); let trailing_in_comments = comments.dangling_comments(iter); diff --git a/crates/ruff_python_formatter/src/other/match_case.rs b/crates/ruff_python_formatter/src/other/match_case.rs index 8d9d51550d82a..d501ecd8cfaa4 100644 --- a/crates/ruff_python_formatter/src/other/match_case.rs +++ b/crates/ruff_python_formatter/src/other/match_case.rs @@ -79,7 +79,7 @@ fn is_match_case_pattern_parenthesized( ) -> FormatResult { let mut tokenizer = SimpleTokenizer::new( context.source(), - TextRange::new(case.range().start(), pattern.range().start()), + TextRange::new(case.start(), pattern.start()), ) .skip_trivia(); diff --git a/crates/ruff_python_formatter/src/other/parameters.rs b/crates/ruff_python_formatter/src/other/parameters.rs index 3c10c8049fc73..09fd227ad2038 100644 --- a/crates/ruff_python_formatter/src/other/parameters.rs +++ b/crates/ruff_python_formatter/src/other/parameters.rs @@ -416,7 +416,7 @@ pub(crate) fn find_parameter_separators( debug_assert!(star.kind() == SimpleTokenKind::Star, "{star:?}"); Some(ParameterSeparator { - preceding_end: parameters.range.start(), + preceding_end: parameters.start(), separator: star.range, following_start: first_keyword_argument.start(), }) diff --git a/crates/ruff_python_formatter/src/type_param/type_params.rs b/crates/ruff_python_formatter/src/type_param/type_params.rs index 0c4858153058b..4228c2da3605e 100644 --- a/crates/ruff_python_formatter/src/type_param/type_params.rs +++ b/crates/ruff_python_formatter/src/type_param/type_params.rs @@ -6,7 +6,7 @@ use ruff_formatter::write; use ruff_formatter::FormatResult; use ruff_python_ast::node::AstNode; -use ruff_python_ast::TypeParams; +use ruff_python_ast::{Ranged, TypeParams}; #[derive(Default)] pub struct FormatTypeParams; @@ -26,7 +26,7 @@ impl FormatNodeRule for FormatTypeParams { write!(f, [trailing_comments(dangling_comments)])?; let items = format_with(|f| { - f.join_comma_separated(item.range.end()) + f.join_comma_separated(item.end()) .nodes(item.type_params.iter()) .finish() }); diff --git a/crates/ruff_python_parser/src/function.rs b/crates/ruff_python_parser/src/function.rs index e537dc4ed3594..eeab6cfd5c71d 100644 --- a/crates/ruff_python_parser/src/function.rs +++ b/crates/ruff_python_parser/src/function.rs @@ -66,7 +66,7 @@ pub(crate) fn validate_pos_params( if let Some(invalid) = first_invalid { return Err(LexicalError { error: LexicalErrorType::DefaultArgumentError, - location: invalid.parameter.range.start(), + location: invalid.parameter.start(), }); } Ok(()) diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index 9f154d071c224..beeb5b9dc0942 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -318,9 +318,8 @@ impl<'a> StringParser<'a> { ) })?; let leading = - &expression[..usize::from(value.range().start() - start_location) - 1]; - let trailing = - &expression[usize::from(value.range().end() - start_location) - 1..]; + &expression[..usize::from(value.start() - start_location) - 1]; + let trailing = &expression[usize::from(value.end() - start_location) - 1..]; vec![Expr::from(ast::ExprFormattedValue { value: Box::new(value), debug_text: Some(ast::DebugText { diff --git a/crates/ruff_python_semantic/src/binding.rs b/crates/ruff_python_semantic/src/binding.rs index 1d910bbab302f..ca4c4d532726b 100644 --- a/crates/ruff_python_semantic/src/binding.rs +++ b/crates/ruff_python_semantic/src/binding.rs @@ -283,6 +283,12 @@ bitflags! { } } +impl Ranged for Binding<'_> { + fn range(&self) -> TextRange { + self.range + } +} + /// ID uniquely identifying a [Binding] in a program. /// /// Using a `u32` to identify [Binding]s should is sufficient because Ruff only supports documents with a diff --git a/crates/ruff_python_semantic/src/reference.rs b/crates/ruff_python_semantic/src/reference.rs index 6c3201f53884e..80a3fdef8d72c 100644 --- a/crates/ruff_python_semantic/src/reference.rs +++ b/crates/ruff_python_semantic/src/reference.rs @@ -3,6 +3,7 @@ use ruff_text_size::TextRange; use std::ops::Deref; use ruff_index::{newtype_index, IndexSlice, IndexVec}; +use ruff_python_ast::Ranged; use ruff_source_file::Locator; use crate::context::ExecutionContext; @@ -26,11 +27,6 @@ impl ResolvedReference { self.scope_id } - /// The range of the reference in the source code. - pub const fn range(&self) -> TextRange { - self.range - } - /// The [`ExecutionContext`] of the reference. pub const fn context(&self) -> ExecutionContext { if self.flags.intersects(SemanticModelFlags::TYPING_CONTEXT) { @@ -41,6 +37,13 @@ impl ResolvedReference { } } +impl Ranged for ResolvedReference { + /// The range of the reference in the source code. + fn range(&self) -> TextRange { + self.range + } +} + /// Id uniquely identifying a read reference in a program. #[newtype_index] pub struct ResolvedReferenceId; diff --git a/crates/ruff_shrinking/src/main.rs b/crates/ruff_shrinking/src/main.rs index 5efef3a728464..1847eb9a8fd54 100644 --- a/crates/ruff_shrinking/src/main.rs +++ b/crates/ruff_shrinking/src/main.rs @@ -87,10 +87,8 @@ impl Strategy for StrategyRemoveModuleMember { ) -> Result> { let iter = ast.iter().map(|stmt| { // trim the newlines the range misses - input[..stmt.range().start().to_usize()] - .trim_end() - .to_string() - + input[stmt.range().end().to_usize()..].trim_start() + input[..stmt.start().to_usize()].trim_end().to_string() + + input[stmt.end().to_usize()..].trim_start() }); Ok(Box::new(iter)) }