mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 13:33:50 +00:00
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`
This commit is contained in:
parent
a70807e1e1
commit
db1c556508
66 changed files with 221 additions and 176 deletions
|
@ -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(|| {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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::{
|
||||
|
|
|
@ -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,43 +27,34 @@ 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 range(&self) -> TextRange {
|
||||
self.expr.range()
|
||||
}
|
||||
|
||||
pub(crate) fn leading_quote(&self) -> &'a str {
|
||||
&self.contents[TextRange::up_to(self.body_range.start())]
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for Docstring<'_> {
|
||||
fn range(&self) -> TextRange {
|
||||
self.expr.range()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct DocstringBody<'a> {
|
||||
docstring: &'a Docstring<'a>,
|
||||
}
|
||||
|
||||
impl<'a> DocstringBody<'a> {
|
||||
#[inline]
|
||||
pub(crate) fn start(self) -> TextSize {
|
||||
self.range().start()
|
||||
}
|
||||
|
||||
pub(crate) 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 Ranged for DocstringBody<'_> {
|
||||
fn range(&self) -> TextRange {
|
||||
self.docstring.body_range + self.docstring.start()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for DocstringBody<'_> {
|
||||
type Target = str;
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(|| {
|
||||
|
|
|
@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TextRange>,
|
||||
}
|
||||
|
||||
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");
|
||||
|
|
|
@ -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<TextRange>,
|
||||
}
|
||||
|
||||
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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -96,10 +96,8 @@ pub(crate) fn remove_exception_handler_assignment(
|
|||
locator: &Locator,
|
||||
) -> Result<Edit> {
|
||||
// Lex backwards, to the token just before the `as`.
|
||||
let mut tokenizer = SimpleTokenizer::up_to_without_back_comment(
|
||||
bound_exception.range.start(),
|
||||
locator.contents(),
|
||||
)
|
||||
let mut tokenizer =
|
||||
SimpleTokenizer::up_to_without_back_comment(bound_exception.start(), locator.contents())
|
||||
.skip_trivia();
|
||||
|
||||
// Eat the `as` token.
|
||||
|
@ -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")?;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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<TextRange>,
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Diagnostic> {
|
||||
if binding.is_invalid_all_format() {
|
||||
Some(Diagnostic::new(InvalidAllFormat, binding.range))
|
||||
Some(Diagnostic::new(InvalidAllFormat, binding.range()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -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<Diagnostic> {
|
||||
if binding.is_invalid_all_object() {
|
||||
Some(Diagnostic::new(InvalidAllObject, binding.range))
|
||||
Some(Diagnostic::new(InvalidAllObject, binding.range()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Item = IfElifBranch> {
|
||||
iter::once(IfElifBranch {
|
||||
kind: BranchKind::If,
|
||||
|
|
|
@ -327,7 +327,7 @@ impl Format<PyFormatContext<'_>> 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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<ExprSlice> 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<ExprSlice> 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<ExprSlice> for FormatExprSlice {
|
|||
pub(crate) fn find_colons(
|
||||
contents: &str,
|
||||
range: TextRange,
|
||||
lower: &Option<Box<Expr>>,
|
||||
upper: &Option<Box<Expr>>,
|
||||
lower: Option<&Expr>,
|
||||
upper: Option<&Expr>,
|
||||
) -> FormatResult<(SimpleToken, Option<SimpleToken>)> {
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<PyFormatContext<'_>> 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())
|
||||
]
|
||||
)
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ impl FormatNodeRule<Comprehension> 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);
|
||||
|
|
|
@ -79,7 +79,7 @@ fn is_match_case_pattern_parenthesized(
|
|||
) -> FormatResult<bool> {
|
||||
let mut tokenizer = SimpleTokenizer::new(
|
||||
context.source(),
|
||||
TextRange::new(case.range().start(), pattern.range().start()),
|
||||
TextRange::new(case.start(), pattern.start()),
|
||||
)
|
||||
.skip_trivia();
|
||||
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
|
|
|
@ -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<TypeParams> 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()
|
||||
});
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -87,10 +87,8 @@ impl Strategy for StrategyRemoveModuleMember {
|
|||
) -> Result<Box<dyn ExactSizeStringIter + 'a>> {
|
||||
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))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue