mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:53 +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
|
@ -264,8 +264,8 @@ pub(crate) fn lint_path(
|
||||||
// Lint the file.
|
// Lint the file.
|
||||||
let (
|
let (
|
||||||
LinterResult {
|
LinterResult {
|
||||||
data: messages,
|
messages,
|
||||||
error: parse_error,
|
has_syntax_error: has_error,
|
||||||
},
|
},
|
||||||
transformed,
|
transformed,
|
||||||
fixed,
|
fixed,
|
||||||
|
@ -334,7 +334,7 @@ pub(crate) fn lint_path(
|
||||||
|
|
||||||
if let Some((cache, relative_path, key)) = caching {
|
if let Some((cache, relative_path, key)) = caching {
|
||||||
// We don't cache parsing errors.
|
// We don't cache parsing errors.
|
||||||
if parse_error.is_none() {
|
if !has_error {
|
||||||
// `FixMode::Apply` and `FixMode::Diff` rely on side-effects (writing to disk,
|
// `FixMode::Apply` and `FixMode::Diff` rely on side-effects (writing to disk,
|
||||||
// and writing the diff to stdout, respectively). If a file has diagnostics, we
|
// and writing the diff to stdout, respectively). If a file has diagnostics, we
|
||||||
// need to avoid reading from and writing to the cache in these modes.
|
// need to avoid reading from and writing to the cache in these modes.
|
||||||
|
@ -400,7 +400,7 @@ pub(crate) fn lint_stdin(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Lint the inputs.
|
// Lint the inputs.
|
||||||
let (LinterResult { data: messages, .. }, transformed, fixed) =
|
let (LinterResult { messages, .. }, transformed, fixed) =
|
||||||
if matches!(fix_mode, flags::FixMode::Apply | flags::FixMode::Diff) {
|
if matches!(fix_mode, flags::FixMode::Apply | flags::FixMode::Diff) {
|
||||||
if let Ok(FixerResult {
|
if let Ok(FixerResult {
|
||||||
result,
|
result,
|
||||||
|
|
|
@ -73,7 +73,7 @@ fn benchmark_linter(mut group: BenchmarkGroup, settings: &LinterSettings) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert that file contains no parse errors
|
// Assert that file contains no parse errors
|
||||||
assert_eq!(result.error, None);
|
assert!(!result.has_syntax_error);
|
||||||
},
|
},
|
||||||
criterion::BatchSize::SmallInput,
|
criterion::BatchSize::SmallInput,
|
||||||
);
|
);
|
||||||
|
|
|
@ -35,29 +35,19 @@ use crate::settings::{flags, LinterSettings};
|
||||||
use crate::source_kind::SourceKind;
|
use crate::source_kind::SourceKind;
|
||||||
use crate::{directives, fs};
|
use crate::{directives, fs};
|
||||||
|
|
||||||
/// A [`Result`]-like type that returns both data and an error. Used to return
|
pub struct LinterResult {
|
||||||
/// diagnostics even in the face of parse errors, since many diagnostics can be
|
/// A collection of diagnostic messages generated by the linter.
|
||||||
/// generated without a full AST.
|
pub messages: Vec<Message>,
|
||||||
pub struct LinterResult<T> {
|
/// A flag indicating the presence of syntax errors in the source file.
|
||||||
pub data: T,
|
/// If `true`, at least one syntax error was detected in the source file.
|
||||||
pub error: Option<ParseError>,
|
pub has_syntax_error: bool,
|
||||||
}
|
|
||||||
|
|
||||||
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 type FixTable = FxHashMap<Rule, usize>;
|
pub type FixTable = FxHashMap<Rule, usize>;
|
||||||
|
|
||||||
pub struct FixerResult<'a> {
|
pub struct FixerResult<'a> {
|
||||||
/// The result returned by the linter, after applying any fixes.
|
/// 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.
|
/// The resulting source code, after applying any fixes.
|
||||||
pub transformed: Cow<'a, SourceKind>,
|
pub transformed: Cow<'a, SourceKind>,
|
||||||
/// The number of fixes applied for each [`Rule`].
|
/// The number of fixes applied for each [`Rule`].
|
||||||
|
@ -79,7 +69,7 @@ pub fn check_path(
|
||||||
source_kind: &SourceKind,
|
source_kind: &SourceKind,
|
||||||
source_type: PySourceType,
|
source_type: PySourceType,
|
||||||
parsed: &Parsed<ModModule>,
|
parsed: &Parsed<ModModule>,
|
||||||
) -> LinterResult<Vec<Diagnostic>> {
|
) -> Vec<Diagnostic> {
|
||||||
// Aggregate all diagnostics.
|
// Aggregate all diagnostics.
|
||||||
let mut diagnostics = vec![];
|
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;
|
const MAX_ITERATIONS: usize = 100;
|
||||||
|
@ -351,9 +341,7 @@ pub fn add_noqa_to_path(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generate diagnostics, ignoring any existing `noqa` directives.
|
// Generate diagnostics, ignoring any existing `noqa` directives.
|
||||||
let LinterResult {
|
let diagnostics = check_path(
|
||||||
data: diagnostics, ..
|
|
||||||
} = check_path(
|
|
||||||
path,
|
path,
|
||||||
package,
|
package,
|
||||||
&locator,
|
&locator,
|
||||||
|
@ -390,7 +378,7 @@ pub fn lint_only(
|
||||||
source_kind: &SourceKind,
|
source_kind: &SourceKind,
|
||||||
source_type: PySourceType,
|
source_type: PySourceType,
|
||||||
source: ParseSource,
|
source: ParseSource,
|
||||||
) -> LinterResult<Vec<Message>> {
|
) -> LinterResult {
|
||||||
let parsed = source.into_parsed(source_kind, source_type);
|
let parsed = source.into_parsed(source_kind, source_type);
|
||||||
|
|
||||||
// Map row and column locations to byte slices (lazily).
|
// Map row and column locations to byte slices (lazily).
|
||||||
|
@ -411,7 +399,7 @@ pub fn lint_only(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generate diagnostics.
|
// Generate diagnostics.
|
||||||
let result = check_path(
|
let diagnostics = check_path(
|
||||||
path,
|
path,
|
||||||
package,
|
package,
|
||||||
&locator,
|
&locator,
|
||||||
|
@ -425,9 +413,16 @@ pub fn lint_only(
|
||||||
&parsed,
|
&parsed,
|
||||||
);
|
);
|
||||||
|
|
||||||
result.map(|diagnostics| {
|
LinterResult {
|
||||||
diagnostics_to_messages(diagnostics, parsed.errors(), path, &locator, &directives)
|
messages: diagnostics_to_messages(
|
||||||
})
|
diagnostics,
|
||||||
|
parsed.errors(),
|
||||||
|
path,
|
||||||
|
&locator,
|
||||||
|
&directives,
|
||||||
|
),
|
||||||
|
has_syntax_error: !parsed.is_valid(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert from diagnostics to messages.
|
/// Convert from diagnostics to messages.
|
||||||
|
@ -479,8 +474,8 @@ pub fn lint_fix<'a>(
|
||||||
// As an escape hatch, bail after 100 iterations.
|
// As an escape hatch, bail after 100 iterations.
|
||||||
let mut iterations = 0;
|
let mut iterations = 0;
|
||||||
|
|
||||||
// Track whether the _initial_ source code was parseable.
|
// Track whether the _initial_ source code is valid syntax.
|
||||||
let mut parseable = false;
|
let mut is_valid_syntax = false;
|
||||||
|
|
||||||
// Continuously fix until the source code stabilizes.
|
// Continuously fix until the source code stabilizes.
|
||||||
loop {
|
loop {
|
||||||
|
@ -506,7 +501,7 @@ pub fn lint_fix<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generate diagnostics.
|
// Generate diagnostics.
|
||||||
let result = check_path(
|
let diagnostics = check_path(
|
||||||
path,
|
path,
|
||||||
package,
|
package,
|
||||||
&locator,
|
&locator,
|
||||||
|
@ -521,19 +516,21 @@ pub fn lint_fix<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
if iterations == 0 {
|
if iterations == 0 {
|
||||||
parseable = result.error.is_none();
|
is_valid_syntax = parsed.is_valid();
|
||||||
} else {
|
} else {
|
||||||
// If the source code was parseable on the first pass, but is no
|
// If the source code was parseable on the first pass, but is no
|
||||||
// longer parseable on a subsequent pass, then we've introduced a
|
// longer parseable on a subsequent pass, then we've introduced a
|
||||||
// syntax error. Return the original code.
|
// syntax error. Return the original code.
|
||||||
if parseable && result.error.is_some() {
|
if is_valid_syntax {
|
||||||
report_fix_syntax_error(
|
if let Some(error) = parsed.errors().first() {
|
||||||
path,
|
report_fix_syntax_error(
|
||||||
transformed.source_code(),
|
path,
|
||||||
&result.error.unwrap(),
|
transformed.source_code(),
|
||||||
fixed.keys().copied(),
|
error,
|
||||||
);
|
fixed.keys().copied(),
|
||||||
return Err(anyhow!("Fix introduced a syntax error"));
|
);
|
||||||
|
return Err(anyhow!("Fix introduced a syntax error"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,7 +539,7 @@ pub fn lint_fix<'a>(
|
||||||
code: fixed_contents,
|
code: fixed_contents,
|
||||||
fixes: applied,
|
fixes: applied,
|
||||||
source_map,
|
source_map,
|
||||||
}) = fix_file(&result.data, &locator, unsafe_fixes)
|
}) = fix_file(&diagnostics, &locator, unsafe_fixes)
|
||||||
{
|
{
|
||||||
if iterations < MAX_ITERATIONS {
|
if iterations < MAX_ITERATIONS {
|
||||||
// Count the number of fixed errors.
|
// Count the number of fixed errors.
|
||||||
|
@ -559,13 +556,20 @@ pub fn lint_fix<'a>(
|
||||||
continue;
|
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 {
|
return Ok(FixerResult {
|
||||||
result: result.map(|diagnostics| {
|
result: LinterResult {
|
||||||
diagnostics_to_messages(diagnostics, parsed.errors(), path, &locator, &directives)
|
messages: diagnostics_to_messages(
|
||||||
}),
|
diagnostics,
|
||||||
|
parsed.errors(),
|
||||||
|
path,
|
||||||
|
&locator,
|
||||||
|
&directives,
|
||||||
|
),
|
||||||
|
has_syntax_error: !is_valid_syntax,
|
||||||
|
},
|
||||||
transformed,
|
transformed,
|
||||||
fixed,
|
fixed,
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,7 +22,7 @@ mod tests {
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::linter::{check_path, LinterResult};
|
use crate::linter::check_path;
|
||||||
use crate::registry::{AsRule, Linter, Rule};
|
use crate::registry::{AsRule, Linter, Rule};
|
||||||
use crate::rules::pyflakes;
|
use crate::rules::pyflakes;
|
||||||
use crate::settings::types::PreviewMode;
|
use crate::settings::types::PreviewMode;
|
||||||
|
@ -650,10 +650,7 @@ mod tests {
|
||||||
&locator,
|
&locator,
|
||||||
&indexer,
|
&indexer,
|
||||||
);
|
);
|
||||||
let LinterResult {
|
let mut diagnostics = check_path(
|
||||||
data: mut diagnostics,
|
|
||||||
..
|
|
||||||
} = check_path(
|
|
||||||
Path::new("<filename>"),
|
Path::new("<filename>"),
|
||||||
None,
|
None,
|
||||||
&locator,
|
&locator,
|
||||||
|
|
|
@ -23,7 +23,7 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::directives;
|
use crate::directives;
|
||||||
use crate::fix::{fix_file, FixResult};
|
use crate::fix::{fix_file, FixResult};
|
||||||
use crate::linter::{check_path, LinterResult};
|
use crate::linter::check_path;
|
||||||
use crate::message::{Emitter, EmitterContext, Message, TextEmitter};
|
use crate::message::{Emitter, EmitterContext, Message, TextEmitter};
|
||||||
use crate::packaging::detect_package_root;
|
use crate::packaging::detect_package_root;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
@ -119,10 +119,7 @@ pub(crate) fn test_contents<'a>(
|
||||||
&locator,
|
&locator,
|
||||||
&indexer,
|
&indexer,
|
||||||
);
|
);
|
||||||
let LinterResult {
|
let diagnostics = check_path(
|
||||||
data: diagnostics,
|
|
||||||
error,
|
|
||||||
} = check_path(
|
|
||||||
path,
|
path,
|
||||||
path.parent()
|
path.parent()
|
||||||
.and_then(|parent| detect_package_root(parent, &settings.namespace_packages)),
|
.and_then(|parent| detect_package_root(parent, &settings.namespace_packages)),
|
||||||
|
@ -137,7 +134,7 @@ pub(crate) fn test_contents<'a>(
|
||||||
&parsed,
|
&parsed,
|
||||||
);
|
);
|
||||||
|
|
||||||
let source_has_errors = error.is_some();
|
let source_has_errors = !parsed.is_valid();
|
||||||
|
|
||||||
// Detect fixes that don't converge after multiple iterations.
|
// Detect fixes that don't converge after multiple iterations.
|
||||||
let mut iterations = 0;
|
let mut iterations = 0;
|
||||||
|
@ -186,10 +183,7 @@ pub(crate) fn test_contents<'a>(
|
||||||
&indexer,
|
&indexer,
|
||||||
);
|
);
|
||||||
|
|
||||||
let LinterResult {
|
let fixed_diagnostics = check_path(
|
||||||
data: fixed_diagnostics,
|
|
||||||
..
|
|
||||||
} = check_path(
|
|
||||||
path,
|
path,
|
||||||
None,
|
None,
|
||||||
&locator,
|
&locator,
|
||||||
|
|
|
@ -68,7 +68,10 @@ pub(crate) fn fix_all(
|
||||||
// which is inconsistent with how `ruff check --fix` works.
|
// which is inconsistent with how `ruff check --fix` works.
|
||||||
let FixerResult {
|
let FixerResult {
|
||||||
transformed,
|
transformed,
|
||||||
result: LinterResult { error, .. },
|
result: LinterResult {
|
||||||
|
has_syntax_error: has_error,
|
||||||
|
..
|
||||||
|
},
|
||||||
..
|
..
|
||||||
} = ruff_linter::linter::lint_fix(
|
} = ruff_linter::linter::lint_fix(
|
||||||
&query.virtual_file_path(),
|
&query.virtual_file_path(),
|
||||||
|
@ -80,11 +83,9 @@ pub(crate) fn fix_all(
|
||||||
source_type,
|
source_type,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(error) = error {
|
if has_error {
|
||||||
// abort early if a parsing error occurred
|
// abort early if a parsing error occurred
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!("A parsing error occurred during `fix_all`"));
|
||||||
"A parsing error occurred during `fix_all`: {error}"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fast path: if `transformed` is still borrowed, no changes were made and we can return early
|
// fast path: if `transformed` is still borrowed, no changes were made and we can return early
|
||||||
|
|
|
@ -8,7 +8,7 @@ use ruff_diagnostics::{Applicability, Diagnostic, DiagnosticKind, Edit, Fix};
|
||||||
use ruff_linter::{
|
use ruff_linter::{
|
||||||
directives::{extract_directives, Flags},
|
directives::{extract_directives, Flags},
|
||||||
generate_noqa_edits,
|
generate_noqa_edits,
|
||||||
linter::{check_path, LinterResult},
|
linter::check_path,
|
||||||
packaging::detect_package_root,
|
packaging::detect_package_root,
|
||||||
registry::AsRule,
|
registry::AsRule,
|
||||||
settings::flags,
|
settings::flags,
|
||||||
|
@ -58,9 +58,9 @@ pub(crate) struct DiagnosticFix {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A series of diagnostics across a single text document or an arbitrary number of notebook cells.
|
/// A series of diagnostics across a single text document or an arbitrary number of notebook cells.
|
||||||
pub(crate) type Diagnostics = FxHashMap<lsp_types::Url, Vec<lsp_types::Diagnostic>>;
|
pub(crate) type DiagnosticsMap = FxHashMap<lsp_types::Url, Vec<lsp_types::Diagnostic>>;
|
||||||
|
|
||||||
pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> Diagnostics {
|
pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> DiagnosticsMap {
|
||||||
let source_kind = query.make_source_kind();
|
let source_kind = query.make_source_kind();
|
||||||
let file_resolver_settings = query.settings().file_resolver();
|
let file_resolver_settings = query.settings().file_resolver();
|
||||||
let linter_settings = query.settings().linter();
|
let linter_settings = query.settings().linter();
|
||||||
|
@ -80,7 +80,7 @@ pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> Diagno
|
||||||
exclusion,
|
exclusion,
|
||||||
document_path.display()
|
document_path.display()
|
||||||
);
|
);
|
||||||
return Diagnostics::default();
|
return DiagnosticsMap::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_package_root(
|
detect_package_root(
|
||||||
|
@ -113,7 +113,7 @@ pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> Diagno
|
||||||
let directives = extract_directives(parsed.tokens(), Flags::all(), &locator, &indexer);
|
let directives = extract_directives(parsed.tokens(), Flags::all(), &locator, &indexer);
|
||||||
|
|
||||||
// Generate checks.
|
// Generate checks.
|
||||||
let LinterResult { data, .. } = check_path(
|
let diagnostics = check_path(
|
||||||
&query.virtual_file_path(),
|
&query.virtual_file_path(),
|
||||||
package,
|
package,
|
||||||
&locator,
|
&locator,
|
||||||
|
@ -129,7 +129,7 @@ pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> Diagno
|
||||||
|
|
||||||
let noqa_edits = generate_noqa_edits(
|
let noqa_edits = generate_noqa_edits(
|
||||||
&query.virtual_file_path(),
|
&query.virtual_file_path(),
|
||||||
data.as_slice(),
|
&diagnostics,
|
||||||
&locator,
|
&locator,
|
||||||
indexer.comment_ranges(),
|
indexer.comment_ranges(),
|
||||||
&linter_settings.external,
|
&linter_settings.external,
|
||||||
|
@ -137,19 +137,21 @@ pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> Diagno
|
||||||
stylist.line_ending(),
|
stylist.line_ending(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut diagnostics = Diagnostics::default();
|
let mut diagnostics_map = DiagnosticsMap::default();
|
||||||
|
|
||||||
// Populates all relevant URLs with an empty diagnostic list.
|
// Populates all relevant URLs with an empty diagnostic list.
|
||||||
// This ensures that documents without diagnostics still get updated.
|
// This ensures that documents without diagnostics still get updated.
|
||||||
if let Some(notebook) = query.as_notebook() {
|
if let Some(notebook) = query.as_notebook() {
|
||||||
for url in notebook.urls() {
|
for url in notebook.urls() {
|
||||||
diagnostics.entry(url.clone()).or_default();
|
diagnostics_map.entry(url.clone()).or_default();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
diagnostics.entry(query.make_key().into_url()).or_default();
|
diagnostics_map
|
||||||
|
.entry(query.make_key().into_url())
|
||||||
|
.or_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
let lsp_diagnostics = data
|
let lsp_diagnostics = diagnostics
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(noqa_edits)
|
.zip(noqa_edits)
|
||||||
.map(|(diagnostic, noqa_edit)| {
|
.map(|(diagnostic, noqa_edit)| {
|
||||||
|
@ -165,18 +167,21 @@ pub(crate) fn check(query: &DocumentQuery, encoding: PositionEncoding) -> Diagno
|
||||||
tracing::warn!("Unable to find notebook cell at index {index}.");
|
tracing::warn!("Unable to find notebook cell at index {index}.");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
diagnostics.entry(uri.clone()).or_default().push(diagnostic);
|
diagnostics_map
|
||||||
|
.entry(uri.clone())
|
||||||
|
.or_default()
|
||||||
|
.push(diagnostic);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (_, diagnostic) in lsp_diagnostics {
|
for (_, diagnostic) in lsp_diagnostics {
|
||||||
diagnostics
|
diagnostics_map
|
||||||
.entry(query.make_key().into_url())
|
.entry(query.make_key().into_url())
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(diagnostic);
|
.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics
|
diagnostics_map
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts LSP diagnostics to a list of `DiagnosticFix`es by deserializing associated data on each diagnostic.
|
/// Converts LSP diagnostics to a list of `DiagnosticFix`es by deserializing associated data on each diagnostic.
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
lint::Diagnostics,
|
lint::DiagnosticsMap,
|
||||||
server::client::Notifier,
|
server::client::Notifier,
|
||||||
session::{DocumentQuery, DocumentSnapshot},
|
session::{DocumentQuery, DocumentSnapshot},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::LSPResult;
|
use super::LSPResult;
|
||||||
|
|
||||||
pub(super) fn generate_diagnostics(snapshot: &DocumentSnapshot) -> Diagnostics {
|
pub(super) fn generate_diagnostics(snapshot: &DocumentSnapshot) -> DiagnosticsMap {
|
||||||
if snapshot.client_settings().lint() {
|
if snapshot.client_settings().lint() {
|
||||||
let document = snapshot.query();
|
let document = snapshot.query();
|
||||||
crate::lint::check(document, snapshot.encoding())
|
crate::lint::check(document, snapshot.encoding())
|
||||||
} else {
|
} else {
|
||||||
Diagnostics::default()
|
DiagnosticsMap::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use ruff_formatter::printer::SourceMapGeneration;
|
||||||
use ruff_formatter::{FormatResult, Formatted, IndentStyle};
|
use ruff_formatter::{FormatResult, Formatted, IndentStyle};
|
||||||
use ruff_linter::directives;
|
use ruff_linter::directives;
|
||||||
use ruff_linter::line_width::{IndentWidth, LineLength};
|
use ruff_linter::line_width::{IndentWidth, LineLength};
|
||||||
use ruff_linter::linter::{check_path, LinterResult};
|
use ruff_linter::linter::check_path;
|
||||||
use ruff_linter::registry::AsRule;
|
use ruff_linter::registry::AsRule;
|
||||||
use ruff_linter::settings::types::PythonVersion;
|
use ruff_linter::settings::types::PythonVersion;
|
||||||
use ruff_linter::settings::{flags, DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX};
|
use ruff_linter::settings::{flags, DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX};
|
||||||
|
@ -181,9 +181,7 @@ impl Workspace {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generate checks.
|
// Generate checks.
|
||||||
let LinterResult {
|
let diagnostics = check_path(
|
||||||
data: diagnostics, ..
|
|
||||||
} = check_path(
|
|
||||||
Path::new("<filename>"),
|
Path::new("<filename>"),
|
||||||
None,
|
None,
|
||||||
&locator,
|
&locator,
|
||||||
|
|
|
@ -27,23 +27,23 @@ fn do_fuzz(case: &[u8]) -> Corpus {
|
||||||
let linter_settings = SETTINGS.get_or_init(LinterSettings::default);
|
let linter_settings = SETTINGS.get_or_init(LinterSettings::default);
|
||||||
let format_options = PyFormatOptions::default();
|
let format_options = PyFormatOptions::default();
|
||||||
|
|
||||||
let linter_results = ruff_linter::linter::lint_only(
|
let linter_result = ruff_linter::linter::lint_only(
|
||||||
"fuzzed-source.py".as_ref(),
|
"fuzzed-source.py".as_ref(),
|
||||||
None,
|
None,
|
||||||
&linter_settings,
|
linter_settings,
|
||||||
Noqa::Enabled,
|
Noqa::Enabled,
|
||||||
&SourceKind::Python(code.to_string()),
|
&SourceKind::Python(code.to_string()),
|
||||||
PySourceType::Python,
|
PySourceType::Python,
|
||||||
ParseSource::None,
|
ParseSource::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if linter_results.error.is_some() {
|
if linter_result.has_syntax_error {
|
||||||
return Corpus::Keep; // keep, but don't continue
|
return Corpus::Keep; // keep, but don't continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut warnings = HashMap::new();
|
let mut warnings = HashMap::new();
|
||||||
|
|
||||||
for msg in &linter_results.data {
|
for msg in &linter_result.messages {
|
||||||
let count: &mut usize = warnings.entry(msg.name()).or_default();
|
let count: &mut usize = warnings.entry(msg.name()).or_default();
|
||||||
*count += 1;
|
*count += 1;
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,10 @@ fn do_fuzz(case: &[u8]) -> Corpus {
|
||||||
if let Ok(formatted) = format_module_source(code, format_options.clone()) {
|
if let Ok(formatted) = format_module_source(code, format_options.clone()) {
|
||||||
let formatted = formatted.as_code().to_string();
|
let formatted = formatted.as_code().to_string();
|
||||||
|
|
||||||
let linter_results = ruff_linter::linter::lint_only(
|
let linter_result = ruff_linter::linter::lint_only(
|
||||||
"fuzzed-source.py".as_ref(),
|
"fuzzed-source.py".as_ref(),
|
||||||
None,
|
None,
|
||||||
&linter_settings,
|
linter_settings,
|
||||||
Noqa::Enabled,
|
Noqa::Enabled,
|
||||||
&SourceKind::Python(formatted.clone()),
|
&SourceKind::Python(formatted.clone()),
|
||||||
PySourceType::Python,
|
PySourceType::Python,
|
||||||
|
@ -63,11 +63,11 @@ fn do_fuzz(case: &[u8]) -> Corpus {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
linter_results.error.is_none(),
|
!linter_result.has_syntax_error,
|
||||||
"formatter introduced a parse error"
|
"formatter introduced a parse error"
|
||||||
);
|
);
|
||||||
|
|
||||||
for msg in &linter_results.data {
|
for msg in &linter_result.messages {
|
||||||
if let Some(count) = warnings.get_mut(msg.name()) {
|
if let Some(count) = warnings.get_mut(msg.name()) {
|
||||||
if let Some(decremented) = count.checked_sub(1) {
|
if let Some(decremented) = count.checked_sub(1) {
|
||||||
*count = decremented;
|
*count = decremented;
|
||||||
|
@ -77,7 +77,6 @@ fn do_fuzz(case: &[u8]) -> Corpus {
|
||||||
TextDiff::from_lines(code, &formatted)
|
TextDiff::from_lines(code, &formatted)
|
||||||
.unified_diff()
|
.unified_diff()
|
||||||
.header("Unformatted", "Formatted")
|
.header("Unformatted", "Formatted")
|
||||||
.to_string()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -86,7 +85,6 @@ fn do_fuzz(case: &[u8]) -> Corpus {
|
||||||
TextDiff::from_lines(code, &formatted)
|
TextDiff::from_lines(code, &formatted)
|
||||||
.unified_diff()
|
.unified_diff()
|
||||||
.header("Unformatted", "Formatted")
|
.header("Unformatted", "Formatted")
|
||||||
.to_string()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue