Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement an iterator for universal newlines #3454

Merged
merged 5 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/ruff/src/autofix/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::Fix;
use ruff_python_ast::helpers;
use ruff_python_ast::helpers::to_absolute;
use ruff_python_ast::newlines::NewlineWithTrailingNewline;
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
use ruff_python_ast::whitespace::LinesWithTrailingNewline;

use crate::cst::helpers::compose_module_path;
use crate::cst::matchers::match_module;
Expand Down Expand Up @@ -100,7 +100,7 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
/// of a multi-statement line.
fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<Location> {
let contents = locator.skip(stmt.end_location.unwrap());
for (row, line) in LinesWithTrailingNewline::from(contents).enumerate() {
for (row, line) in NewlineWithTrailingNewline::from(contents).enumerate() {
let trimmed = line.trim();
if trimmed.starts_with(';') {
let column = line
Expand All @@ -123,7 +123,7 @@ fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<Location> {
fn next_stmt_break(semicolon: Location, locator: &Locator) -> Location {
let start_location = Location::new(semicolon.row(), semicolon.column() + 1);
let contents = locator.skip(start_location);
for (row, line) in LinesWithTrailingNewline::from(contents).enumerate() {
for (row, line) in NewlineWithTrailingNewline::from(contents).enumerate() {
let trimmed = line.trim();
// Skip past any continuations.
if trimmed.starts_with('\\') {
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/checkers/noqa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use nohash_hasher::IntMap;
use rustpython_parser::ast::Location;

use ruff_diagnostics::{Diagnostic, Fix};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;

use crate::codes::NoqaCode;
Expand Down Expand Up @@ -38,7 +39,7 @@ pub fn check_noqa(
// Indices of diagnostics that were ignored by a `noqa` directive.
let mut ignored_diagnostics = vec![];

let lines: Vec<&str> = contents.lines().collect();
let lines: Vec<&str> = contents.universal_newlines().collect();
for lineno in commented_lines {
match extract_file_exemption(lines[lineno - 1]) {
Exemption::All => {
Expand Down
11 changes: 6 additions & 5 deletions crates/ruff/src/checkers/physical_lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
use std::path::Path;

use ruff_diagnostics::Diagnostic;
use ruff_python_ast::source_code::Stylist;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::source_code::{Locator, Stylist};

use crate::registry::Rule;
use crate::rules::flake8_executable::helpers::{extract_shebang, ShebangDirective};
Expand All @@ -21,8 +22,8 @@ use crate::settings::{flags, Settings};

pub fn check_physical_lines(
path: &Path,
locator: &Locator,
stylist: &Stylist,
contents: &str,
commented_lines: &[usize],
doc_lines: &[usize],
settings: &Settings,
Expand Down Expand Up @@ -56,7 +57,7 @@ pub fn check_physical_lines(

let mut commented_lines_iter = commented_lines.iter().peekable();
let mut doc_lines_iter = doc_lines.iter().peekable();
for (index, line) in contents.lines().enumerate() {
for (index, line) in locator.contents().universal_newlines().enumerate() {
while commented_lines_iter
.next_if(|lineno| &(index + 1) == *lineno)
.is_some()
Expand Down Expand Up @@ -162,8 +163,8 @@ pub fn check_physical_lines(

if enforce_no_newline_at_end_of_file {
if let Some(diagnostic) = no_newline_at_end_of_file(
locator,
stylist,
contents,
autofix.into() && settings.rules.should_fix(&Rule::NoNewLineAtEndOfFile),
) {
diagnostics.push(diagnostic);
Expand Down Expand Up @@ -199,8 +200,8 @@ mod tests {
let check_with_max_line_length = |line_length: usize| {
check_physical_lines(
Path::new("foo.py"),
&locator,
&stylist,
line,
&[],
&[],
&Settings {
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff/src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ pub fn check_path(
{
diagnostics.extend(check_physical_lines(
path,
locator,
stylist,
contents,
indexer.commented_lines(),
&doc_lines,
settings,
Expand Down
5 changes: 3 additions & 2 deletions crates/ruff/src/noqa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
use rustpython_parser::ast::Location;

use ruff_diagnostics::Diagnostic;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::source_code::{LineEnding, Locator};
use ruff_python_ast::types::Range;

Expand Down Expand Up @@ -181,7 +182,7 @@ fn add_noqa_inner(
// Codes that are globally exempted (within the current file).
let mut file_exemptions: Vec<NoqaCode> = vec![];

let lines: Vec<&str> = contents.lines().collect();
let lines: Vec<&str> = contents.universal_newlines().collect();
for lineno in commented_lines {
match extract_file_exemption(lines[lineno - 1]) {
Exemption::All => {
Expand Down Expand Up @@ -263,7 +264,7 @@ fn add_noqa_inner(

let mut count: usize = 0;
let mut output = String::new();
for (lineno, line) in contents.lines().enumerate() {
for (lineno, line) in lines.into_iter().enumerate() {
match matches_by_line.get(&lineno) {
None => {
output.push_str(line);
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use ruff_python_ast::helpers::{
contains_call_path, contains_effect, create_expr, create_stmt, first_colon_range, has_comments,
has_comments_in, unparse_expr, unparse_stmt,
};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -283,7 +284,7 @@ pub fn nested_if_statements(
Ok(fix) => {
if fix
.content
.lines()
.universal_newlines()
.all(|line| line.len() <= checker.settings.line_length)
{
diagnostic.amend(fix);
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::{AutofixKind, Availability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{first_colon_range, has_comments_in};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -115,7 +116,7 @@ pub fn multiple_with_statements(
Ok(fix) => {
if fix
.content
.lines()
.universal_newlines()
.all(|line| line.len() <= checker.settings.line_length)
{
diagnostic.amend(fix);
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/isort/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use rustpython_parser::ast::{Location, Stmt};
use rustpython_parser::{lexer, Mode, Tok};

use ruff_python_ast::helpers::is_docstring_stmt;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::source_code::Locator;

use super::types::TrailingComma;
Expand Down Expand Up @@ -62,7 +63,7 @@ pub fn has_comment_break(stmt: &Stmt, locator: &Locator) -> bool {
// # Direct comment.
// def f(): pass
let mut seen_blank = false;
for line in locator.take(stmt.location).lines().rev() {
for line in locator.take(stmt.location).universal_newlines().rev() {
let line = line.trim();
if seen_blank {
if line.starts_with('#') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use rustpython_parser::ast::Location;

use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::Range;

Expand Down Expand Up @@ -76,7 +77,7 @@ pub fn invalid_escape_sequence(
let body = &text[(quote_pos + quote.len())..(text.len() - quote.len())];

if !prefix.contains('r') {
for (row_offset, line) in body.lines().enumerate() {
for (row_offset, line) in body.universal_newlines().enumerate() {
let chars: Vec<char> = line.chars().collect();
for col_offset in 0..chars.len() {
if chars[col_offset] != '\\' {
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/pycodestyle/rules/lambda_assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustpython_parser::ast::{Arguments, Expr, ExprKind, Location, Stmt, StmtKind
use ruff_diagnostics::{AutofixKind, Availability, Diagnostic, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{match_leading_content, match_trailing_content, unparse_stmt};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::source_code::Stylist;
use ruff_python_ast::types::{Range, ScopeKind};
use ruff_python_ast::whitespace::leading_space;
Expand Down Expand Up @@ -86,7 +87,7 @@ pub fn lambda_assignment(checker: &mut Checker, target: &Expr, value: &Expr, stm
let indentation = &leading_space(first_line);
let mut indented = String::new();
for (idx, line) in function(id, args, body, checker.stylist)
.lines()
.universal_newlines()
.enumerate()
{
if idx == 0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use rustpython_parser::ast::Location;

use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::Stylist;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::source_code::{Locator, Stylist};
use ruff_python_ast::types::Range;

/// ## What it does
Expand Down Expand Up @@ -37,16 +38,16 @@ impl AlwaysAutofixableViolation for NoNewLineAtEndOfFile {

/// W292
pub fn no_newline_at_end_of_file(
locator: &Locator,
stylist: &Stylist,
contents: &str,
autofix: bool,
) -> Option<Diagnostic> {
if !contents.ends_with('\n') {
if !locator.contents().ends_with(['\n', '\r']) {
// Note: if `lines.last()` is `None`, then `contents` is empty (and so we don't
// want to raise W292 anyway).
if let Some(line) = contents.lines().last() {
if let Some(line) = locator.contents().universal_newlines().last() {
// Both locations are at the end of the file (and thus the same).
let location = Location::new(contents.lines().count(), line.len());
let location = Location::new(locator.count_lines(), line.len());
let mut diagnostic =
Diagnostic::new(NoNewLineAtEndOfFile, Range::new(location, location));
if autofix {
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/pydocstyle/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::BTreeSet;

use ruff_python_ast::cast;
use ruff_python_ast::helpers::{map_callable, to_call_path};
use ruff_python_ast::newlines::StrExt;

use crate::checkers::ast::Checker;
use crate::docstrings::definition::{Definition, DefinitionKind};
Expand All @@ -10,7 +11,7 @@ use crate::docstrings::definition::{Definition, DefinitionKind};
pub fn logical_line(content: &str) -> Option<usize> {
// Find the first logical line.
let mut logical_line = None;
for (i, line) in content.lines().enumerate() {
for (i, line) in content.universal_newlines().enumerate() {
if line.trim().is_empty() {
// Empty line. If this is the line _after_ the first logical line, stop.
if logical_line.is_some() {
Expand Down
5 changes: 3 additions & 2 deletions crates/ruff/src/rules/pydocstyle/rules/blank_after_summary.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ruff_diagnostics::{AutofixKind, Availability, Diagnostic, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -45,7 +46,7 @@ pub fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) {

let mut lines_count = 1;
let mut blanks_count = 0;
for line in body.trim().lines().skip(1) {
for line in body.trim().universal_newlines().skip(1) {
lines_count += 1;
if line.trim().is_empty() {
blanks_count += 1;
Expand All @@ -64,7 +65,7 @@ pub fn blank_after_summary(checker: &mut Checker, docstring: &Docstring) {
if blanks_count > 1 {
// Find the "summary" line (defined as the first non-blank line).
let mut summary_line = 0;
for line in body.lines() {
for line in body.universal_newlines() {
if line.trim().is_empty() {
summary_line += 1;
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -75,7 +76,7 @@ pub fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
.slice(Range::new(parent.location, docstring.expr.location));

let blank_lines_before = before
.lines()
.universal_newlines()
.rev()
.skip(1)
.take_while(|line| line.trim().is_empty())
Expand Down Expand Up @@ -138,15 +139,15 @@ pub fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
));

let all_blank_after = after
.lines()
.universal_newlines()
.skip(1)
.all(|line| line.trim().is_empty() || line.trim_start().starts_with('#'));
if all_blank_after {
return;
}

let blank_lines_after = after
.lines()
.universal_newlines()
.skip(1)
.take_while(|line| line.trim().is_empty())
.count();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use regex::Regex;

use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -67,7 +68,7 @@ pub fn blank_before_after_function(checker: &mut Checker, docstring: &Docstring)
.slice(Range::new(parent.location, docstring.expr.location));

let blank_lines_before = before
.lines()
.universal_newlines()
.rev()
.skip(1)
.take_while(|line| line.trim().is_empty())
Expand Down Expand Up @@ -102,7 +103,7 @@ pub fn blank_before_after_function(checker: &mut Checker, docstring: &Docstring)

// If the docstring is only followed by blank and commented lines, abort.
let all_blank_after = after
.lines()
.universal_newlines()
.skip(1)
.all(|line| line.trim().is_empty() || line.trim_start().starts_with('#'));
if all_blank_after {
Expand All @@ -111,15 +112,15 @@ pub fn blank_before_after_function(checker: &mut Checker, docstring: &Docstring)

// Count the number of blank lines after the docstring.
let blank_lines_after = after
.lines()
.universal_newlines()
.skip(1)
.take_while(|line| line.trim().is_empty())
.count();

// Avoid violations for blank lines followed by inner functions or classes.
if blank_lines_after == 1
&& after
.lines()
.universal_newlines()
.skip(1 + blank_lines_after)
.find(|line| !line.trim_start().starts_with('#'))
.map_or(false, |line| INNER_FUNCTION_OR_CLASS_REGEX.is_match(line))
Expand Down
5 changes: 3 additions & 2 deletions crates/ruff/src/rules/pydocstyle/rules/ends_with_period.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use strum::IntoEnumIterator;

use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::str::leading_quote;
use ruff_python_ast::types::Range;

Expand Down Expand Up @@ -31,7 +32,7 @@ pub fn ends_with_period(checker: &mut Checker, docstring: &Docstring) {
let contents = docstring.contents;
let body = docstring.body;

if let Some(first_line) = body.trim().lines().next() {
if let Some(first_line) = body.trim().universal_newlines().next() {
let trimmed = first_line.trim();

// Avoid false-positives: `:param`, etc.
Expand All @@ -55,7 +56,7 @@ pub fn ends_with_period(checker: &mut Checker, docstring: &Docstring) {
}

if let Some(index) = logical_line(body) {
let line = body.lines().nth(index).unwrap();
let line = body.universal_newlines().nth(index).unwrap();
let trimmed = line.trim_end();

if !trimmed.ends_with('.') {
Expand Down
Loading