diff --git a/Cargo.lock b/Cargo.lock index 2db3ed69597e7..98e58bde8bbc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3435,7 +3435,6 @@ dependencies = [ "ruff_linter", "ruff_python_ast", "ruff_ranged_value", - "ruff_source_file", "ruff_workspace", "salsa", ] diff --git a/crates/ruff/src/diagnostics.rs b/crates/ruff/src/diagnostics.rs index 8a6535a00997a..61311515bb05a 100644 --- a/crates/ruff/src/diagnostics.rs +++ b/crates/ruff/src/diagnostics.rs @@ -225,8 +225,7 @@ pub(crate) fn lint_path( return Ok(Diagnostics::from_source_error(&err, Some(path), settings)); } }; - let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish(); - lint_pyproject_toml(&source_file, settings) + lint_pyproject_toml(path, &contents, settings) } else { vec![] }; @@ -370,8 +369,6 @@ pub(crate) fn lint_stdin( } let path = path.unwrap(); - let source_file = - SourceFileBuilder::new(path.to_string_lossy(), contents.clone()).finish(); match fix_mode { flags::FixMode::Diff | flags::FixMode::Generate => {} @@ -379,7 +376,7 @@ pub(crate) fn lint_stdin( } return Ok(Diagnostics { - inner: lint_pyproject_toml(&source_file, &settings.linter), + inner: lint_pyproject_toml(path, &contents, &settings.linter), fixed: FixMap::from_iter([(fs::relativize_path(path), FixTable::default())]), notebook_indexes: FxHashMap::default(), }); diff --git a/crates/ruff_linter/resources/mdtest/ruff/invalid-pyproject-toml.md b/crates/ruff_linter/resources/mdtest/ruff/invalid-pyproject-toml.md index 47fcd4206bdb0..033ca832e92a1 100644 --- a/crates/ruff_linter/resources/mdtest/ruff/invalid-pyproject-toml.md +++ b/crates/ruff_linter/resources/mdtest/ruff/invalid-pyproject-toml.md @@ -5,6 +5,8 @@ select = ["RUF200"] ``` +## Reports an invalid `pyproject.toml` + `pyproject.toml`: ```toml @@ -20,3 +22,18 @@ error[RUF200]: Failed to parse pyproject.toml: invalid type: integer `1`, expect | ^ | ``` + +## Respects per-file ignores + +```toml +[lint] +select = ["RUF200"] +per-file-ignores = { "pyproject.toml" = ["RUF200"] } +``` + +`pyproject.toml`: + +```toml +[project] +name = 1 +``` diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index cdfa6c1bc4a78..afdf134f1e0f1 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -3548,6 +3548,11 @@ impl<'a> LintContext<'a> { (self.diagnostics.into_inner(), self.source_file) } + #[inline] + pub(crate) fn into_diagnostics(self) -> Vec { + self.diagnostics.into_inner() + } + #[inline] pub(crate) fn as_mut_vec(&mut self) -> &mut Vec { self.diagnostics.get_mut() diff --git a/crates/ruff_linter/src/pyproject_toml.rs b/crates/ruff_linter/src/pyproject_toml.rs index 8b319f595cddd..583f099981e68 100644 --- a/crates/ruff_linter/src/pyproject_toml.rs +++ b/crates/ruff_linter/src/pyproject_toml.rs @@ -1,61 +1,25 @@ -use colored::Colorize; -use log::warn; -use pyproject_toml::PyProjectToml; -use ruff_text_size::{TextRange, TextSize}; +use std::path::Path; +use pyproject_toml::PyProjectToml; use ruff_db::diagnostic::Diagnostic; -use ruff_source_file::SourceFile; -use crate::registry::Rule; -use crate::rules::ruff::rules::InvalidPyprojectToml; +use crate::checkers::ast::LintContext; +use crate::codes::Rule; +use crate::rules::ruff::rules::invalid_pyproject_toml; use crate::settings::LinterSettings; -use crate::{IOError, Violation}; -/// RUF200 -pub fn lint_pyproject_toml(source_file: &SourceFile, settings: &LinterSettings) -> Vec { - let Some(err) = toml::from_str::(source_file.source_text()).err() else { - return Vec::default(); - }; +pub fn lint_pyproject_toml( + path: &Path, + contents: &str, + settings: &LinterSettings, +) -> Vec { + let context = LintContext::new(path, contents, settings); - let mut messages = Vec::new(); - let range = match err.span() { - // This is bad but sometimes toml and/or serde just don't give us spans - // TODO(konstin,micha): https://github.com/astral-sh/ruff/issues/4571 - None => TextRange::default(), - Some(range) => { - let Ok(end) = TextSize::try_from(range.end) else { - let message = format!( - "{} is larger than 4GB, but ruff assumes all files to be smaller", - source_file.name(), - ); - if settings.rules.enabled(Rule::IOError) { - let diagnostic = - IOError { message }.into_diagnostic(TextRange::default(), source_file); - messages.push(diagnostic); - } else { - warn!( - "{}{}{} {message}", - "Failed to lint ".bold(), - source_file.name().bold(), - ":".bold() - ); - } - return messages; - }; - TextRange::new( - // start <= end, so if end < 4GB follows start < 4GB - TextSize::try_from(range.start).unwrap(), - end, - ) + if let Err(err) = toml::from_str::(contents) { + if context.is_rule_enabled(Rule::InvalidPyprojectToml) { + invalid_pyproject_toml(&context, &err); } - }; - - if settings.rules.enabled(Rule::InvalidPyprojectToml) { - let toml_err = err.message().to_string(); - let diagnostic = - InvalidPyprojectToml { message: toml_err }.into_diagnostic(range, source_file); - messages.push(diagnostic); } - messages + context.into_diagnostics() } diff --git a/crates/ruff_linter/src/rules/ruff/mod.rs b/crates/ruff_linter/src/rules/ruff/mod.rs index 68bd7b17265e9..a91f858996dc7 100644 --- a/crates/ruff_linter/src/rules/ruff/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/mod.rs @@ -13,7 +13,6 @@ mod tests { use anyhow::Result; use regex::Regex; use ruff_python_ast::PythonVersion; - use ruff_source_file::SourceFileBuilder; use rustc_hash::FxHashSet; use test_case::test_case; @@ -795,9 +794,9 @@ mod tests { .join(path) .join("pyproject.toml"); let contents = fs::read_to_string(path)?; - let source_file = SourceFileBuilder::new("pyproject.toml", contents).finish(); let messages = lint_pyproject_toml( - &source_file, + Path::new("pyproject.toml"), + &contents, &settings::LinterSettings::for_rule(Rule::InvalidPyprojectToml), ); assert_diagnostics!(snapshot, messages); diff --git a/crates/ruff_linter/src/rules/ruff/rules/invalid_pyproject_toml.rs b/crates/ruff_linter/src/rules/ruff/rules/invalid_pyproject_toml.rs index 4da7ce2996bf9..be78db98cf6e3 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/invalid_pyproject_toml.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/invalid_pyproject_toml.rs @@ -1,6 +1,7 @@ use ruff_macros::{ViolationMetadata, derive_message_formats}; +use ruff_text_size::{TextRange, TextSize}; -use crate::{FixAvailability, Violation}; +use crate::{FixAvailability, Violation, checkers::ast::LintContext}; /// ## What it does /// Checks for any pyproject.toml that does not conform to the schema from the relevant PEPs. @@ -45,3 +46,19 @@ impl Violation for InvalidPyprojectToml { format!("Failed to parse pyproject.toml: {message}") } } + +/// RUF200 +pub(crate) fn invalid_pyproject_toml(context: &LintContext, err: &toml::de::Error) { + let range = match err.span() { + // This is bad but sometimes toml and/or serde just don't give us spans + // TODO(konstin,micha): https://github.com/astral-sh/ruff/issues/4571 + None => TextRange::default(), + Some(range) => TextRange::new( + TextSize::try_from(range.start).unwrap(), + TextSize::try_from(range.end).unwrap(), + ), + }; + + let toml_err = err.message().to_string(); + context.report_diagnostic(InvalidPyprojectToml { message: toml_err }, range); +} diff --git a/crates/ruff_mdtest/Cargo.toml b/crates/ruff_mdtest/Cargo.toml index cbf24ad06a733..9209374fc5a3f 100644 --- a/crates/ruff_mdtest/Cargo.toml +++ b/crates/ruff_mdtest/Cargo.toml @@ -20,7 +20,6 @@ ruff_db = { workspace = true, features = ["os", "testing"] } ruff_linter = { workspace = true, features = ["testing"] } ruff_python_ast = { workspace = true } ruff_ranged_value = { workspace = true } -ruff_source_file = { workspace = true } ruff_workspace = { workspace = true } anyhow = { workspace = true } diff --git a/crates/ruff_mdtest/src/lib.rs b/crates/ruff_mdtest/src/lib.rs index 1fbe0b1512638..c35ced5469294 100644 --- a/crates/ruff_mdtest/src/lib.rs +++ b/crates/ruff_mdtest/src/lib.rs @@ -15,7 +15,6 @@ use ruff_linter::source_kind::SourceKind; use ruff_linter::test::test_contents; use ruff_python_ast::SourceType; use ruff_ranged_value::{ValueSource, ValueSourceGuard}; -use ruff_source_file::SourceFileBuilder; use ruff_workspace::configuration::Configuration; use ruff_workspace::options::Options; @@ -128,10 +127,7 @@ fn run_test( test_contents(&source_kind, path, &settings.linter).0 } SourceType::Toml(source_type) if source_type.is_pyproject() => { - let source_file = - SourceFileBuilder::new(path.to_string_lossy(), source.as_str()) - .finish(); - lint_pyproject_toml(&source_file, &settings.linter) + lint_pyproject_toml(path, source.as_str(), &settings.linter) } SourceType::Toml(_) | SourceType::Markdown => Vec::new(), }