mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 06:11:21 +00:00
Start detecting version-related syntax errors in the parser (#16090)
## Summary This PR builds on the changes in #16220 to pass a target Python version to the parser. It also adds the `Parser::unsupported_syntax_errors` field, which collects version-related syntax errors while parsing. These syntax errors are then turned into `Message`s in ruff (in preview mode). This PR only detects one syntax error (`match` statement before Python 3.10), but it has been pretty quick to extend to several other simple errors (see #16308 for example). ## Test Plan The current tests are CLI tests in the linter crate, but these could be supplemented with inline parser tests after #16357. I also tested the display of these syntax errors in VS Code:   --------- Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
b39a4ad01d
commit
78806361fd
14 changed files with 356 additions and 37 deletions
|
@ -24,7 +24,7 @@ use ruff_linter::{
|
|||
use ruff_notebook::Notebook;
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
use ruff_python_parser::ParseError;
|
||||
use ruff_python_parser::{ParseError, ParseOptions, UnsupportedSyntaxError};
|
||||
use ruff_source_file::LineIndex;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
|
@ -94,8 +94,18 @@ pub(crate) fn check(
|
|||
|
||||
let source_type = query.source_type();
|
||||
|
||||
let target_version = if let Some(path) = &document_path {
|
||||
settings.linter.resolve_target_version(path)
|
||||
} else {
|
||||
settings.linter.unresolved_target_version
|
||||
};
|
||||
|
||||
let parse_options = ParseOptions::from(source_type).with_target_version(target_version);
|
||||
|
||||
// Parse once.
|
||||
let parsed = ruff_python_parser::parse_unchecked_source(source_kind.source_code(), source_type);
|
||||
let parsed = ruff_python_parser::parse_unchecked(source_kind.source_code(), parse_options)
|
||||
.try_into_module()
|
||||
.expect("PySourceType always parses to a ModModule");
|
||||
|
||||
// Map row and column locations to byte slices (lazily).
|
||||
let locator = Locator::new(source_kind.source_code());
|
||||
|
@ -122,6 +132,7 @@ pub(crate) fn check(
|
|||
&source_kind,
|
||||
source_type,
|
||||
&parsed,
|
||||
target_version,
|
||||
);
|
||||
|
||||
let noqa_edits = generate_noqa_edits(
|
||||
|
@ -164,14 +175,25 @@ pub(crate) fn check(
|
|||
let lsp_diagnostics = lsp_diagnostics.chain(
|
||||
show_syntax_errors
|
||||
.then(|| {
|
||||
parsed.errors().iter().map(|parse_error| {
|
||||
parse_error_to_lsp_diagnostic(
|
||||
parse_error,
|
||||
&source_kind,
|
||||
locator.to_index(),
|
||||
encoding,
|
||||
)
|
||||
})
|
||||
parsed
|
||||
.errors()
|
||||
.iter()
|
||||
.map(|parse_error| {
|
||||
parse_error_to_lsp_diagnostic(
|
||||
parse_error,
|
||||
&source_kind,
|
||||
locator.to_index(),
|
||||
encoding,
|
||||
)
|
||||
})
|
||||
.chain(parsed.unsupported_syntax_errors().iter().map(|error| {
|
||||
unsupported_syntax_error_to_lsp_diagnostic(
|
||||
error,
|
||||
&source_kind,
|
||||
locator.to_index(),
|
||||
encoding,
|
||||
)
|
||||
}))
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
|
@ -350,6 +372,45 @@ fn parse_error_to_lsp_diagnostic(
|
|||
)
|
||||
}
|
||||
|
||||
fn unsupported_syntax_error_to_lsp_diagnostic(
|
||||
unsupported_syntax_error: &UnsupportedSyntaxError,
|
||||
source_kind: &SourceKind,
|
||||
index: &LineIndex,
|
||||
encoding: PositionEncoding,
|
||||
) -> (usize, lsp_types::Diagnostic) {
|
||||
let range: lsp_types::Range;
|
||||
let cell: usize;
|
||||
|
||||
if let Some(notebook_index) = source_kind.as_ipy_notebook().map(Notebook::index) {
|
||||
NotebookRange { cell, range } = unsupported_syntax_error.range.to_notebook_range(
|
||||
source_kind.source_code(),
|
||||
index,
|
||||
notebook_index,
|
||||
encoding,
|
||||
);
|
||||
} else {
|
||||
cell = usize::default();
|
||||
range = unsupported_syntax_error
|
||||
.range
|
||||
.to_range(source_kind.source_code(), index, encoding);
|
||||
}
|
||||
|
||||
(
|
||||
cell,
|
||||
lsp_types::Diagnostic {
|
||||
range,
|
||||
severity: Some(lsp_types::DiagnosticSeverity::ERROR),
|
||||
tags: None,
|
||||
code: None,
|
||||
code_description: None,
|
||||
source: Some(DIAGNOSTIC_NAME.into()),
|
||||
message: format!("SyntaxError: {unsupported_syntax_error}"),
|
||||
related_information: None,
|
||||
data: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn diagnostic_edit_range(
|
||||
range: TextRange,
|
||||
source_kind: &SourceKind,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue