mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
Simplify LinterResult
, avoid cloning ParseError
(#11903)
## Summary Follow-up to #11902 This PR simplifies the `LinterResult` struct by avoiding the generic and not store the `ParseError`. This is possible because the callers already have access to the `ParseError` via the `Parsed` output. This also means that we can simplify the return type of `check_path` and avoid the generic `T` on `LinterResult`. ## Test Plan `cargo insta test`
This commit is contained in:
parent
73851e73ab
commit
72b6c26101
10 changed files with 96 additions and 99 deletions
|
@ -35,29 +35,19 @@ use crate::settings::{flags, LinterSettings};
|
|||
use crate::source_kind::SourceKind;
|
||||
use crate::{directives, fs};
|
||||
|
||||
/// A [`Result`]-like type that returns both data and an error. Used to return
|
||||
/// diagnostics even in the face of parse errors, since many diagnostics can be
|
||||
/// generated without a full AST.
|
||||
pub struct LinterResult<T> {
|
||||
pub data: T,
|
||||
pub error: Option<ParseError>,
|
||||
}
|
||||
|
||||
impl<T> LinterResult<T> {
|
||||
const fn new(data: T, error: Option<ParseError>) -> Self {
|
||||
Self { data, error }
|
||||
}
|
||||
|
||||
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> LinterResult<U> {
|
||||
LinterResult::new(f(self.data), self.error)
|
||||
}
|
||||
pub struct LinterResult {
|
||||
/// A collection of diagnostic messages generated by the linter.
|
||||
pub messages: Vec<Message>,
|
||||
/// A flag indicating the presence of syntax errors in the source file.
|
||||
/// If `true`, at least one syntax error was detected in the source file.
|
||||
pub has_syntax_error: bool,
|
||||
}
|
||||
|
||||
pub type FixTable = FxHashMap<Rule, usize>;
|
||||
|
||||
pub struct FixerResult<'a> {
|
||||
/// The result returned by the linter, after applying any fixes.
|
||||
pub result: LinterResult<Vec<Message>>,
|
||||
pub result: LinterResult,
|
||||
/// The resulting source code, after applying any fixes.
|
||||
pub transformed: Cow<'a, SourceKind>,
|
||||
/// The number of fixes applied for each [`Rule`].
|
||||
|
@ -79,7 +69,7 @@ pub fn check_path(
|
|||
source_kind: &SourceKind,
|
||||
source_type: PySourceType,
|
||||
parsed: &Parsed<ModModule>,
|
||||
) -> LinterResult<Vec<Diagnostic>> {
|
||||
) -> Vec<Diagnostic> {
|
||||
// Aggregate all diagnostics.
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
|
@ -317,7 +307,7 @@ pub fn check_path(
|
|||
}
|
||||
}
|
||||
|
||||
LinterResult::new(diagnostics, parsed.errors().iter().next().cloned())
|
||||
diagnostics
|
||||
}
|
||||
|
||||
const MAX_ITERATIONS: usize = 100;
|
||||
|
@ -351,9 +341,7 @@ pub fn add_noqa_to_path(
|
|||
);
|
||||
|
||||
// Generate diagnostics, ignoring any existing `noqa` directives.
|
||||
let LinterResult {
|
||||
data: diagnostics, ..
|
||||
} = check_path(
|
||||
let diagnostics = check_path(
|
||||
path,
|
||||
package,
|
||||
&locator,
|
||||
|
@ -390,7 +378,7 @@ pub fn lint_only(
|
|||
source_kind: &SourceKind,
|
||||
source_type: PySourceType,
|
||||
source: ParseSource,
|
||||
) -> LinterResult<Vec<Message>> {
|
||||
) -> LinterResult {
|
||||
let parsed = source.into_parsed(source_kind, source_type);
|
||||
|
||||
// Map row and column locations to byte slices (lazily).
|
||||
|
@ -411,7 +399,7 @@ pub fn lint_only(
|
|||
);
|
||||
|
||||
// Generate diagnostics.
|
||||
let result = check_path(
|
||||
let diagnostics = check_path(
|
||||
path,
|
||||
package,
|
||||
&locator,
|
||||
|
@ -425,9 +413,16 @@ pub fn lint_only(
|
|||
&parsed,
|
||||
);
|
||||
|
||||
result.map(|diagnostics| {
|
||||
diagnostics_to_messages(diagnostics, parsed.errors(), path, &locator, &directives)
|
||||
})
|
||||
LinterResult {
|
||||
messages: diagnostics_to_messages(
|
||||
diagnostics,
|
||||
parsed.errors(),
|
||||
path,
|
||||
&locator,
|
||||
&directives,
|
||||
),
|
||||
has_syntax_error: !parsed.is_valid(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from diagnostics to messages.
|
||||
|
@ -479,8 +474,8 @@ pub fn lint_fix<'a>(
|
|||
// As an escape hatch, bail after 100 iterations.
|
||||
let mut iterations = 0;
|
||||
|
||||
// Track whether the _initial_ source code was parseable.
|
||||
let mut parseable = false;
|
||||
// Track whether the _initial_ source code is valid syntax.
|
||||
let mut is_valid_syntax = false;
|
||||
|
||||
// Continuously fix until the source code stabilizes.
|
||||
loop {
|
||||
|
@ -506,7 +501,7 @@ pub fn lint_fix<'a>(
|
|||
);
|
||||
|
||||
// Generate diagnostics.
|
||||
let result = check_path(
|
||||
let diagnostics = check_path(
|
||||
path,
|
||||
package,
|
||||
&locator,
|
||||
|
@ -521,19 +516,21 @@ pub fn lint_fix<'a>(
|
|||
);
|
||||
|
||||
if iterations == 0 {
|
||||
parseable = result.error.is_none();
|
||||
is_valid_syntax = parsed.is_valid();
|
||||
} else {
|
||||
// If the source code was parseable on the first pass, but is no
|
||||
// longer parseable on a subsequent pass, then we've introduced a
|
||||
// syntax error. Return the original code.
|
||||
if parseable && result.error.is_some() {
|
||||
report_fix_syntax_error(
|
||||
path,
|
||||
transformed.source_code(),
|
||||
&result.error.unwrap(),
|
||||
fixed.keys().copied(),
|
||||
);
|
||||
return Err(anyhow!("Fix introduced a syntax error"));
|
||||
if is_valid_syntax {
|
||||
if let Some(error) = parsed.errors().first() {
|
||||
report_fix_syntax_error(
|
||||
path,
|
||||
transformed.source_code(),
|
||||
error,
|
||||
fixed.keys().copied(),
|
||||
);
|
||||
return Err(anyhow!("Fix introduced a syntax error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,7 +539,7 @@ pub fn lint_fix<'a>(
|
|||
code: fixed_contents,
|
||||
fixes: applied,
|
||||
source_map,
|
||||
}) = fix_file(&result.data, &locator, unsafe_fixes)
|
||||
}) = fix_file(&diagnostics, &locator, unsafe_fixes)
|
||||
{
|
||||
if iterations < MAX_ITERATIONS {
|
||||
// Count the number of fixed errors.
|
||||
|
@ -559,13 +556,20 @@ pub fn lint_fix<'a>(
|
|||
continue;
|
||||
}
|
||||
|
||||
report_failed_to_converge_error(path, transformed.source_code(), &result.data);
|
||||
report_failed_to_converge_error(path, transformed.source_code(), &diagnostics);
|
||||
}
|
||||
|
||||
return Ok(FixerResult {
|
||||
result: result.map(|diagnostics| {
|
||||
diagnostics_to_messages(diagnostics, parsed.errors(), path, &locator, &directives)
|
||||
}),
|
||||
result: LinterResult {
|
||||
messages: diagnostics_to_messages(
|
||||
diagnostics,
|
||||
parsed.errors(),
|
||||
path,
|
||||
&locator,
|
||||
&directives,
|
||||
),
|
||||
has_syntax_error: !is_valid_syntax,
|
||||
},
|
||||
transformed,
|
||||
fixed,
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue