mirror of https://github.com/astral-sh/ruff
92 lines
3.0 KiB
Rust
92 lines
3.0 KiB
Rust
/// Helper functions for the tests of rule implementations.
|
|
use std::path::Path;
|
|
|
|
use anyhow::Result;
|
|
use rustpython_parser::lexer::LexResult;
|
|
|
|
use crate::{
|
|
autofix::fix_file,
|
|
directives, fs,
|
|
linter::check_path,
|
|
packaging::detect_package_root,
|
|
registry::Diagnostic,
|
|
rustpython_helpers,
|
|
settings::{flags, Settings},
|
|
source_code::{Indexer, Locator, Stylist},
|
|
};
|
|
|
|
/// A convenient wrapper around [`check_path`], that additionally
|
|
/// asserts that autofixes converge after 10 iterations.
|
|
pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> {
|
|
let contents = fs::read_file(path)?;
|
|
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents);
|
|
let locator = Locator::new(&contents);
|
|
let stylist = Stylist::from_contents(&contents, &locator);
|
|
let indexer: Indexer = tokens.as_slice().into();
|
|
let directives =
|
|
directives::extract_directives(&tokens, directives::Flags::from_settings(settings));
|
|
let mut diagnostics = check_path(
|
|
path,
|
|
path.parent()
|
|
.and_then(|parent| detect_package_root(parent, &settings.namespace_packages)),
|
|
&contents,
|
|
tokens,
|
|
&locator,
|
|
&stylist,
|
|
&indexer,
|
|
&directives,
|
|
settings,
|
|
flags::Autofix::Enabled,
|
|
flags::Noqa::Enabled,
|
|
)?;
|
|
|
|
// Detect autofixes that don't converge after multiple iterations.
|
|
if diagnostics
|
|
.iter()
|
|
.any(|diagnostic| diagnostic.fix.is_some())
|
|
{
|
|
let max_iterations = 10;
|
|
|
|
let mut contents = contents.clone();
|
|
let mut iterations = 0;
|
|
|
|
loop {
|
|
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents);
|
|
let locator = Locator::new(&contents);
|
|
let stylist = Stylist::from_contents(&contents, &locator);
|
|
let indexer: Indexer = tokens.as_slice().into();
|
|
let directives =
|
|
directives::extract_directives(&tokens, directives::Flags::from_settings(settings));
|
|
let diagnostics = check_path(
|
|
path,
|
|
None,
|
|
&contents,
|
|
tokens,
|
|
&locator,
|
|
&stylist,
|
|
&indexer,
|
|
&directives,
|
|
settings,
|
|
flags::Autofix::Enabled,
|
|
flags::Noqa::Enabled,
|
|
)?;
|
|
if let Some((fixed_contents, _)) = fix_file(&diagnostics, &locator) {
|
|
if iterations < max_iterations {
|
|
iterations += 1;
|
|
contents = fixed_contents.to_string();
|
|
} else {
|
|
panic!(
|
|
"Failed to converge after {max_iterations} iterations. This likely \
|
|
indicates a bug in the implementation of the fix."
|
|
);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
diagnostics.sort_by_key(|diagnostic| diagnostic.location);
|
|
Ok(diagnostics)
|
|
}
|