Extract `LineIndex` independent methods from `Locator` (#13938)

This commit is contained in:
Micha Reiser 2024-10-28 08:53:41 +01:00 committed by GitHub
parent f8eb547fb4
commit 9f3a38d408
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
171 changed files with 1348 additions and 1284 deletions

2
Cargo.lock generated
View File

@ -2748,7 +2748,6 @@ dependencies = [
"ruff_python_ast", "ruff_python_ast",
"ruff_python_parser", "ruff_python_parser",
"ruff_python_stdlib", "ruff_python_stdlib",
"ruff_source_file",
"ruff_text_size", "ruff_text_size",
"rustc-hash 2.0.0", "rustc-hash 2.0.0",
"schemars", "schemars",
@ -2779,7 +2778,6 @@ dependencies = [
"insta", "insta",
"ruff_python_parser", "ruff_python_parser",
"ruff_python_trivia", "ruff_python_trivia",
"ruff_source_file",
"ruff_text_size", "ruff_text_size",
] ]

View File

@ -40,7 +40,7 @@ use ruff_db::files::File;
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
use ruff_db::source::{line_index, source_text, SourceText}; use ruff_db::source::{line_index, source_text, SourceText};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::{LineIndex, Locator, OneIndexed}; use ruff_source_file::{LineIndex, OneIndexed};
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::ops::Deref; use std::ops::Deref;
@ -67,16 +67,12 @@ impl InlineFileAssertions {
} }
} }
fn locator(&self) -> Locator {
Locator::with_index(&self.source, self.lines.clone())
}
fn line_number(&self, range: &impl Ranged) -> OneIndexed { fn line_number(&self, range: &impl Ranged) -> OneIndexed {
self.lines.line_index(range.start()) self.lines.line_index(range.start())
} }
fn is_own_line_comment(&self, ranged_assertion: &AssertionWithRange) -> bool { fn is_own_line_comment(&self, ranged_assertion: &AssertionWithRange) -> bool {
CommentRanges::is_own_line(ranged_assertion.start(), &self.locator()) CommentRanges::is_own_line(ranged_assertion.start(), self.source.as_str())
} }
} }
@ -131,10 +127,9 @@ impl<'a> Iterator for AssertionWithRangeIterator<'a> {
type Item = AssertionWithRange<'a>; type Item = AssertionWithRange<'a>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let locator = self.file_assertions.locator();
loop { loop {
let inner_next = self.inner.next()?; let inner_next = self.inner.next()?;
let comment = locator.slice(inner_next); let comment = &self.file_assertions.source[inner_next];
if let Some(assertion) = Assertion::from_comment(comment) { if let Some(assertion) = Assertion::from_comment(comment) {
return Some(AssertionWithRange(assertion, inner_next)); return Some(AssertionWithRange(assertion, inner_next));
}; };

View File

@ -26,11 +26,11 @@ pub(crate) fn bindings(checker: &mut Checker) {
&& !checker && !checker
.settings .settings
.dummy_variable_rgx .dummy_variable_rgx
.is_match(binding.name(checker.locator)) .is_match(binding.name(checker.source()))
{ {
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
pyflakes::rules::UnusedVariable { pyflakes::rules::UnusedVariable {
name: binding.name(checker.locator).to_string(), name: binding.name(checker.source()).to_string(),
}, },
binding.range(), binding.range(),
); );

View File

@ -1,10 +1,10 @@
use ruff_python_ast::str::raw_contents_range; use ruff_python_ast::str::raw_contents_range;
use ruff_text_size::{Ranged, TextRange};
use ruff_python_semantic::all::DunderAllName; use ruff_python_semantic::all::DunderAllName;
use ruff_python_semantic::{ use ruff_python_semantic::{
BindingKind, ContextualizedDefinition, Definition, Export, Member, MemberKind, BindingKind, ContextualizedDefinition, Definition, Export, Member, MemberKind,
}; };
use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::codes::Rule; use crate::codes::Rule;

View File

@ -17,7 +17,7 @@ pub(crate) fn unresolved_references(checker: &mut Checker) {
if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) { if checker.enabled(Rule::UndefinedLocalWithImportStarUsage) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
pyflakes::rules::UndefinedLocalWithImportStarUsage { pyflakes::rules::UndefinedLocalWithImportStarUsage {
name: reference.name(checker.locator).to_string(), name: reference.name(checker.source()).to_string(),
}, },
reference.range(), reference.range(),
)); ));
@ -31,12 +31,12 @@ pub(crate) fn unresolved_references(checker: &mut Checker) {
// Allow __path__. // Allow __path__.
if checker.path.ends_with("__init__.py") { if checker.path.ends_with("__init__.py") {
if reference.name(checker.locator) == "__path__" { if reference.name(checker.source()) == "__path__" {
continue; continue;
} }
} }
let symbol_name = reference.name(checker.locator); let symbol_name = reference.name(checker.source());
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(
pyflakes::rules::UndefinedName { pyflakes::rules::UndefinedName {

View File

@ -59,7 +59,7 @@ use ruff_python_semantic::{
}; };
use ruff_python_stdlib::builtins::{python_builtins, MAGIC_GLOBALS}; use ruff_python_stdlib::builtins::{python_builtins, MAGIC_GLOBALS};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::{Locator, OneIndexed, SourceRow}; use ruff_source_file::{OneIndexed, SourceRow};
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::annotation::AnnotationContext; use crate::checkers::ast::annotation::AnnotationContext;
@ -69,7 +69,7 @@ use crate::noqa::NoqaMapping;
use crate::registry::Rule; use crate::registry::Rule;
use crate::rules::{flake8_pyi, flake8_type_checking, pyflakes, pyupgrade}; use crate::rules::{flake8_pyi, flake8_type_checking, pyflakes, pyupgrade};
use crate::settings::{flags, LinterSettings}; use crate::settings::{flags, LinterSettings};
use crate::{docstrings, noqa}; use crate::{docstrings, noqa, Locator};
mod analyze; mod analyze;
mod annotation; mod annotation;
@ -352,6 +352,10 @@ impl<'a> Checker<'a> {
self.locator self.locator
} }
pub(crate) const fn source(&self) -> &'a str {
self.locator.contents()
}
/// The [`Stylist`] for the current file, which detects the current line ending, quote, and /// The [`Stylist`] for the current file, which detects the current line ending, quote, and
/// indentation style. /// indentation style.
pub(crate) const fn stylist(&self) -> &'a Stylist<'a> { pub(crate) const fn stylist(&self) -> &'a Stylist<'a> {

View File

@ -2,13 +2,13 @@ use std::path::Path;
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use crate::registry::Rule; use crate::registry::Rule;
use crate::rules::flake8_builtins::rules::builtin_module_shadowing; use crate::rules::flake8_builtins::rules::builtin_module_shadowing;
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package; use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
use crate::rules::pep8_naming::rules::invalid_module_name; use crate::rules::pep8_naming::rules::invalid_module_name;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
pub(crate) fn check_file_path( pub(crate) fn check_file_path(
path: &Path, path: &Path,

View File

@ -8,13 +8,13 @@ use ruff_python_ast::{ModModule, PySourceType};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::Parsed; use ruff_python_parser::Parsed;
use ruff_source_file::Locator;
use crate::directives::IsortDirectives; use crate::directives::IsortDirectives;
use crate::registry::Rule; use crate::registry::Rule;
use crate::rules::isort; use crate::rules::isort;
use crate::rules::isort::block::{Block, BlockBuilder}; use crate::rules::isort::block::{Block, BlockBuilder};
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn check_imports( pub(crate) fn check_imports(

View File

@ -1,11 +1,11 @@
use crate::line_width::IndentWidth;
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::{TokenKind, Tokens}; use ruff_python_parser::{TokenKind, Tokens};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::line_width::IndentWidth;
use crate::registry::{AsRule, Rule}; use crate::registry::{AsRule, Rule};
use crate::rules::pycodestyle::rules::logical_lines::{ use crate::rules::pycodestyle::rules::logical_lines::{
extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword, extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword,
@ -14,6 +14,7 @@ use crate::rules::pycodestyle::rules::logical_lines::{
whitespace_before_comment, whitespace_before_parameters, LogicalLines, TokenFlags, whitespace_before_comment, whitespace_before_parameters, LogicalLines, TokenFlags,
}; };
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
/// Return the amount of indentation, expanding tabs to the next multiple of the settings' tab size. /// Return the amount of indentation, expanding tabs to the next multiple of the settings' tab size.
pub(crate) fn expand_indent(line: &str, indent_width: IndentWidth) -> usize { pub(crate) fn expand_indent(line: &str, indent_width: IndentWidth) -> usize {

View File

@ -7,7 +7,6 @@ use rustc_hash::FxHashSet;
use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::fix::edits::delete_comment; use crate::fix::edits::delete_comment;
@ -20,6 +19,7 @@ use crate::rules::pygrep_hooks;
use crate::rules::ruff; use crate::rules::ruff;
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA}; use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn check_noqa( pub(crate) fn check_noqa(
@ -33,13 +33,8 @@ pub(crate) fn check_noqa(
settings: &LinterSettings, settings: &LinterSettings,
) -> Vec<usize> { ) -> Vec<usize> {
// Identify any codes that are globally exempted (within the current file). // Identify any codes that are globally exempted (within the current file).
let file_noqa_directives = FileNoqaDirectives::extract( let file_noqa_directives =
locator.contents(), FileNoqaDirectives::extract(locator, comment_ranges, &settings.external, path);
comment_ranges,
&settings.external,
path,
locator,
);
let exemption = FileExemption::from(&file_noqa_directives); let exemption = FileExemption::from(&file_noqa_directives);
// Extract all `noqa` directives. // Extract all `noqa` directives.

View File

@ -3,7 +3,7 @@
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_source_file::{Locator, UniversalNewlines}; use ruff_source_file::UniversalNewlines;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use crate::registry::Rule; use crate::registry::Rule;
@ -14,6 +14,7 @@ use crate::rules::pycodestyle::rules::{
}; };
use crate::rules::pylint; use crate::rules::pylint;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
pub(crate) fn check_physical_lines( pub(crate) fn check_physical_lines(
locator: &Locator, locator: &Locator,
@ -92,12 +93,12 @@ mod tests {
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::parse_module; use ruff_python_parser::parse_module;
use ruff_source_file::Locator;
use crate::line_width::LineLength; use crate::line_width::LineLength;
use crate::registry::Rule; use crate::registry::Rule;
use crate::rules::pycodestyle; use crate::rules::pycodestyle;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
use super::check_physical_lines; use super::check_physical_lines;
@ -106,8 +107,8 @@ mod tests {
let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8. let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8.
let locator = Locator::new(line); let locator = Locator::new(line);
let parsed = parse_module(line).unwrap(); let parsed = parse_module(line).unwrap();
let indexer = Indexer::from_tokens(parsed.tokens(), &locator); let indexer = Indexer::from_tokens(parsed.tokens(), locator.contents());
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
let check_with_max_line_length = |line_length: LineLength| { let check_with_max_line_length = |line_length: LineLength| {
check_physical_lines( check_physical_lines(

View File

@ -2,14 +2,12 @@
use std::path::Path; use std::path::Path;
use ruff_diagnostics::Diagnostic;
use ruff_notebook::CellOffsets; use ruff_notebook::CellOffsets;
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_diagnostics::Diagnostic;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::Tokens; use ruff_python_parser::Tokens;
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::directives::TodoComment; use crate::directives::TodoComment;
@ -20,6 +18,7 @@ use crate::rules::{
flake8_pyi, flake8_todos, pycodestyle, pygrep_hooks, pylint, pyupgrade, ruff, flake8_pyi, flake8_todos, pycodestyle, pygrep_hooks, pylint, pyupgrade, ruff,
}; };
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn check_tokens( pub(crate) fn check_tokens(

View File

@ -4,15 +4,16 @@ use std::iter::Peekable;
use std::str::FromStr; use std::str::FromStr;
use bitflags::bitflags; use bitflags::bitflags;
use ruff_python_parser::{TokenKind, Tokens};
use ruff_python_trivia::CommentRanges;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_source_file::Locator; use ruff_python_parser::{TokenKind, Tokens};
use ruff_python_trivia::CommentRanges;
use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::noqa::NoqaMapping; use crate::noqa::NoqaMapping;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
bitflags! { bitflags! {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -360,24 +361,23 @@ impl TodoDirectiveKind {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruff_python_index::Indexer;
use ruff_python_parser::parse_module; use ruff_python_parser::parse_module;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_text_size::{TextLen, TextRange, TextSize}; use ruff_text_size::{TextLen, TextRange, TextSize};
use ruff_python_index::Indexer;
use ruff_source_file::Locator;
use crate::directives::{ use crate::directives::{
extract_isort_directives, extract_noqa_line_for, TodoDirective, TodoDirectiveKind, extract_isort_directives, extract_noqa_line_for, TodoDirective, TodoDirectiveKind,
}; };
use crate::noqa::NoqaMapping; use crate::noqa::NoqaMapping;
use crate::Locator;
use super::IsortDirectives; use super::IsortDirectives;
fn noqa_mappings(contents: &str) -> NoqaMapping { fn noqa_mappings(contents: &str) -> NoqaMapping {
let parsed = parse_module(contents).unwrap(); let parsed = parse_module(contents).unwrap();
let locator = Locator::new(contents); let locator = Locator::new(contents);
let indexer = Indexer::from_tokens(parsed.tokens(), &locator); let indexer = Indexer::from_tokens(parsed.tokens(), locator.contents());
extract_noqa_line_for(parsed.tokens(), &locator, &indexer) extract_noqa_line_for(parsed.tokens(), &locator, &indexer)
} }

View File

@ -4,12 +4,13 @@
use std::iter::FusedIterator; use std::iter::FusedIterator;
use std::slice::Iter; use std::slice::Iter;
use ruff_python_ast::statement_visitor::{walk_stmt, StatementVisitor};
use ruff_python_ast::{self as ast, Stmt, Suite}; use ruff_python_ast::{self as ast, Stmt, Suite};
use ruff_python_parser::{Token, TokenKind, Tokens}; use ruff_python_parser::{Token, TokenKind, Tokens};
use ruff_source_file::UniversalNewlineIterator;
use ruff_text_size::{Ranged, TextSize}; use ruff_text_size::{Ranged, TextSize};
use ruff_python_ast::statement_visitor::{walk_stmt, StatementVisitor}; use crate::Locator;
use ruff_source_file::{Locator, UniversalNewlineIterator};
/// Extract doc lines (standalone comments) from a token sequence. /// Extract doc lines (standalone comments) from a token sequence.
pub(crate) fn doc_lines_from_tokens(tokens: &Tokens) -> DocLines { pub(crate) fn doc_lines_from_tokens(tokens: &Tokens) -> DocLines {

View File

@ -13,9 +13,9 @@ use unicode_normalization::UnicodeNormalization;
use ruff_python_ast::name::UnqualifiedName; use ruff_python_ast::name::UnqualifiedName;
use ruff_python_ast::Stmt; use ruff_python_ast::Stmt;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_source_file::Locator;
use crate::cst::matchers::match_statement; use crate::cst::matchers::match_statement;
use crate::Locator;
/// Glue code to make libcst codegen work with ruff's Stylist /// Glue code to make libcst codegen work with ruff's Stylist
pub(crate) trait CodegenStylist<'a>: Codegen<'a> { pub(crate) trait CodegenStylist<'a>: Codegen<'a> {

View File

@ -13,13 +13,14 @@ use ruff_python_trivia::{
has_leading_content, is_python_whitespace, CommentRanges, PythonWhitespace, SimpleTokenKind, has_leading_content, is_python_whitespace, CommentRanges, PythonWhitespace, SimpleTokenKind,
SimpleTokenizer, SimpleTokenizer,
}; };
use ruff_source_file::{Locator, NewlineWithTrailingNewline, UniversalNewlines}; use ruff_source_file::{LineRanges, NewlineWithTrailingNewline, UniversalNewlines};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::cst::matchers::{match_function_def, match_indented_block, match_statement}; use crate::cst::matchers::{match_function_def, match_indented_block, match_statement};
use crate::fix::codemods; use crate::fix::codemods;
use crate::fix::codemods::CodegenStylist; use crate::fix::codemods::CodegenStylist;
use crate::line_width::{IndentWidth, LineLength, LineWidthBuilder}; use crate::line_width::{IndentWidth, LineLength, LineWidthBuilder};
use crate::Locator;
/// Return the `Fix` to use when deleting a `Stmt`. /// Return the `Fix` to use when deleting a `Stmt`.
/// ///
@ -48,9 +49,11 @@ pub(crate) fn delete_stmt(
if let Some(semicolon) = trailing_semicolon(stmt.end(), locator) { if let Some(semicolon) = trailing_semicolon(stmt.end(), locator) {
let next = next_stmt_break(semicolon, locator); let next = next_stmt_break(semicolon, locator);
Edit::deletion(stmt.start(), next) Edit::deletion(stmt.start(), next)
} else if has_leading_content(stmt.start(), locator) { } else if has_leading_content(stmt.start(), locator.contents()) {
Edit::range_deletion(stmt.range()) Edit::range_deletion(stmt.range())
} else if let Some(start) = indexer.preceded_by_continuations(stmt.start(), locator) { } else if let Some(start) =
indexer.preceded_by_continuations(stmt.start(), locator.contents())
{
Edit::deletion(start, stmt.end()) Edit::deletion(start, stmt.end())
} else { } else {
let range = locator.full_lines_range(stmt.range()); let range = locator.full_lines_range(stmt.range());
@ -595,13 +598,13 @@ mod tests {
use ruff_python_ast::Stmt; use ruff_python_ast::Stmt;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_parser::{parse_expression, parse_module}; use ruff_python_parser::{parse_expression, parse_module};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::fix::apply_fixes; use crate::fix::apply_fixes;
use crate::fix::edits::{ use crate::fix::edits::{
add_to_dunder_all, make_redundant_alias, next_stmt_break, trailing_semicolon, add_to_dunder_all, make_redundant_alias, next_stmt_break, trailing_semicolon,
}; };
use crate::Locator;
/// Parse the given source using [`Mode::Module`] and return the first statement. /// Parse the given source using [`Mode::Module`] and return the first statement.
fn parse_first_stmt(source: &str) -> Result<Stmt> { fn parse_first_stmt(source: &str) -> Result<Stmt> {
@ -726,7 +729,7 @@ x = 1 \
let locator = Locator::new(raw); let locator = Locator::new(raw);
let edits = { let edits = {
let parsed = parse_expression(raw)?; let parsed = parse_expression(raw)?;
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
add_to_dunder_all(names.iter().copied(), parsed.expr(), &stylist) add_to_dunder_all(names.iter().copied(), parsed.expr(), &stylist)
}; };
let diag = { let diag = {

View File

@ -1,15 +1,15 @@
use itertools::Itertools;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use ruff_diagnostics::{Diagnostic, Edit, Fix, IsolationLevel, SourceMap}; use ruff_diagnostics::{Diagnostic, Edit, Fix, IsolationLevel, SourceMap};
use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::linter::FixTable; use crate::linter::FixTable;
use crate::registry::{AsRule, Rule}; use crate::registry::{AsRule, Rule};
use crate::settings::types::UnsafeFixes; use crate::settings::types::UnsafeFixes;
use crate::Locator;
pub(crate) mod codemods; pub(crate) mod codemods;
pub(crate) mod edits; pub(crate) mod edits;
@ -158,13 +158,12 @@ fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Orderi
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruff_text_size::{Ranged, TextSize};
use ruff_diagnostics::{Diagnostic, Edit, Fix, SourceMarker}; use ruff_diagnostics::{Diagnostic, Edit, Fix, SourceMarker};
use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextSize};
use crate::fix::{apply_fixes, FixResult}; use crate::fix::{apply_fixes, FixResult};
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile; use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
use crate::Locator;
#[allow(deprecated)] #[allow(deprecated)]
fn create_diagnostics(edit: impl IntoIterator<Item = Edit>) -> Vec<Diagnostic> { fn create_diagnostics(edit: impl IntoIterator<Item = Edit>) -> Vec<Diagnostic> {

View File

@ -1,15 +1,16 @@
//! Insert statements into Python code. //! Insert statements into Python code.
use std::ops::Add; use std::ops::Add;
use ruff_python_ast::Stmt;
use ruff_python_parser::{TokenKind, Tokens};
use ruff_text_size::{Ranged, TextSize};
use ruff_diagnostics::Edit; use ruff_diagnostics::Edit;
use ruff_python_ast::helpers::is_docstring_stmt; use ruff_python_ast::helpers::is_docstring_stmt;
use ruff_python_ast::Stmt;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_parser::{TokenKind, Tokens};
use ruff_python_trivia::{textwrap::indent, PythonWhitespace}; use ruff_python_trivia::{textwrap::indent, PythonWhitespace};
use ruff_source_file::{Locator, UniversalNewlineIterator}; use ruff_source_file::{LineRanges, UniversalNewlineIterator};
use ruff_text_size::{Ranged, TextSize};
use crate::Locator;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub(super) enum Placement<'a> { pub(super) enum Placement<'a> {
@ -64,7 +65,7 @@ impl<'a> Insertion<'a> {
// Otherwise, advance to the next row. // Otherwise, advance to the next row.
locator.full_line_end(location) locator.full_line_end(location)
} else { } else {
locator.contents_start() locator.bom_start_offset()
}; };
// Skip over commented lines, with whitespace separation. // Skip over commented lines, with whitespace separation.
@ -319,9 +320,11 @@ mod tests {
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_parser::parse_module; use ruff_python_parser::parse_module;
use ruff_source_file::{LineEnding, Locator}; use ruff_source_file::LineEnding;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use crate::Locator;
use super::Insertion; use super::Insertion;
#[test] #[test]
@ -329,7 +332,7 @@ mod tests {
fn insert(contents: &str) -> Result<Insertion> { fn insert(contents: &str) -> Result<Insertion> {
let parsed = parse_module(contents)?; let parsed = parse_module(contents)?;
let locator = Locator::new(contents); let locator = Locator::new(contents);
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
Ok(Insertion::start_of_file(parsed.suite(), &locator, &stylist)) Ok(Insertion::start_of_file(parsed.suite(), &locator, &stylist))
} }
@ -440,7 +443,7 @@ x = 1
fn insert(contents: &str, offset: TextSize) -> Insertion { fn insert(contents: &str, offset: TextSize) -> Insertion {
let parsed = parse_module(contents).unwrap(); let parsed = parse_module(contents).unwrap();
let locator = Locator::new(contents); let locator = Locator::new(contents);
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
Insertion::start_of_block(offset, &locator, &stylist, parsed.tokens()) Insertion::start_of_block(offset, &locator, &stylist, parsed.tokens())
} }

View File

@ -16,13 +16,13 @@ use ruff_python_semantic::{
ImportedName, MemberNameImport, ModuleNameImport, NameImport, SemanticModel, ImportedName, MemberNameImport, ModuleNameImport, NameImport, SemanticModel,
}; };
use ruff_python_trivia::textwrap::indent; use ruff_python_trivia::textwrap::indent;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextSize}; use ruff_text_size::{Ranged, TextSize};
use crate::cst::matchers::{match_aliases, match_import_from, match_statement}; use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
use crate::fix; use crate::fix;
use crate::fix::codemods::CodegenStylist; use crate::fix::codemods::CodegenStylist;
use crate::importer::insertion::Insertion; use crate::importer::insertion::Insertion;
use crate::Locator;
mod insertion; mod insertion;

View File

@ -5,6 +5,7 @@
//! //!
//! [Ruff]: https://github.com/astral-sh/ruff //! [Ruff]: https://github.com/astral-sh/ruff
pub use locator::Locator;
pub use noqa::generate_noqa_edits; pub use noqa::generate_noqa_edits;
#[cfg(feature = "clap")] #[cfg(feature = "clap")]
pub use registry::clap_completion::RuleParser; pub use registry::clap_completion::RuleParser;
@ -27,6 +28,7 @@ pub mod fs;
mod importer; mod importer;
pub mod line_width; pub mod line_width;
pub mod linter; pub mod linter;
mod locator;
pub mod logging; pub mod logging;
pub mod message; pub mod message;
mod noqa; mod noqa;

View File

@ -14,7 +14,7 @@ use ruff_python_ast::{ModModule, PySourceType};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::{ParseError, Parsed}; use ruff_python_parser::{ParseError, Parsed};
use ruff_source_file::{Locator, SourceFileBuilder}; use ruff_source_file::SourceFileBuilder;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::check_ast; use crate::checkers::ast::check_ast;
@ -34,7 +34,7 @@ use crate::rules::ruff::rules::test_rules::{self, TestRule, TEST_RULES};
use crate::settings::types::UnsafeFixes; use crate::settings::types::UnsafeFixes;
use crate::settings::{flags, LinterSettings}; use crate::settings::{flags, LinterSettings};
use crate::source_kind::SourceKind; use crate::source_kind::SourceKind;
use crate::{directives, fs}; use crate::{directives, fs, Locator};
pub struct LinterResult { pub struct LinterResult {
/// A collection of diagnostic messages generated by the linter. /// A collection of diagnostic messages generated by the linter.
@ -335,10 +335,10 @@ pub fn add_noqa_to_path(
let locator = Locator::new(source_kind.source_code()); let locator = Locator::new(source_kind.source_code());
// Detect the current code style (lazily). // Detect the current code style (lazily).
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
// Extra indices from the code. // Extra indices from the code.
let indexer = Indexer::from_tokens(parsed.tokens(), &locator); let indexer = Indexer::from_tokens(parsed.tokens(), locator.contents());
// Extract the `# noqa` and `# isort: skip` directives from the source. // Extract the `# noqa` and `# isort: skip` directives from the source.
let directives = directives::extract_directives( let directives = directives::extract_directives(
@ -393,10 +393,10 @@ pub fn lint_only(
let locator = Locator::new(source_kind.source_code()); let locator = Locator::new(source_kind.source_code());
// Detect the current code style (lazily). // Detect the current code style (lazily).
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
// Extra indices from the code. // Extra indices from the code.
let indexer = Indexer::from_tokens(parsed.tokens(), &locator); let indexer = Indexer::from_tokens(parsed.tokens(), locator.contents());
// Extract the `# noqa` and `# isort: skip` directives from the source. // Extract the `# noqa` and `# isort: skip` directives from the source.
let directives = directives::extract_directives( let directives = directives::extract_directives(
@ -495,10 +495,10 @@ pub fn lint_fix<'a>(
let locator = Locator::new(transformed.source_code()); let locator = Locator::new(transformed.source_code());
// Detect the current code style (lazily). // Detect the current code style (lazily).
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
// Extra indices from the code. // Extra indices from the code.
let indexer = Indexer::from_tokens(parsed.tokens(), &locator); let indexer = Indexer::from_tokens(parsed.tokens(), locator.contents());
// Extract the `# noqa` and `# isort: skip` directives from the source. // Extract the `# noqa` and `# isort: skip` directives from the source.
let directives = directives::extract_directives( let directives = directives::extract_directives(

View File

@ -0,0 +1,224 @@
//! Struct used to efficiently slice source code at (row, column) Locations.
use std::cell::OnceCell;
use ruff_source_file::{LineIndex, LineRanges, OneIndexed, SourceCode, SourceLocation};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
#[derive(Debug)]
pub struct Locator<'a> {
contents: &'a str,
index: OnceCell<LineIndex>,
}
impl<'a> Locator<'a> {
pub const fn new(contents: &'a str) -> Self {
Self {
contents,
index: OnceCell::new(),
}
}
pub fn with_index(contents: &'a str, index: LineIndex) -> Self {
Self {
contents,
index: OnceCell::from(index),
}
}
#[deprecated(
note = "This is expensive, avoid using outside of the diagnostic phase. Prefer the other `Locator` methods instead."
)]
pub fn compute_line_index(&self, offset: TextSize) -> OneIndexed {
self.to_index().line_index(offset)
}
#[deprecated(
note = "This is expensive, avoid using outside of the diagnostic phase. Prefer the other `Locator` methods instead."
)]
pub fn compute_source_location(&self, offset: TextSize) -> SourceLocation {
self.to_source_code().source_location(offset)
}
pub fn to_index(&self) -> &LineIndex {
self.index
.get_or_init(|| LineIndex::from_source_text(self.contents))
}
pub fn line_index(&self) -> Option<&LineIndex> {
self.index.get()
}
pub fn to_source_code(&self) -> SourceCode {
SourceCode::new(self.contents, self.to_index())
}
/// Take the source code up to the given [`TextSize`].
#[inline]
pub fn up_to(&self, offset: TextSize) -> &'a str {
&self.contents[TextRange::up_to(offset)]
}
/// Take the source code after the given [`TextSize`].
#[inline]
pub fn after(&self, offset: TextSize) -> &'a str {
&self.contents[usize::from(offset)..]
}
/// Finds the closest [`TextSize`] not exceeding the offset for which `is_char_boundary` is
/// `true`.
///
/// Can be replaced with `str::floor_char_boundary` once it's stable.
///
/// ## Examples
///
/// ```
/// # use ruff_text_size::{Ranged, TextRange, TextSize};
/// # use ruff_linter::Locator;
///
/// let locator = Locator::new("Hello");
///
/// assert_eq!(
/// locator.floor_char_boundary(TextSize::from(0)),
/// TextSize::from(0)
/// );
///
/// assert_eq!(
/// locator.floor_char_boundary(TextSize::from(5)),
/// TextSize::from(5)
/// );
///
/// let locator = Locator::new("α");
///
/// assert_eq!(
/// locator.floor_char_boundary(TextSize::from(0)),
/// TextSize::from(0)
/// );
///
/// assert_eq!(
/// locator.floor_char_boundary(TextSize::from(1)),
/// TextSize::from(0)
/// );
///
/// assert_eq!(
/// locator.floor_char_boundary(TextSize::from(2)),
/// TextSize::from(2)
/// );
/// ```
pub fn floor_char_boundary(&self, offset: TextSize) -> TextSize {
if offset >= self.text_len() {
self.text_len()
} else {
// We know that the character boundary is within four bytes.
(0u32..=3u32)
.map(TextSize::from)
.filter_map(|index| offset.checked_sub(index))
.find(|offset| self.contents.is_char_boundary(offset.to_usize()))
.unwrap_or_default()
}
}
/// Take the source code between the given [`TextRange`].
#[inline]
pub fn slice<T: Ranged>(&self, ranged: T) -> &'a str {
&self.contents[ranged.range()]
}
/// Return the underlying source code.
pub const fn contents(&self) -> &'a str {
self.contents
}
/// Return the number of bytes in the source code.
pub const fn len(&self) -> usize {
self.contents.len()
}
pub fn text_len(&self) -> TextSize {
self.contents.text_len()
}
/// Return `true` if the source code is empty.
pub const fn is_empty(&self) -> bool {
self.contents.is_empty()
}
}
// Override the `_str` methods from [`LineRanges`] to extend the lifetime to `'a`.
impl<'a> Locator<'a> {
/// Returns the text of the `offset`'s line.
///
/// See [`LineRanges::full_lines_str`].
pub fn full_line_str(&self, offset: TextSize) -> &'a str {
self.contents.full_line_str(offset)
}
/// Returns the text of the `offset`'s line.
///
/// See [`LineRanges::line_str`].
pub fn line_str(&self, offset: TextSize) -> &'a str {
self.contents.line_str(offset)
}
/// Returns the text of all lines that include `range`.
///
/// See [`LineRanges::lines_str`].
pub fn lines_str(&self, range: TextRange) -> &'a str {
self.contents.lines_str(range)
}
/// Returns the text of all lines that include `range`.
///
/// See [`LineRanges::full_lines_str`].
pub fn full_lines_str(&self, range: TextRange) -> &'a str {
self.contents.full_lines_str(range)
}
}
// Allow calling [`LineRanges`] methods on [`Locator`] directly.
impl LineRanges for Locator<'_> {
#[inline]
fn line_start(&self, offset: TextSize) -> TextSize {
self.contents.line_start(offset)
}
#[inline]
fn bom_start_offset(&self) -> TextSize {
self.contents.bom_start_offset()
}
#[inline]
fn full_line_end(&self, offset: TextSize) -> TextSize {
self.contents.full_line_end(offset)
}
#[inline]
fn line_end(&self, offset: TextSize) -> TextSize {
self.contents.line_end(offset)
}
#[inline]
fn full_line_str(&self, offset: TextSize) -> &str {
self.contents.full_line_str(offset)
}
#[inline]
fn line_str(&self, offset: TextSize) -> &str {
self.contents.line_str(offset)
}
#[inline]
fn contains_line_break(&self, range: TextRange) -> bool {
self.contents.contains_line_break(range)
}
#[inline]
fn lines_str(&self, range: TextRange) -> &str {
self.contents.lines_str(range)
}
#[inline]
fn full_lines_str(&self, range: TextRange) -> &str {
self.contents.full_lines_str(range)
}
}

View File

@ -14,17 +14,17 @@ pub use json_lines::JsonLinesEmitter;
pub use junit::JunitEmitter; pub use junit::JunitEmitter;
pub use pylint::PylintEmitter; pub use pylint::PylintEmitter;
pub use rdjson::RdjsonEmitter; pub use rdjson::RdjsonEmitter;
pub use sarif::SarifEmitter;
pub use text::TextEmitter;
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix}; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
use ruff_notebook::NotebookIndex; use ruff_notebook::NotebookIndex;
use ruff_python_parser::ParseError; use ruff_python_parser::ParseError;
use ruff_source_file::{Locator, SourceFile, SourceLocation}; use ruff_source_file::{SourceFile, SourceLocation};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
pub use sarif::SarifEmitter;
pub use text::TextEmitter;
use crate::logging::DisplayParseErrorType; use crate::logging::DisplayParseErrorType;
use crate::registry::{AsRule, Rule}; use crate::registry::{AsRule, Rule};
use crate::Locator;
mod azure; mod azure;
mod diff; mod diff;
@ -310,10 +310,11 @@ mod tests {
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Edit, Fix}; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Edit, Fix};
use ruff_notebook::NotebookIndex; use ruff_notebook::NotebookIndex;
use ruff_python_parser::{parse_unchecked, Mode}; use ruff_python_parser::{parse_unchecked, Mode};
use ruff_source_file::{Locator, OneIndexed, SourceFileBuilder}; use ruff_source_file::{OneIndexed, SourceFileBuilder};
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::message::{Emitter, EmitterContext, Message}; use crate::message::{Emitter, EmitterContext, Message};
use crate::Locator;
pub(super) fn create_syntax_error_messages() -> Vec<Message> { pub(super) fn create_syntax_error_messages() -> Vec<Message> {
let source = r"from os import let source = r"from os import

View File

@ -8,16 +8,17 @@ use std::path::Path;
use anyhow::Result; use anyhow::Result;
use itertools::Itertools; use itertools::Itertools;
use log::warn; use log::warn;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use ruff_diagnostics::{Diagnostic, Edit}; use ruff_diagnostics::{Diagnostic, Edit};
use ruff_python_trivia::{indentation_at_offset, CommentRanges}; use ruff_python_trivia::{indentation_at_offset, CommentRanges};
use ruff_source_file::{LineEnding, Locator}; use ruff_source_file::{LineEnding, LineRanges};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::codes::NoqaCode; use crate::codes::NoqaCode;
use crate::fs::relativize_path; use crate::fs::relativize_path;
use crate::registry::{AsRule, Rule, RuleSet}; use crate::registry::{AsRule, Rule, RuleSet};
use crate::rule_redirects::get_redirect_target; use crate::rule_redirects::get_redirect_target;
use crate::Locator;
/// Generates an array of edits that matches the length of `diagnostics`. /// Generates an array of edits that matches the length of `diagnostics`.
/// Each potential edit in the array is paired, in order, with the associated diagnostic. /// Each potential edit in the array is paired, in order, with the associated diagnostic.
@ -33,8 +34,7 @@ pub fn generate_noqa_edits(
noqa_line_for: &NoqaMapping, noqa_line_for: &NoqaMapping,
line_ending: LineEnding, line_ending: LineEnding,
) -> Vec<Option<Edit>> { ) -> Vec<Option<Edit>> {
let file_directives = let file_directives = FileNoqaDirectives::extract(locator, comment_ranges, external, path);
FileNoqaDirectives::extract(locator.contents(), comment_ranges, external, path, locator);
let exemption = FileExemption::from(&file_directives); let exemption = FileExemption::from(&file_directives);
let directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator); let directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator);
let comments = find_noqa_comments(diagnostics, locator, &exemption, &directives, noqa_line_for); let comments = find_noqa_comments(diagnostics, locator, &exemption, &directives, noqa_line_for);
@ -352,16 +352,15 @@ impl<'a> FileNoqaDirectives<'a> {
/// Extract the [`FileNoqaDirectives`] for a given Python source file, enumerating any rules /// Extract the [`FileNoqaDirectives`] for a given Python source file, enumerating any rules
/// that are globally ignored within the file. /// that are globally ignored within the file.
pub(crate) fn extract( pub(crate) fn extract(
contents: &'a str, locator: &Locator<'a>,
comment_ranges: &CommentRanges, comment_ranges: &CommentRanges,
external: &[String], external: &[String],
path: &Path, path: &Path,
locator: &Locator,
) -> Self { ) -> Self {
let mut lines = vec![]; let mut lines = vec![];
for range in comment_ranges { for range in comment_ranges {
match ParsedFileExemption::try_extract(&contents[range]) { match ParsedFileExemption::try_extract(&locator.contents()[range]) {
Err(err) => { Err(err) => {
#[allow(deprecated)] #[allow(deprecated)]
let line = locator.compute_line_index(range.start()); let line = locator.compute_line_index(range.start());
@ -369,7 +368,7 @@ impl<'a> FileNoqaDirectives<'a> {
warn!("Invalid `# ruff: noqa` directive at {path_display}:{line}: {err}"); warn!("Invalid `# ruff: noqa` directive at {path_display}:{line}: {err}");
} }
Ok(Some(exemption)) => { Ok(Some(exemption)) => {
if indentation_at_offset(range.start(), locator).is_none() { if indentation_at_offset(range.start(), locator.contents()).is_none() {
#[allow(deprecated)] #[allow(deprecated)]
let line = locator.compute_line_index(range.start()); let line = locator.compute_line_index(range.start());
let path_display = relativize_path(path); let path_display = relativize_path(path);
@ -619,8 +618,7 @@ fn add_noqa_inner(
let mut count = 0; let mut count = 0;
// Whether the file is exempted from all checks. // Whether the file is exempted from all checks.
let directives = let directives = FileNoqaDirectives::extract(locator, comment_ranges, external, path);
FileNoqaDirectives::extract(locator.contents(), comment_ranges, external, path, locator);
let exemption = FileExemption::from(&directives); let exemption = FileExemption::from(&directives);
let directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator); let directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator);
@ -1055,17 +1053,17 @@ mod tests {
use std::path::Path; use std::path::Path;
use insta::assert_debug_snapshot; use insta::assert_debug_snapshot;
use ruff_text_size::{TextRange, TextSize};
use ruff_diagnostics::{Diagnostic, Edit}; use ruff_diagnostics::{Diagnostic, Edit};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::{LineEnding, Locator}; use ruff_source_file::LineEnding;
use ruff_text_size::{TextRange, TextSize};
use crate::generate_noqa_edits;
use crate::noqa::{add_noqa_inner, Directive, NoqaMapping, ParsedFileExemption}; use crate::noqa::{add_noqa_inner, Directive, NoqaMapping, ParsedFileExemption};
use crate::rules::pycodestyle::rules::{AmbiguousVariableName, UselessSemicolon}; use crate::rules::pycodestyle::rules::{AmbiguousVariableName, UselessSemicolon};
use crate::rules::pyflakes::rules::UnusedVariable; use crate::rules::pyflakes::rules::UnusedVariable;
use crate::rules::pyupgrade::rules::PrintfStringFormatting; use crate::rules::pyupgrade::rules::PrintfStringFormatting;
use crate::{generate_noqa_edits, Locator};
#[test] #[test]
fn noqa_all() { fn noqa_all() {

View File

@ -1,10 +1,12 @@
use crate::settings::LinterSettings;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::{Locator, UniversalNewlineIterator}; use ruff_source_file::{LineRanges, UniversalNewlineIterator};
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use crate::settings::LinterSettings;
use crate::Locator;
use super::super::detection::comment_contains_code; use super::super::detection::comment_contains_code;
/// ## What it does /// ## What it does
@ -53,7 +55,7 @@ pub(crate) fn commented_out_code(
let mut comments = comment_ranges.into_iter().peekable(); let mut comments = comment_ranges.into_iter().peekable();
// Iterate over all comments in the document. // Iterate over all comments in the document.
while let Some(range) = comments.next() { while let Some(range) = comments.next() {
let line = locator.line(range.start()); let line = locator.line_str(range.start());
if is_script_tag_start(line) { if is_script_tag_start(line) {
if skip_script_comments(range, &mut comments, locator) { if skip_script_comments(range, &mut comments, locator) {
@ -176,11 +178,14 @@ fn is_script_tag_start(line: &str) -> bool {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::rules::eradicate::rules::commented_out_code::skip_script_comments;
use ruff_python_parser::parse_module; use ruff_python_parser::parse_module;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use crate::rules::eradicate::rules::commented_out_code::skip_script_comments;
use crate::Locator;
#[test] #[test]
fn script_comment() { fn script_comment() {
let code = r#" let code = r#"

View File

@ -6,10 +6,10 @@ use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::str::raw_contents; use ruff_python_ast::str::raw_contents;
use ruff_python_ast::{self as ast, Expr, Operator}; use ruff_python_ast::{self as ast, Expr, Operator};
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
static SQL_REGEX: LazyLock<Regex> = LazyLock::new(|| { static SQL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"(?i)\b(select\s+.*\s+from\s|delete\s+from\s|(insert|replace)\s+.*\s+values\s|update\s+.*\s+set\s)") Regex::new(r"(?i)\b(select\s+.*\s+from\s|delete\s+from\s|(insert|replace)\s+.*\s+values\s|update\s+.*\s+set\s)")

View File

@ -1,9 +1,10 @@
use ruff_notebook::CellOffsets; use ruff_notebook::CellOffsets;
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::Locator;
/// Return `true` if the statement containing the current expression is the last /// Return `true` if the statement containing the current expression is the last
/// top-level expression in the cell. This assumes that the source is a Jupyter /// top-level expression in the cell. This assumes that the source is a Jupyter
/// Notebook. /// Notebook.

View File

@ -1,11 +1,12 @@
use crate::fix::edits::pad;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private}; use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::fix::edits::pad;
/// ## What it does /// ## What it does
/// Checks for uses of `getattr` that take a constant attribute value as an /// Checks for uses of `getattr` that take a constant attribute value as an

View File

@ -9,10 +9,11 @@ use ruff_python_semantic::analyze::function_type::is_stub;
use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr}; use ruff_python_semantic::analyze::typing::{is_immutable_annotation, is_mutable_expr};
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_python_trivia::{indentation_at_offset, textwrap}; use ruff_python_trivia::{indentation_at_offset, textwrap};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for uses of mutable objects as function argument defaults. /// Checks for uses of mutable objects as function argument defaults.
@ -145,7 +146,7 @@ fn move_initialization(
// Avoid attempting to fix single-line functions. // Avoid attempting to fix single-line functions.
let statement = body.peek()?; let statement = body.peek()?;
if indexer.preceded_by_multi_statement_line(statement, locator) { if indexer.preceded_by_multi_statement_line(statement, locator.contents()) {
return None; return None;
} }
@ -170,7 +171,7 @@ fn move_initialization(
content.push_str(stylist.line_ending().as_str()); content.push_str(stylist.line_ending().as_str());
// Determine the indentation depth of the function body. // Determine the indentation depth of the function body.
let indentation = indentation_at_offset(statement.start(), locator)?; let indentation = indentation_at_offset(statement.start(), locator.contents())?;
// Indent the edit to match the body indentation. // Indent the edit to match the body indentation.
let mut content = textwrap::indent(&content, indentation).to_string(); let mut content = textwrap::indent(&content, indentation).to_string();
@ -186,7 +187,7 @@ fn move_initialization(
if let Some(next) = body.peek() { if let Some(next) = body.peek() {
// If there's a second statement, insert _before_ it, but ensure this isn't a // If there's a second statement, insert _before_ it, but ensure this isn't a
// multi-statement line. // multi-statement line.
if indexer.in_multi_statement_line(statement, locator) { if indexer.in_multi_statement_line(statement, locator.contents()) {
continue; continue;
} }
pos = locator.line_start(next.start()); pos = locator.line_start(next.start());

View File

@ -3,9 +3,10 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::{TokenKind, Tokens}; use ruff_python_parser::{TokenKind, Tokens};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::Locator;
/// Simplified token type. /// Simplified token type.
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
enum TokenType { enum TokenType {

View File

@ -14,13 +14,13 @@ use ruff_diagnostics::{Edit, Fix};
use ruff_python_ast::{self as ast, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::cst::helpers::{negate, space}; use crate::cst::helpers::{negate, space};
use crate::fix::codemods::CodegenStylist; use crate::fix::codemods::CodegenStylist;
use crate::fix::edits::pad; use crate::fix::edits::pad;
use crate::rules::flake8_comprehensions::rules::ObjectType; use crate::rules::flake8_comprehensions::rules::ObjectType;
use crate::Locator;
use crate::{ use crate::{
checkers::ast::Checker, checkers::ast::Checker,
cst::matchers::{ cst::matchers::{

View File

@ -1,9 +1,9 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_source_file::Locator;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for the absence of copyright notices within Python files. /// Checks for the absence of copyright notices within Python files.

View File

@ -1,14 +1,14 @@
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
use ruff_source_file::Locator;
use ruff_text_size::Ranged;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::whitespace; use ruff_python_ast::whitespace;
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_source_file::LineRanges;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::registry::Rule; use crate::registry::Rule;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for the use of string literals in exception constructors. /// Checks for the use of string literals in exception constructors.
@ -190,7 +190,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
let mut diagnostic = let mut diagnostic =
Diagnostic::new(RawStringInException, first.range()); Diagnostic::new(RawStringInException, first.range());
if let Some(indentation) = if let Some(indentation) =
whitespace::indentation(checker.locator(), stmt) whitespace::indentation(checker.source(), stmt)
{ {
diagnostic.set_fix(generate_fix( diagnostic.set_fix(generate_fix(
stmt, stmt,
@ -208,8 +208,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
Expr::FString(_) => { Expr::FString(_) => {
if checker.enabled(Rule::FStringInException) { if checker.enabled(Rule::FStringInException) {
let mut diagnostic = Diagnostic::new(FStringInException, first.range()); let mut diagnostic = Diagnostic::new(FStringInException, first.range());
if let Some(indentation) = whitespace::indentation(checker.locator(), stmt) if let Some(indentation) = whitespace::indentation(checker.source(), stmt) {
{
diagnostic.set_fix(generate_fix( diagnostic.set_fix(generate_fix(
stmt, stmt,
first, first,
@ -231,7 +230,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
let mut diagnostic = let mut diagnostic =
Diagnostic::new(DotFormatInException, first.range()); Diagnostic::new(DotFormatInException, first.range());
if let Some(indentation) = if let Some(indentation) =
whitespace::indentation(checker.locator(), stmt) whitespace::indentation(checker.source(), stmt)
{ {
diagnostic.set_fix(generate_fix( diagnostic.set_fix(generate_fix(
stmt, stmt,

View File

@ -1,17 +1,18 @@
use std::path::Path; use std::path::Path;
use crate::codes::Rule;
use crate::comments::shebang::ShebangDirective;
use crate::settings::LinterSettings;
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
pub(crate) use shebang_leading_whitespace::*; pub(crate) use shebang_leading_whitespace::*;
pub(crate) use shebang_missing_executable_file::*; pub(crate) use shebang_missing_executable_file::*;
pub(crate) use shebang_missing_python::*; pub(crate) use shebang_missing_python::*;
pub(crate) use shebang_not_executable::*; pub(crate) use shebang_not_executable::*;
pub(crate) use shebang_not_first_line::*; pub(crate) use shebang_not_first_line::*;
use crate::codes::Rule;
use crate::comments::shebang::ShebangDirective;
use crate::settings::LinterSettings;
use crate::Locator;
mod shebang_leading_whitespace; mod shebang_leading_whitespace;
mod shebang_missing_executable_file; mod shebang_missing_executable_file;
mod shebang_missing_python; mod shebang_missing_python;

View File

@ -1,9 +1,9 @@
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::Locator;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::is_python_whitespace; use ruff_python_trivia::is_python_whitespace;
use ruff_source_file::Locator;
/// ## What it does /// ## What it does
/// Checks for whitespace before a shebang directive. /// Checks for whitespace before a shebang directive.

View File

@ -1,9 +1,9 @@
use ruff_text_size::{TextRange, TextSize};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::is_python_whitespace; use ruff_python_trivia::is_python_whitespace;
use ruff_source_file::Locator; use ruff_text_size::{TextRange, TextSize};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for a shebang directive that is not at the beginning of the file. /// Checks for a shebang directive that is not at the beginning of the file.

View File

@ -1,11 +1,12 @@
use ruff_python_ast::{self as ast, Expr, Operator};
use crate::settings::LinterSettings;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_source_file::Locator; use ruff_python_ast::{self as ast, Expr, Operator};
use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::settings::LinterSettings;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for string literals that are explicitly concatenated (using the /// Checks for string literals that are explicitly concatenated (using the
/// `+` operator). /// `+` operator).

View File

@ -7,10 +7,11 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::str::{leading_quote, trailing_quote}; use ruff_python_ast::str::{leading_quote, trailing_quote};
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::{TokenKind, Tokens}; use ruff_python_parser::{TokenKind, Tokens};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for implicitly concatenated strings on a single line. /// Checks for implicitly concatenated strings on a single line.

View File

@ -65,7 +65,7 @@ pub(crate) fn unconventional_import_alias(
let qualified_name = import.qualified_name().to_string(); let qualified_name = import.qualified_name().to_string();
let expected_alias = conventions.get(qualified_name.as_str())?; let expected_alias = conventions.get(qualified_name.as_str())?;
let name = binding.name(checker.locator()); let name = binding.name(checker.source());
if name == expected_alias { if name == expected_alias {
return None; return None;
} }

View File

@ -4,11 +4,11 @@ use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::comments::shebang::ShebangDirective; use crate::comments::shebang::ShebangDirective;
use crate::fs; use crate::fs;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for packages that are missing an `__init__.py` file. /// Checks for packages that are missing an `__init__.py` file.

View File

@ -105,7 +105,7 @@ pub(crate) fn unnecessary_placeholder(checker: &mut Checker, body: &[Stmt]) {
}; };
let mut diagnostic = Diagnostic::new(UnnecessaryPlaceholder { kind }, stmt.range()); let mut diagnostic = Diagnostic::new(UnnecessaryPlaceholder { kind }, stmt.range());
let edit = if let Some(index) = trailing_comment_start_offset(stmt, checker.locator()) { let edit = if let Some(index) = trailing_comment_start_offset(stmt, checker.source()) {
Edit::range_deletion(stmt.range().add_end(index)) Edit::range_deletion(stmt.range().add_end(index))
} else { } else {
fix::edits::delete_stmt(stmt, None, checker.locator(), checker.indexer()) fix::edits::delete_stmt(stmt, None, checker.locator(), checker.indexer())

View File

@ -1,12 +1,11 @@
use ruff_python_ast::{self as ast, Expr};
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr};
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextSize}; use ruff_text_size::{Ranged, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for unnecessary dictionary unpacking operators (`**`). /// Checks for unnecessary dictionary unpacking operators (`**`).

View File

@ -1,11 +1,11 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, comparable::ComparableExpr}; use ruff_python_ast::{self as ast, comparable::ComparableExpr};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextSize}; use ruff_text_size::{Ranged, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::fix::snippet::SourceCodeSnippet; use crate::fix::snippet::SourceCodeSnippet;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for redundant `Final[Literal[...]]` annotations. /// Checks for redundant `Final[Literal[...]]` annotations.

View File

@ -5,13 +5,13 @@ use ruff_python_ast::{
self as ast, Expr, Operator, ParameterWithDefault, Parameters, Stmt, UnaryOp, self as ast, Expr, Operator, ParameterWithDefault, Parameters, Stmt, UnaryOp,
}; };
use ruff_python_semantic::{analyze::class::is_enumeration, ScopeKind, SemanticModel}; use ruff_python_semantic::{analyze::class::is_enumeration, ScopeKind, SemanticModel};
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::importer::ImportRequest; use crate::importer::ImportRequest;
use crate::rules::flake8_pyi::rules::TypingModule; use crate::rules::flake8_pyi::rules::TypingModule;
use crate::settings::types::PythonVersion; use crate::settings::types::PythonVersion;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for typed function arguments in stubs with complex default values. /// Checks for typed function arguments in stubs with complex default values.

View File

@ -1,10 +1,12 @@
use regex::Regex;
use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use std::sync::LazyLock; use std::sync::LazyLock;
use regex::Regex;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::CommentRanges;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for the use of type comments (e.g., `x = 1 # type: int`) in stub /// Checks for the use of type comments (e.g., `x = 1 # type: int`) in stub

View File

@ -73,7 +73,7 @@ pub(crate) fn unaliased_collections_abc_set_import(
return None; return None;
} }
let name = binding.name(checker.locator()); let name = binding.name(checker.source());
if name == "AbstractSet" { if name == "AbstractSet" {
return None; return None;
} }

View File

@ -17,7 +17,7 @@ use ruff_python_ast::{
}; };
use ruff_python_ast::{visitor, whitespace}; use ruff_python_ast::{visitor, whitespace};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -26,6 +26,7 @@ use crate::cst::matchers::match_indented_block;
use crate::cst::matchers::match_module; use crate::cst::matchers::match_module;
use crate::fix::codemods::CodegenStylist; use crate::fix::codemods::CodegenStylist;
use crate::importer::ImportRequest; use crate::importer::ImportRequest;
use crate::Locator;
use super::unittest_assert::UnittestAssert; use super::unittest_assert::UnittestAssert;
@ -386,7 +387,7 @@ pub(crate) fn unittest_raises_assertion(
); );
if !checker if !checker
.comment_ranges() .comment_ranges()
.has_comments(call, checker.locator()) .has_comments(call, checker.source())
{ {
if let Some(args) = to_pytest_raises_args(checker, attr.as_str(), &call.arguments) { if let Some(args) = to_pytest_raises_args(checker, attr.as_str(), &call.arguments) {
diagnostic.try_set_fix(|| { diagnostic.try_set_fix(|| {
@ -622,11 +623,11 @@ fn parenthesize<'a>(expression: &Expression<'a>, parent: &Expression<'a>) -> Exp
/// `assert a == "hello"` and `assert b == "world"`. /// `assert a == "hello"` and `assert b == "world"`.
fn fix_composite_condition(stmt: &Stmt, locator: &Locator, stylist: &Stylist) -> Result<Edit> { fn fix_composite_condition(stmt: &Stmt, locator: &Locator, stylist: &Stylist) -> Result<Edit> {
// Infer the indentation of the outer block. // Infer the indentation of the outer block.
let outer_indent = let outer_indent = whitespace::indentation(locator.contents(), stmt)
whitespace::indentation(locator, stmt).context("Unable to fix multiline statement")?; .context("Unable to fix multiline statement")?;
// Extract the module text. // Extract the module text.
let contents = locator.lines(stmt.range()); let contents = locator.lines_str(stmt.range());
// If the block is indented, "embed" it in a function definition, to preserve // If the block is indented, "embed" it in a function definition, to preserve
// indentation while retaining valid source code. (We'll strip the prefix later // indentation while retaining valid source code. (We'll strip the prefix later
@ -747,7 +748,7 @@ pub(crate) fn composite_condition(
&& !checker.comment_ranges().intersects(stmt.range()) && !checker.comment_ranges().intersects(stmt.range())
&& !checker && !checker
.indexer() .indexer()
.in_multi_statement_line(stmt, checker.locator()) .in_multi_statement_line(stmt, checker.source())
{ {
diagnostic.try_set_fix(|| { diagnostic.try_set_fix(|| {
fix_composite_condition(stmt, checker.locator(), checker.stylist()) fix_composite_condition(stmt, checker.locator(), checker.stylist())

View File

@ -9,6 +9,7 @@ use ruff_python_ast::Decorator;
use ruff_python_ast::{self as ast, Expr, Parameters, Stmt}; use ruff_python_ast::{self as ast, Expr, Parameters, Stmt};
use ruff_python_semantic::analyze::visibility::is_abstract; use ruff_python_semantic::analyze::visibility::is_abstract;
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use ruff_text_size::{TextLen, TextRange}; use ruff_text_size::{TextLen, TextRange};

View File

@ -1,16 +1,15 @@
use flake8_quotes::helpers::{contains_escaped_quote, raw_contents, unescape_string};
use flake8_quotes::settings::Quote;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::visitor::{walk_f_string, Visitor}; use ruff_python_ast::visitor::{walk_f_string, Visitor};
use ruff_python_ast::{self as ast, AnyStringFlags, StringFlags, StringLike}; use ruff_python_ast::{self as ast, AnyStringFlags, StringFlags, StringLike};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::rules::flake8_quotes; use crate::rules::flake8_quotes;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
use flake8_quotes::helpers::{contains_escaped_quote, raw_contents, unescape_string};
use flake8_quotes::settings::Quote;
/// ## What it does /// ## What it does
/// Checks for strings that include escaped quotes, and suggests changing /// Checks for strings that include escaped quotes, and suggests changing

View File

@ -1,11 +1,11 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::StringLike; use ruff_python_ast::StringLike;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::registry::Rule; use crate::registry::Rule;
use crate::Locator;
use super::super::settings::Quote; use super::super::settings::Quote;

View File

@ -1,10 +1,10 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, AnyStringFlags, StringFlags, StringLike}; use ruff_python_ast::{self as ast, AnyStringFlags, StringFlags, StringLike};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
use super::super::helpers::{contains_escaped_quote, raw_contents, unescape_string}; use super::super::helpers::{contains_escaped_quote, raw_contents, unescape_string};

View File

@ -1,8 +1,9 @@
use ruff_python_ast as ast; use ruff_python_ast as ast;
use ruff_python_ast::Stmt; use ruff_python_ast::Stmt;
use ruff_source_file::UniversalNewlines;
use ruff_text_size::{Ranged, TextSize}; use ruff_text_size::{Ranged, TextSize};
use ruff_source_file::{Locator, UniversalNewlines}; use crate::Locator;
/// Return `true` if a function's return statement include at least one /// Return `true` if a function's return statement include at least one
/// non-`None` value. /// non-`None` value.

View File

@ -15,7 +15,7 @@ use ruff_python_index::Indexer;
use ruff_python_semantic::analyze::visibility::is_property; use ruff_python_semantic::analyze::visibility::is_property;
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_python_trivia::{is_python_whitespace, SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{is_python_whitespace, SimpleTokenKind, SimpleTokenizer};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -23,6 +23,7 @@ use crate::fix::edits;
use crate::fix::edits::adjust_indentation; use crate::fix::edits::adjust_indentation;
use crate::registry::{AsRule, Rule}; use crate::registry::{AsRule, Rule};
use crate::rules::flake8_return::helpers::end_of_last_statement; use crate::rules::flake8_return::helpers::end_of_last_statement;
use crate::Locator;
use super::super::branch::Branch; use super::super::branch::Branch;
use super::super::helpers::result_exists; use super::super::helpers::result_exists;
@ -453,7 +454,7 @@ fn is_noreturn_func(func: &Expr, semantic: &SemanticModel) -> bool {
fn add_return_none(checker: &mut Checker, stmt: &Stmt, range: TextRange) { fn add_return_none(checker: &mut Checker, stmt: &Stmt, range: TextRange) {
let mut diagnostic = Diagnostic::new(ImplicitReturn, range); let mut diagnostic = Diagnostic::new(ImplicitReturn, range);
if let Some(indent) = indentation(checker.locator(), stmt) { if let Some(indent) = indentation(checker.source(), stmt) {
let mut content = String::new(); let mut content = String::new();
content.push_str(checker.stylist().line_ending().as_str()); content.push_str(checker.stylist().line_ending().as_str());
content.push_str(indent); content.push_str(indent);
@ -851,14 +852,14 @@ fn remove_else(
}; };
// get the indentation of the `else`, since that is the indent level we want to end with // get the indentation of the `else`, since that is the indent level we want to end with
let Some(desired_indentation) = indentation(locator, elif_else) else { let Some(desired_indentation) = indentation(locator.contents(), elif_else) else {
return Err(anyhow::anyhow!("Compound statement cannot be inlined")); return Err(anyhow::anyhow!("Compound statement cannot be inlined"));
}; };
// If the statement is on the same line as the `else`, just remove the `else: `. // If the statement is on the same line as the `else`, just remove the `else: `.
// Ex) `else: return True` -> `return True` // Ex) `else: return True` -> `return True`
if let Some(first) = elif_else.body.first() { if let Some(first) = elif_else.body.first() {
if indexer.preceded_by_multi_statement_line(first, locator) { if indexer.preceded_by_multi_statement_line(first, locator.contents()) {
return Ok(Fix::safe_edit(Edit::deletion( return Ok(Fix::safe_edit(Edit::deletion(
elif_else.start(), elif_else.start(),
first.start(), first.start(),

View File

@ -536,7 +536,7 @@ pub(crate) fn compare_with_tuple(checker: &mut Checker, expr: &Expr) {
// Avoid removing comments. // Avoid removing comments.
if checker if checker
.comment_ranges() .comment_ranges()
.has_comments(expr, checker.locator()) .has_comments(expr, checker.source())
{ {
continue; continue;
} }

View File

@ -11,7 +11,7 @@ use ruff_python_ast::{self as ast, whitespace, ElifElseClause, Expr, Stmt};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block}; use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block};
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -19,6 +19,7 @@ use crate::cst::helpers::space;
use crate::cst::matchers::{match_function_def, match_if, match_indented_block, match_statement}; use crate::cst::matchers::{match_function_def, match_if, match_indented_block, match_statement};
use crate::fix::codemods::CodegenStylist; use crate::fix::codemods::CodegenStylist;
use crate::fix::edits::fits; use crate::fix::edits::fits;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for nested `if` statements that can be collapsed into a single `if` /// Checks for nested `if` statements that can be collapsed into a single `if`
@ -292,12 +293,12 @@ pub(super) fn collapse_nested_if(
nested_if: NestedIf, nested_if: NestedIf,
) -> Result<Edit> { ) -> Result<Edit> {
// Infer the indentation of the outer block. // Infer the indentation of the outer block.
let Some(outer_indent) = whitespace::indentation(locator, &nested_if) else { let Some(outer_indent) = whitespace::indentation(locator.contents(), &nested_if) else {
bail!("Unable to fix multiline statement"); bail!("Unable to fix multiline statement");
}; };
// Extract the module text. // Extract the module text.
let contents = locator.lines(nested_if.range()); let contents = locator.lines_str(nested_if.range());
// If this is an `elif`, we have to remove the `elif` keyword for now. (We'll // If this is an `elif`, we have to remove the `elif` keyword for now. (We'll
// restore the `el` later on.) // restore the `el` later on.)

View File

@ -5,11 +5,12 @@ use ruff_diagnostics::Edit;
use ruff_python_ast as ast; use ruff_python_ast as ast;
use ruff_python_ast::whitespace; use ruff_python_ast::whitespace;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::cst::matchers::{match_function_def, match_indented_block, match_statement, match_with}; use crate::cst::matchers::{match_function_def, match_indented_block, match_statement, match_with};
use crate::fix::codemods::CodegenStylist; use crate::fix::codemods::CodegenStylist;
use crate::Locator;
/// (SIM117) Convert `with a: with b:` to `with a, b:`. /// (SIM117) Convert `with a: with b:` to `with a, b:`.
pub(crate) fn fix_multiple_with_statements( pub(crate) fn fix_multiple_with_statements(
@ -18,12 +19,12 @@ pub(crate) fn fix_multiple_with_statements(
with_stmt: &ast::StmtWith, with_stmt: &ast::StmtWith,
) -> Result<Edit> { ) -> Result<Edit> {
// Infer the indentation of the outer block. // Infer the indentation of the outer block.
let Some(outer_indent) = whitespace::indentation(locator, with_stmt) else { let Some(outer_indent) = whitespace::indentation(locator.contents(), with_stmt) else {
bail!("Unable to fix multiline statement"); bail!("Unable to fix multiline statement");
}; };
// Extract the module text. // Extract the module text.
let contents = locator.lines(with_stmt.range()); let contents = locator.lines_str(with_stmt.range());
// If the block is indented, "embed" it in a function definition, to preserve // If the block is indented, "embed" it in a function definition, to preserve
// indentation while retaining valid source code. (We'll strip the prefix later // indentation while retaining valid source code. (We'll strip the prefix later

View File

@ -211,7 +211,7 @@ pub(crate) fn if_else_block_instead_of_dict_get(checker: &mut Checker, stmt_if:
); );
if !checker if !checker
.comment_ranges() .comment_ranges()
.has_comments(stmt_if, checker.locator()) .has_comments(stmt_if, checker.source())
{ {
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
contents, contents,
@ -300,7 +300,7 @@ pub(crate) fn if_exp_instead_of_dict_get(
); );
if !checker if !checker
.comment_ranges() .comment_ranges()
.has_comments(expr, checker.locator()) .has_comments(expr, checker.source())
{ {
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
contents, contents,

View File

@ -227,7 +227,7 @@ pub(crate) fn if_else_block_instead_of_if_exp(checker: &mut Checker, stmt_if: &a
); );
if !checker if !checker
.comment_ranges() .comment_ranges()
.has_comments(stmt_if, checker.locator()) .has_comments(stmt_if, checker.source())
{ {
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
contents, contents,

View File

@ -9,10 +9,11 @@ use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::stmt_if::{if_elif_branches, IfElifBranch}; use ruff_python_ast::stmt_if::{if_elif_branches, IfElifBranch};
use ruff_python_ast::{self as ast, Expr}; use ruff_python_ast::{self as ast, Expr};
use ruff_python_trivia::{CommentRanges, SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{CommentRanges, SimpleTokenKind, SimpleTokenizer};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for `if` branches with identical arm bodies. /// Checks for `if` branches with identical arm bodies.

View File

@ -200,7 +200,7 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
// Generate the replacement condition. // Generate the replacement condition.
let condition = if checker let condition = if checker
.comment_ranges() .comment_ranges()
.has_comments(&range, checker.locator()) .has_comments(&range, checker.source())
{ {
None None
} else { } else {

View File

@ -7,6 +7,7 @@ use ruff_python_ast::{
self as ast, Arguments, CmpOp, Comprehension, Expr, ExprContext, Stmt, UnaryOp, self as ast, Arguments, CmpOp, Comprehension, Expr, ExprContext, Stmt, UnaryOp,
}; };
use ruff_python_codegen::Generator; use ruff_python_codegen::Generator;
use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;

View File

@ -3,6 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers; use ruff_python_ast::helpers;
use ruff_python_ast::name::UnqualifiedName; use ruff_python_ast::name::UnqualifiedName;
use ruff_python_ast::{self as ast, ExceptHandler, Stmt}; use ruff_python_ast::{self as ast, ExceptHandler, Stmt};
use ruff_source_file::LineRanges;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use ruff_text_size::{TextLen, TextRange}; use ruff_text_size::{TextLen, TextRange};
@ -127,7 +128,7 @@ pub(crate) fn suppressible_exception(
); );
if !checker if !checker
.comment_ranges() .comment_ranges()
.has_comments(stmt, checker.locator()) .has_comments(stmt, checker.source())
{ {
diagnostic.try_set_fix(|| { diagnostic.try_set_fix(|| {
// let range = statement_range(stmt, checker.locator(), checker.indexer()); // let range = statement_range(stmt, checker.locator(), checker.indexer());

View File

@ -8,7 +8,6 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, CmpOp, Expr, UnaryOp}; use ruff_python_ast::{self as ast, CmpOp, Expr, UnaryOp};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_stdlib::str::{self}; use ruff_python_stdlib::str::{self};
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -16,6 +15,7 @@ use crate::cst::helpers::or_space;
use crate::cst::matchers::{match_comparison, transform_expression}; use crate::cst::matchers::{match_comparison, transform_expression};
use crate::fix::edits::pad; use crate::fix::edits::pad;
use crate::fix::snippet::SourceCodeSnippet; use crate::fix::snippet::SourceCodeSnippet;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for conditions that position a constant on the left-hand side of the /// Checks for conditions that position a constant on the left-hand side of the

View File

@ -1,13 +1,14 @@
use regex::RegexSet;
use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use ruff_text_size::{TextLen, TextRange, TextSize};
use std::sync::LazyLock; use std::sync::LazyLock;
use regex::RegexSet;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::CommentRanges;
use ruff_text_size::{TextLen, TextRange, TextSize};
use crate::directives::{TodoComment, TodoDirective, TodoDirectiveKind}; use crate::directives::{TodoComment, TodoDirective, TodoDirectiveKind};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks that a TODO comment is labelled with "TODO". /// Checks that a TODO comment is labelled with "TODO".

View File

@ -1,8 +1,9 @@
use ruff_python_ast::{self as ast, Stmt}; use ruff_python_ast::{self as ast, Stmt};
use ruff_python_parser::Tokens; use ruff_python_parser::Tokens;
use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use ruff_source_file::Locator; use crate::Locator;
use super::comments::Comment; use super::comments::Comment;
use super::helpers::trailing_comma; use super::helpers::trailing_comma;

View File

@ -4,11 +4,11 @@ use std::slice;
use ruff_notebook::CellOffsets; use ruff_notebook::CellOffsets;
use ruff_python_ast::statement_visitor::StatementVisitor; use ruff_python_ast::statement_visitor::StatementVisitor;
use ruff_python_ast::{self as ast, ElifElseClause, ExceptHandler, MatchCase, Stmt}; use ruff_python_ast::{self as ast, ElifElseClause, ExceptHandler, MatchCase, Stmt};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::directives::IsortDirectives; use crate::directives::IsortDirectives;
use crate::rules::isort::helpers; use crate::rules::isort::helpers;
use crate::Locator;
/// A block of imports within a Python module. /// A block of imports within a Python module.
#[derive(Debug, Default)] #[derive(Debug, Default)]

View File

@ -1,9 +1,10 @@
use std::borrow::Cow; use std::borrow::Cow;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::Locator;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Comment<'a> { pub(crate) struct Comment<'a> {
pub(crate) value: Cow<'a, str>, pub(crate) value: Cow<'a, str>,

View File

@ -1,10 +1,11 @@
use ruff_python_ast::Stmt; use ruff_python_ast::Stmt;
use ruff_python_parser::{TokenKind, Tokens}; use ruff_python_parser::{TokenKind, Tokens};
use ruff_python_trivia::PythonWhitespace; use ruff_python_trivia::PythonWhitespace;
use ruff_source_file::{Locator, UniversalNewlines}; use ruff_source_file::UniversalNewlines;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::rules::isort::types::TrailingComma; use crate::rules::isort::types::TrailingComma;
use crate::Locator;
/// Return `true` if a `Stmt::ImportFrom` statement ends with a magic /// Return `true` if a `Stmt::ImportFrom` statement ends with a magic
/// trailing comma. /// trailing comma.

View File

@ -13,13 +13,13 @@ use order::order_imports;
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_parser::Tokens; use ruff_python_parser::Tokens;
use ruff_source_file::Locator;
use settings::Settings; use settings::Settings;
use types::EitherImport::{Import, ImportFrom}; use types::EitherImport::{Import, ImportFrom};
use types::{AliasData, ImportBlock, TrailingComma}; use types::{AliasData, ImportBlock, TrailingComma};
use crate::line_width::{LineLength, LineWidthBuilder}; use crate::line_width::{LineLength, LineWidthBuilder};
use crate::settings::types::PythonVersion; use crate::settings::types::PythonVersion;
use crate::Locator;
mod annotate; mod annotate;
pub(crate) mod block; pub(crate) mod block;
@ -282,11 +282,12 @@ mod tests {
use std::path::Path; use std::path::Path;
use anyhow::Result; use anyhow::Result;
use ruff_python_semantic::{MemberNameImport, ModuleNameImport, NameImport};
use ruff_text_size::Ranged;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use test_case::test_case; use test_case::test_case;
use ruff_python_semantic::{MemberNameImport, ModuleNameImport, NameImport};
use ruff_text_size::Ranged;
use crate::assert_messages; use crate::assert_messages;
use crate::registry::Rule; use crate::registry::Rule;
use crate::rules::isort::categorize::{ImportSection, KnownModules}; use crate::rules::isort::categorize::{ImportSection, KnownModules};

View File

@ -5,12 +5,11 @@ use ruff_python_ast::{self as ast, ModModule, PySourceType, Stmt};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_parser::Parsed; use ruff_python_parser::Parsed;
use ruff_python_semantic::{FutureImport, NameImport}; use ruff_python_semantic::{FutureImport, NameImport};
use ruff_source_file::Locator;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::importer::Importer; use crate::importer::Importer;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
/// ## What it does /// ## What it does
/// Adds any required imports, as specified by the user, to the top of the /// Adds any required imports, as specified by the user, to the top of the

View File

@ -10,12 +10,12 @@ use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::Tokens; use ruff_python_parser::Tokens;
use ruff_python_trivia::{leading_indentation, textwrap::indent, PythonWhitespace}; use ruff_python_trivia::{leading_indentation, textwrap::indent, PythonWhitespace};
use ruff_source_file::{Locator, UniversalNewlines}; use ruff_source_file::{LineRanges, UniversalNewlines};
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::line_width::LineWidthBuilder; use crate::line_width::LineWidthBuilder;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
use super::super::block::Block; use super::super::block::Block;
use super::super::{comments, format_imports}; use super::super::{comments, format_imports};
@ -98,8 +98,9 @@ pub(crate) fn organize_imports(
// Special-cases: there's leading or trailing content in the import block. These // Special-cases: there's leading or trailing content in the import block. These
// are too hard to get right, and relatively rare, so flag but don't fix. // are too hard to get right, and relatively rare, so flag but don't fix.
if indexer.preceded_by_multi_statement_line(block.imports.first().unwrap(), locator) if indexer.preceded_by_multi_statement_line(block.imports.first().unwrap(), locator.contents())
|| indexer.followed_by_multi_statement_line(block.imports.last().unwrap(), locator) || indexer
.followed_by_multi_statement_line(block.imports.last().unwrap(), locator.contents())
{ {
return Some(Diagnostic::new(UnsortedImports, range)); return Some(Diagnostic::new(UnsortedImports, range));
} }
@ -114,7 +115,7 @@ pub(crate) fn organize_imports(
let trailing_line_end = if block.trailer.is_none() { let trailing_line_end = if block.trailer.is_none() {
locator.full_line_end(range.end()) locator.full_line_end(range.end())
} else { } else {
trailing_lines_end(block.imports.last().unwrap(), locator) trailing_lines_end(block.imports.last().unwrap(), locator.contents())
}; };
// Generate the sorted import block. // Generate the sorted import block.

View File

@ -4,11 +4,11 @@ use ruff_python_ast::helpers::is_const_true;
use ruff_python_ast::parenthesize::parenthesized_range; use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::{self as ast, Keyword, Stmt}; use ruff_python_ast::{self as ast, Keyword, Stmt};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::fix::edits::{remove_argument, Parentheses}; use crate::fix::edits::{remove_argument, Parentheses};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for `inplace=True` usages in `pandas` function and method /// Checks for `inplace=True` usages in `pandas` function and method

View File

@ -1,9 +1,9 @@
use ruff_python_ast::{self as ast, ExceptHandler, Expr, Stmt};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::identifier::except; use ruff_python_ast::identifier::except;
use ruff_source_file::Locator; use ruff_python_ast::{self as ast, ExceptHandler, Expr, Stmt};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for bare `except` catches in `try`-`except` statements. /// Checks for bare `except` catches in `try`-`except` statements.

View File

@ -1,28 +1,30 @@
use itertools::Itertools;
use ruff_notebook::CellOffsets;
use ruff_python_parser::TokenIterWithContext;
use ruff_python_parser::Tokens;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::iter::Peekable; use std::iter::Peekable;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::slice::Iter; use std::slice::Iter;
use itertools::Itertools;
use ruff_diagnostics::AlwaysFixableViolation; use ruff_diagnostics::AlwaysFixableViolation;
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::Edit; use ruff_diagnostics::Edit;
use ruff_diagnostics::Fix; use ruff_diagnostics::Fix;
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_notebook::CellOffsets;
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_parser::TokenIterWithContext;
use ruff_python_parser::TokenKind; use ruff_python_parser::TokenKind;
use ruff_python_parser::Tokens;
use ruff_python_trivia::PythonWhitespace; use ruff_python_trivia::PythonWhitespace;
use ruff_source_file::{Locator, UniversalNewlines}; use ruff_source_file::{LineRanges, UniversalNewlines};
use ruff_text_size::TextRange; use ruff_text_size::TextRange;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use crate::checkers::logical_lines::expand_indent; use crate::checkers::logical_lines::expand_indent;
use crate::line_width::IndentWidth; use crate::line_width::IndentWidth;
use crate::rules::pycodestyle::helpers::is_non_logical_token; use crate::rules::pycodestyle::helpers::is_non_logical_token;
use crate::Locator;
/// Number of blank lines around top level classes and functions. /// Number of blank lines around top level classes and functions.
const BLANK_LINES_TOP_LEVEL: u32 = 2; const BLANK_LINES_TOP_LEVEL: u32 = 2;

View File

@ -1,13 +1,13 @@
use ruff_notebook::CellOffsets;
use ruff_python_ast::PySourceType;
use ruff_python_parser::{TokenIterWithContext, TokenKind, Tokens};
use ruff_text_size::{Ranged, TextSize};
use ruff_diagnostics::{AlwaysFixableViolation, Violation}; use ruff_diagnostics::{AlwaysFixableViolation, Violation};
use ruff_diagnostics::{Diagnostic, Edit, Fix}; use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_notebook::CellOffsets;
use ruff_python_ast::PySourceType;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_source_file::Locator; use ruff_python_parser::{TokenIterWithContext, TokenKind, Tokens};
use ruff_text_size::{Ranged, TextSize};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for compound statements (multiple statements on the same line). /// Checks for compound statements (multiple statements on the same line).
@ -170,7 +170,7 @@ pub(crate) fn compound_statements(
let mut diagnostic = Diagnostic::new(UselessSemicolon, range); let mut diagnostic = Diagnostic::new(UselessSemicolon, range);
diagnostic.set_fix(Fix::safe_edit(Edit::deletion( diagnostic.set_fix(Fix::safe_edit(Edit::deletion(
indexer indexer
.preceded_by_continuations(range.start(), locator) .preceded_by_continuations(range.start(), locator.contents())
.unwrap_or(range.start()), .unwrap_or(range.start()),
range.end(), range.end(),
))); )));

View File

@ -3,11 +3,11 @@ use memchr::memchr_iter;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{AnyStringFlags, FStringElement, StringLike, StringLikePart}; use ruff_python_ast::{AnyStringFlags, FStringElement, StringLike, StringLikePart};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::fix::edits::pad_start; use crate::fix::edits::pad_start;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for invalid escape sequences. /// Checks for invalid escape sequences.

View File

@ -79,10 +79,10 @@ pub(crate) fn lambda_assignment(
stmt.range(), stmt.range(),
); );
if !has_leading_content(stmt.start(), checker.locator()) if !has_leading_content(stmt.start(), checker.source())
&& !has_trailing_content(stmt.end(), checker.locator()) && !has_trailing_content(stmt.end(), checker.source())
{ {
let first_line = checker.locator().line(stmt.start()); let first_line = checker.locator().line_str(stmt.start());
let indentation = leading_indentation(first_line); let indentation = leading_indentation(first_line);
let mut indented = String::new(); let mut indented = String::new();
for (idx, line) in function( for (idx, line) in function(

View File

@ -336,7 +336,7 @@ pub(crate) fn literal_comparisons(checker: &mut Checker, compare: &ast::ExprComp
&compare.comparators, &compare.comparators,
compare.into(), compare.into(),
checker.comment_ranges(), checker.comment_ranges(),
checker.locator(), checker.source(),
); );
for diagnostic in &mut diagnostics { for diagnostic in &mut diagnostics {
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(

View File

@ -1,26 +1,25 @@
use std::fmt::{Debug, Formatter};
use std::iter::FusedIterator;
use bitflags::bitflags;
pub(crate) use extraneous_whitespace::*; pub(crate) use extraneous_whitespace::*;
pub(crate) use indentation::*; pub(crate) use indentation::*;
pub(crate) use missing_whitespace::*; pub(crate) use missing_whitespace::*;
pub(crate) use missing_whitespace_after_keyword::*; pub(crate) use missing_whitespace_after_keyword::*;
pub(crate) use missing_whitespace_around_operator::*; pub(crate) use missing_whitespace_around_operator::*;
pub(crate) use redundant_backslash::*; pub(crate) use redundant_backslash::*;
use ruff_python_parser::{TokenKind, Tokens};
use ruff_python_trivia::is_python_whitespace;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
pub(crate) use space_around_operator::*; pub(crate) use space_around_operator::*;
pub(crate) use whitespace_around_keywords::*; pub(crate) use whitespace_around_keywords::*;
pub(crate) use whitespace_around_named_parameter_equals::*; pub(crate) use whitespace_around_named_parameter_equals::*;
pub(crate) use whitespace_before_comment::*; pub(crate) use whitespace_before_comment::*;
pub(crate) use whitespace_before_parameters::*; pub(crate) use whitespace_before_parameters::*;
use std::fmt::{Debug, Formatter};
use std::iter::FusedIterator;
use bitflags::bitflags;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use ruff_python_parser::{TokenKind, Tokens};
use ruff_python_trivia::is_python_whitespace;
use ruff_source_file::Locator;
use crate::rules::pycodestyle::helpers::is_non_logical_token; use crate::rules::pycodestyle::helpers::is_non_logical_token;
use crate::Locator;
mod extraneous_whitespace; mod extraneous_whitespace;
mod indentation; mod indentation;
@ -579,7 +578,8 @@ impl TypeParamsState {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruff_python_parser::parse_module; use ruff_python_parser::parse_module;
use ruff_source_file::Locator;
use crate::Locator;
use super::LogicalLines; use super::LogicalLines;

View File

@ -2,10 +2,11 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_parser::TokenKind; use ruff_python_parser::TokenKind;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::logical_lines::LogicalLinesContext; use crate::checkers::logical_lines::LogicalLinesContext;
use crate::Locator;
use super::LogicalLine; use super::LogicalLine;

View File

@ -2,11 +2,12 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_parser::TokenKind; use ruff_python_parser::TokenKind;
use ruff_python_trivia::PythonWhitespace; use ruff_python_trivia::PythonWhitespace;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::checkers::logical_lines::LogicalLinesContext; use crate::checkers::logical_lines::LogicalLinesContext;
use crate::rules::pycodestyle::rules::logical_lines::LogicalLine; use crate::rules::pycodestyle::rules::logical_lines::LogicalLine;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks if inline comments are separated by at least two spaces. /// Checks if inline comments are separated by at least two spaces.

View File

@ -1,9 +1,9 @@
use ruff_text_size::{TextLen, TextRange};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_source_file::Locator; use ruff_text_size::{TextLen, TextRange};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for files missing a new line at the end of the file. /// Checks for files missing a new line at the end of the file.

View File

@ -6,10 +6,11 @@ use ruff_python_ast::{Alias, Stmt};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_trivia::indentation_at_offset; use ruff_python_trivia::indentation_at_offset;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
/// ## What it does /// ## What it does
/// Check for multiple imports on one line. /// Check for multiple imports on one line.
@ -68,7 +69,7 @@ fn split_imports(
indexer: &Indexer, indexer: &Indexer,
stylist: &Stylist, stylist: &Stylist,
) -> Fix { ) -> Fix {
if indexer.in_multi_statement_line(stmt, locator) { if indexer.in_multi_statement_line(stmt, locator.contents()) {
// Ex) `x = 1; import os, sys` (convert to `x = 1; import os; import sys`) // Ex) `x = 1; import os, sys` (convert to `x = 1; import os; import sys`)
let replacement = names let replacement = names
.iter() .iter()
@ -90,7 +91,8 @@ fn split_imports(
Fix::safe_edit(Edit::range_replacement(replacement, stmt.range())) Fix::safe_edit(Edit::range_replacement(replacement, stmt.range()))
} else { } else {
// Ex) `import os, sys` (convert to `import os\nimport sys`) // Ex) `import os, sys` (convert to `import os\nimport sys`)
let indentation = indentation_at_offset(stmt.start(), locator).unwrap_or_default(); let indentation =
indentation_at_offset(stmt.start(), locator.contents()).unwrap_or_default();
// Generate newline-delimited imports. // Generate newline-delimited imports.
let replacement = names let replacement = names

View File

@ -105,7 +105,7 @@ pub(crate) fn not_tests(checker: &mut Checker, unary_op: &ast::ExprUnaryOp) {
comparators, comparators,
unary_op.into(), unary_op.into(),
checker.comment_ranges(), checker.comment_ranges(),
checker.locator(), checker.source(),
), ),
unary_op.range(), unary_op.range(),
checker.locator(), checker.locator(),
@ -126,7 +126,7 @@ pub(crate) fn not_tests(checker: &mut Checker, unary_op: &ast::ExprUnaryOp) {
comparators, comparators,
unary_op.into(), unary_op.into(),
checker.comment_ranges(), checker.comment_ranges(),
checker.locator(), checker.source(),
), ),
unary_op.range(), unary_op.range(),
checker.locator(), checker.locator(),

View File

@ -1,9 +1,11 @@
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for indentation that uses tabs. /// Checks for indentation that uses tabs.
/// ///

View File

@ -1,11 +1,12 @@
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_source_file::{Line, Locator}; use ruff_source_file::Line;
use ruff_text_size::{TextLen, TextRange, TextSize}; use ruff_text_size::{TextLen, TextRange, TextSize};
use crate::registry::Rule; use crate::registry::Rule;
use crate::settings::LinterSettings; use crate::settings::LinterSettings;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for superfluous trailing whitespace. /// Checks for superfluous trailing whitespace.
@ -100,7 +101,7 @@ pub(crate) fn trailing_whitespace(
diagnostic.set_fix(Fix::applicable_edit( diagnostic.set_fix(Fix::applicable_edit(
Edit::range_deletion(TextRange::new( Edit::range_deletion(TextRange::new(
indexer indexer
.preceded_by_continuations(line.start(), locator) .preceded_by_continuations(line.start(), locator.contents())
.unwrap_or(range.start()), .unwrap_or(range.start()),
range.end(), range.end(),
)), )),

View File

@ -1,7 +1,7 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::{indentation_at_offset, PythonWhitespace}; use ruff_python_trivia::{indentation_at_offset, PythonWhitespace};
use ruff_source_file::{Line, UniversalNewlineIterator}; use ruff_source_file::{Line, LineRanges, UniversalNewlineIterator};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use ruff_text_size::{TextLen, TextRange}; use ruff_text_size::{TextLen, TextRange};
@ -240,7 +240,7 @@ pub(crate) fn blank_before_after_class(checker: &mut Checker, docstring: &Docstr
if let Some(first_line) = &first_line { if let Some(first_line) = &first_line {
let trailing = first_line.as_str().trim_whitespace_start(); let trailing = first_line.as_str().trim_whitespace_start();
if let Some(next_statement) = trailing.strip_prefix(';') { if let Some(next_statement) = trailing.strip_prefix(';') {
let indentation = indentation_at_offset(docstring.start(), checker.locator()) let indentation = indentation_at_offset(docstring.start(), checker.source())
.expect("Own line docstring must have indentation"); .expect("Own line docstring must have indentation");
let mut diagnostic = Diagnostic::new(OneBlankLineAfterClass, docstring.range()); let mut diagnostic = Diagnostic::new(OneBlankLineAfterClass, docstring.range());
let line_ending = checker.stylist().line_ending().as_str(); let line_ending = checker.stylist().line_ending().as_str();

View File

@ -2,7 +2,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::str::{is_triple_quote, leading_quote}; use ruff_python_ast::str::{is_triple_quote, leading_quote};
use ruff_python_semantic::Definition; use ruff_python_semantic::Definition;
use ruff_source_file::{NewlineWithTrailingNewline, UniversalNewlineIterator}; use ruff_source_file::{LineRanges, NewlineWithTrailingNewline, UniversalNewlineIterator};
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;

View File

@ -1464,7 +1464,7 @@ fn blanks_and_section_underline(
// Otherwise, documentation generators will not recognize the directive. // Otherwise, documentation generators will not recognize the directive.
let is_sphinx = checker let is_sphinx = checker
.locator() .locator()
.line(blank_lines_after_dashes_end) .line_str(blank_lines_after_dashes_end)
.trim_start() .trim_start()
.starts_with(".. "); .starts_with(".. ");
@ -1569,7 +1569,7 @@ fn blanks_and_section_underline(
// Otherwise, documentation generators will not recognize the directive. // Otherwise, documentation generators will not recognize the directive.
let is_sphinx = checker let is_sphinx = checker
.locator() .locator()
.line(blank_lines_end) .line_str(blank_lines_end)
.trim_start() .trim_start()
.starts_with(".. "); .starts_with(".. ");

View File

@ -5,10 +5,10 @@ use ruff_python_ast as ast;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_semantic::Binding; use ruff_python_semantic::Binding;
use ruff_python_trivia::{BackwardsTokenizer, SimpleTokenKind, SimpleTokenizer}; use ruff_python_trivia::{BackwardsTokenizer, SimpleTokenKind, SimpleTokenizer};
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::cst::matchers::{match_call_mut, match_dict, transform_expression}; use crate::cst::matchers::{match_call_mut, match_dict, transform_expression};
use crate::Locator;
/// Generate a [`Edit`] to remove unused keys from format dict. /// Generate a [`Edit`] to remove unused keys from format dict.
pub(super) fn remove_unused_format_arguments_from_dict( pub(super) fn remove_unused_format_arguments_from_dict(

View File

@ -12,15 +12,12 @@ mod tests {
use anyhow::Result; use anyhow::Result;
use regex::Regex; use regex::Regex;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use test_case::test_case; use test_case::test_case;
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_python_trivia::textwrap::dedent; use ruff_python_trivia::textwrap::dedent;
use ruff_source_file::Locator;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::linter::check_path; use crate::linter::check_path;
@ -31,6 +28,7 @@ mod tests {
use crate::settings::{flags, LinterSettings}; use crate::settings::{flags, LinterSettings};
use crate::source_kind::SourceKind; use crate::source_kind::SourceKind;
use crate::test::{test_contents, test_path, test_snippet}; use crate::test::{test_contents, test_path, test_snippet};
use crate::Locator;
use crate::{assert_messages, directives}; use crate::{assert_messages, directives};
#[test_case(Rule::UnusedImport, Path::new("F401_0.py"))] #[test_case(Rule::UnusedImport, Path::new("F401_0.py"))]
@ -712,8 +710,8 @@ mod tests {
let parsed = let parsed =
ruff_python_parser::parse_unchecked_source(source_kind.source_code(), source_type); ruff_python_parser::parse_unchecked_source(source_kind.source_code(), source_type);
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
let stylist = Stylist::from_tokens(parsed.tokens(), &locator); let stylist = Stylist::from_tokens(parsed.tokens(), locator.contents());
let indexer = Indexer::from_tokens(parsed.tokens(), &locator); let indexer = Indexer::from_tokens(parsed.tokens(), locator.contents());
let directives = directives::extract_directives( let directives = directives::extract_directives(
parsed.tokens(), parsed.tokens(),
directives::Flags::from_settings(&settings), directives::Flags::from_settings(&settings),

View File

@ -1,9 +1,9 @@
use ruff_python_ast::{self as ast, ExceptHandler};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::identifier::except; use ruff_python_ast::identifier::except;
use ruff_source_file::Locator; use ruff_python_ast::{self as ast, ExceptHandler};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for `except` blocks that handle all exceptions, but are not the last /// Checks for `except` blocks that handle all exceptions, but are not the last

View File

@ -1,10 +1,10 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast as ast; use ruff_python_ast as ast;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for f-strings that do not contain any placeholder expressions. /// Checks for f-strings that do not contain any placeholder expressions.

View File

@ -295,7 +295,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
continue; continue;
}; };
let name = binding.name(checker.locator()); let name = binding.name(checker.source());
// If an import is marked as required, avoid treating it as unused, regardless of whether // If an import is marked as required, avoid treating it as unused, regardless of whether
// it was _actually_ used. // it was _actually_ used.

View File

@ -183,7 +183,7 @@ fn remove_unused_variable(binding: &Binding, checker: &Checker) -> Option<Fix> {
}; };
} }
} else { } else {
let name = binding.name(checker.locator()); let name = binding.name(checker.source());
let renamed = format!("_{name}"); let renamed = format!("_{name}");
if checker.settings.dummy_variable_rgx.is_match(&renamed) { if checker.settings.dummy_variable_rgx.is_match(&renamed) {
let edit = Edit::range_replacement(renamed, binding.range()); let edit = Edit::range_replacement(renamed, binding.range());

View File

@ -1,11 +1,11 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::Cursor; use ruff_python_trivia::Cursor;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::noqa::{Directive, FileNoqaDirectives, NoqaDirectives, ParsedFileExemption}; use crate::noqa::{Directive, FileNoqaDirectives, NoqaDirectives, ParsedFileExemption};
use crate::settings::types::PreviewMode; use crate::settings::types::PreviewMode;
use crate::Locator;
/// ## What it does /// ## What it does
/// Check for `noqa` annotations that suppress all diagnostics, as opposed to /// Check for `noqa` annotations that suppress all diagnostics, as opposed to

View File

@ -1,14 +1,16 @@
use std::sync::LazyLock;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use memchr::memchr_iter; use memchr::memchr_iter;
use regex::Regex; use regex::Regex;
use std::sync::LazyLock;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use crate::Locator;
/// ## What it does /// ## What it does
/// Check for `type: ignore` annotations that suppress all type warnings, as /// Check for `type: ignore` annotations that suppress all type warnings, as
/// opposed to targeting specific type warnings. /// opposed to targeting specific type warnings.

View File

@ -6,11 +6,12 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, ElifElseClause, Stmt}; use ruff_python_ast::{self as ast, ElifElseClause, Stmt};
use ruff_python_codegen::Stylist; use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer; use ruff_python_index::Indexer;
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::fix::edits::adjust_indentation; use crate::fix::edits::adjust_indentation;
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for `else` blocks that consist of a single `if` statement. /// Checks for `else` blocks that consist of a single `if` statement.
@ -113,7 +114,7 @@ fn convert_to_elif(
let trivia_range = TextRange::new(else_line_end, inner_if_line_start); let trivia_range = TextRange::new(else_line_end, inner_if_line_start);
// Identify the indentation of the outer clause // Identify the indentation of the outer clause
let Some(indentation) = indentation(locator, else_clause) else { let Some(indentation) = indentation(locator.contents(), else_clause) else {
return Err(anyhow::anyhow!("`else` is expected to be on its own line")); return Err(anyhow::anyhow!("`else` is expected to be on its own line"));
}; };

View File

@ -1,9 +1,11 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_trivia::{is_python_whitespace, CommentRanges}; use ruff_python_trivia::{is_python_whitespace, CommentRanges};
use ruff_source_file::Locator; use ruff_source_file::LineRanges;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for a # symbol appearing on a line not followed by an actual comment. /// Checks for a # symbol appearing on a line not followed by an actual comment.
/// ///
@ -47,7 +49,7 @@ pub(crate) fn empty_comments(
comment_ranges: &CommentRanges, comment_ranges: &CommentRanges,
locator: &Locator, locator: &Locator,
) { ) {
let block_comments = comment_ranges.block_comments(locator); let block_comments = comment_ranges.block_comments(locator.contents());
for range in comment_ranges { for range in comment_ranges {
// Ignore comments that are part of multi-line "comment blocks". // Ignore comments that are part of multi-line "comment blocks".

View File

@ -1,11 +1,11 @@
use ruff_text_size::{TextLen, TextRange, TextSize};
use ruff_diagnostics::AlwaysFixableViolation; use ruff_diagnostics::AlwaysFixableViolation;
use ruff_diagnostics::Edit; use ruff_diagnostics::Edit;
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix}; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_parser::TokenKind; use ruff_python_parser::TokenKind;
use ruff_source_file::Locator; use ruff_text_size::{TextLen, TextRange, TextSize};
use crate::Locator;
/// ## What it does /// ## What it does
/// Checks for strings that contain the control character `BS`. /// Checks for strings that contain the control character `BS`.

Some files were not shown because too many files have changed in this diff Show More