-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf: Segregate syntax and semantic diagnostics #17775
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -96,6 +96,7 @@ use syntax::{ | |||||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||||||||||
pub enum DiagnosticCode { | ||||||||||
RustcHardError(&'static str), | ||||||||||
SyntaxError, | ||||||||||
RustcLint(&'static str), | ||||||||||
Clippy(&'static str), | ||||||||||
Ra(&'static str, Severity), | ||||||||||
|
@@ -107,6 +108,9 @@ impl DiagnosticCode { | |||||||||
DiagnosticCode::RustcHardError(e) => { | ||||||||||
format!("https://doc.rust-lang.org/stable/error_codes/{e}.html") | ||||||||||
} | ||||||||||
DiagnosticCode::SyntaxError => { | ||||||||||
String::from("https://doc.rust-lang.org/stable/reference/") | ||||||||||
} | ||||||||||
DiagnosticCode::RustcLint(e) => { | ||||||||||
format!("https://doc.rust-lang.org/rustc/?search={e}") | ||||||||||
} | ||||||||||
|
@@ -125,6 +129,7 @@ impl DiagnosticCode { | |||||||||
| DiagnosticCode::RustcLint(r) | ||||||||||
| DiagnosticCode::Clippy(r) | ||||||||||
| DiagnosticCode::Ra(r, _) => r, | ||||||||||
DiagnosticCode::SyntaxError => "syntax-error", | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
@@ -154,7 +159,7 @@ impl Diagnostic { | |||||||||
message, | ||||||||||
range: range.into(), | ||||||||||
severity: match code { | ||||||||||
DiagnosticCode::RustcHardError(_) => Severity::Error, | ||||||||||
DiagnosticCode::RustcHardError(_) | DiagnosticCode::SyntaxError => Severity::Error, | ||||||||||
// FIXME: Rustc lints are not always warning, but the ones that are currently implemented are all warnings. | ||||||||||
DiagnosticCode::RustcLint(_) => Severity::Warning, | ||||||||||
// FIXME: We can make this configurable, and if the user uses `cargo clippy` on flycheck, we can | ||||||||||
|
@@ -297,31 +302,54 @@ impl DiagnosticsContext<'_> { | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/// Request diagnostics for the given [`FileId`]. The produced diagnostics may point to other files | ||||||||||
/// Request parser level diagnostics for the given [`FileId`]. | ||||||||||
pub fn syntax_diagnostics( | ||||||||||
db: &RootDatabase, | ||||||||||
config: &DiagnosticsConfig, | ||||||||||
file_id: FileId, | ||||||||||
) -> Vec<Diagnostic> { | ||||||||||
let _p = tracing::info_span!("syntax_diagnostics").entered(); | ||||||||||
|
||||||||||
if config.disabled.contains("syntax-error") { | ||||||||||
return Vec::new(); | ||||||||||
} | ||||||||||
|
||||||||||
let sema = Semantics::new(db); | ||||||||||
let file_id = sema | ||||||||||
.attach_first_edition(file_id) | ||||||||||
.unwrap_or_else(|| EditionedFileId::current_edition(file_id)); | ||||||||||
|
||||||||||
// [#3434] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | ||||||||||
db.parse_errors(file_id) | ||||||||||
.as_deref() | ||||||||||
.into_iter() | ||||||||||
.flatten() | ||||||||||
.take(128) | ||||||||||
.map(|err| { | ||||||||||
Diagnostic::new( | ||||||||||
DiagnosticCode::SyntaxError, | ||||||||||
format!("Syntax Error: {err}"), | ||||||||||
FileRange { file_id: file_id.into(), range: err.range() }, | ||||||||||
) | ||||||||||
}) | ||||||||||
.collect() | ||||||||||
} | ||||||||||
|
||||||||||
/// Request semantic diagnostics for the given [`FileId`]. The produced diagnostics may point to other files | ||||||||||
/// due to macros. | ||||||||||
pub fn diagnostics( | ||||||||||
pub fn semantic_diagnostics( | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling rust-analyzer/crates/base-db/src/lib.rs Lines 60 to 63 in aa00ddc
|
||||||||||
db: &RootDatabase, | ||||||||||
config: &DiagnosticsConfig, | ||||||||||
resolve: &AssistResolveStrategy, | ||||||||||
file_id: FileId, | ||||||||||
) -> Vec<Diagnostic> { | ||||||||||
let _p = tracing::info_span!("diagnostics").entered(); | ||||||||||
let _p = tracing::info_span!("semantic_diagnostics").entered(); | ||||||||||
let sema = Semantics::new(db); | ||||||||||
let file_id = sema | ||||||||||
.attach_first_edition(file_id) | ||||||||||
.unwrap_or_else(|| EditionedFileId::current_edition(file_id)); | ||||||||||
let mut res = Vec::new(); | ||||||||||
|
||||||||||
// [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | ||||||||||
res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| { | ||||||||||
Diagnostic::new( | ||||||||||
DiagnosticCode::RustcHardError("syntax-error"), | ||||||||||
format!("Syntax Error: {err}"), | ||||||||||
FileRange { file_id: file_id.into(), range: err.range() }, | ||||||||||
) | ||||||||||
})); | ||||||||||
let parse_errors = res.len(); | ||||||||||
|
||||||||||
let parse = sema.parse(file_id); | ||||||||||
|
||||||||||
// FIXME: This iterates the entire file which is a rather expensive operation. | ||||||||||
|
@@ -341,8 +369,11 @@ pub fn diagnostics( | |||||||||
match module { | ||||||||||
// A bunch of parse errors in a file indicate some bigger structural parse changes in the | ||||||||||
// file, so we skip semantic diagnostics so we can show these faster. | ||||||||||
Some(m) if parse_errors < 16 => m.diagnostics(db, &mut diags, config.style_lints), | ||||||||||
Some(_) => (), | ||||||||||
Some(m) => { | ||||||||||
if !db.parse_errors(file_id).as_deref().is_some_and(|es| es.len() >= 16) { | ||||||||||
m.diagnostics(db, &mut diags, config.style_lints); | ||||||||||
} | ||||||||||
} | ||||||||||
None => handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id.file_id()), | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -363,7 +394,7 @@ pub fn diagnostics( | |||||||||
res.extend(d.errors.iter().take(16).map(|err| { | ||||||||||
{ | ||||||||||
Diagnostic::new( | ||||||||||
DiagnosticCode::RustcHardError("syntax-error"), | ||||||||||
DiagnosticCode::SyntaxError, | ||||||||||
format!("Syntax Error in Expansion: {err}"), | ||||||||||
ctx.resolve_precise_location(&d.node.clone(), d.precise_location), | ||||||||||
) | ||||||||||
|
@@ -464,6 +495,19 @@ pub fn diagnostics( | |||||||||
res | ||||||||||
} | ||||||||||
|
||||||||||
/// Request both syntax and semantic diagnostics for the given [`FileId`]. | ||||||||||
pub fn full_diagnostics( | ||||||||||
db: &RootDatabase, | ||||||||||
config: &DiagnosticsConfig, | ||||||||||
resolve: &AssistResolveStrategy, | ||||||||||
file_id: FileId, | ||||||||||
) -> Vec<Diagnostic> { | ||||||||||
let mut res = syntax_diagnostics(db, config, file_id); | ||||||||||
let sema = semantic_diagnostics(db, config, resolve, file_id); | ||||||||||
res.extend(sema); | ||||||||||
res | ||||||||||
} | ||||||||||
|
||||||||||
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros | ||||||||||
|
||||||||||
static RUSTC_LINT_GROUPS_DICT: Lazy<FxHashMap<&str, Vec<&str>>> = | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previous comment was pointing the wrong issue no.34344