Add an AnalysisConfig structure and use it to configure diagnostics run
This commit is contained in:
parent
c463d217a1
commit
90857ff8b0
5 changed files with 57 additions and 26 deletions
|
|
@ -14,7 +14,7 @@
|
|||
//! subsystem provides a separate, non-query-based API which can walk all stored
|
||||
//! values and transform them into instances of `Diagnostic`.
|
||||
|
||||
use std::{any::Any, collections::HashSet, fmt};
|
||||
use std::{any::Any, fmt};
|
||||
|
||||
use ra_syntax::{SyntaxNode, SyntaxNodePtr};
|
||||
|
||||
|
|
@ -50,16 +50,10 @@ pub struct DiagnosticSink<'a> {
|
|||
callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
|
||||
filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
|
||||
default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
|
||||
disabled_diagnostics: HashSet<String>,
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticSink<'a> {
|
||||
pub fn push(&mut self, d: impl Diagnostic) {
|
||||
if self.disabled_diagnostics.contains(&d.name()) {
|
||||
// This diagnostic is disabled, ignore it completely.
|
||||
return;
|
||||
}
|
||||
|
||||
let d: &dyn Diagnostic = &d;
|
||||
self._push(d);
|
||||
}
|
||||
|
|
@ -83,12 +77,11 @@ impl<'a> DiagnosticSink<'a> {
|
|||
pub struct DiagnosticSinkBuilder<'a> {
|
||||
callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
|
||||
filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
|
||||
disabled_diagnostics: HashSet<String>,
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticSinkBuilder<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self { callbacks: Vec::new(), filters: Vec::new(), disabled_diagnostics: HashSet::new() }
|
||||
Self { callbacks: Vec::new(), filters: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self {
|
||||
|
|
@ -108,17 +101,11 @@ impl<'a> DiagnosticSinkBuilder<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn disable_diagnostic(mut self, diagnostic: impl Into<String>) -> Self {
|
||||
self.disabled_diagnostics.insert(diagnostic.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
|
||||
DiagnosticSink {
|
||||
callbacks: self.callbacks,
|
||||
filters: self.filters,
|
||||
default_callback: Box::new(default_callback),
|
||||
disabled_diagnostics: self.disabled_diagnostics,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use ra_syntax::{
|
|||
};
|
||||
use ra_text_edit::{TextEdit, TextEditBuilder};
|
||||
|
||||
use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit};
|
||||
use crate::{AnalysisConfig, Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Severity {
|
||||
|
|
@ -33,6 +33,7 @@ pub(crate) fn diagnostics(
|
|||
db: &RootDatabase,
|
||||
file_id: FileId,
|
||||
enable_experimental: bool,
|
||||
analysis_config: &AnalysisConfig,
|
||||
) -> Vec<Diagnostic> {
|
||||
let _p = profile("diagnostics");
|
||||
let sema = Semantics::new(db);
|
||||
|
|
@ -41,6 +42,7 @@ pub(crate) fn diagnostics(
|
|||
|
||||
// [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
|
||||
res.extend(parse.errors().iter().take(128).map(|err| Diagnostic {
|
||||
name: None,
|
||||
range: err.range(),
|
||||
message: format!("Syntax Error: {}", err),
|
||||
severity: Severity::Error,
|
||||
|
|
@ -52,7 +54,7 @@ pub(crate) fn diagnostics(
|
|||
check_struct_shorthand_initialization(&mut res, file_id, &node);
|
||||
}
|
||||
let res = RefCell::new(res);
|
||||
let mut sink = DiagnosticSinkBuilder::new()
|
||||
let mut sink_builder = DiagnosticSinkBuilder::new()
|
||||
.on::<hir::diagnostics::UnresolvedModule, _>(|d| {
|
||||
let original_file = d.source().file_id.original_file(db);
|
||||
let fix = Fix::new(
|
||||
|
|
@ -61,6 +63,7 @@ pub(crate) fn diagnostics(
|
|||
.into(),
|
||||
);
|
||||
res.borrow_mut().push(Diagnostic {
|
||||
name: Some(d.name()),
|
||||
range: sema.diagnostics_range(d).range,
|
||||
message: d.message(),
|
||||
severity: Severity::Error,
|
||||
|
|
@ -95,6 +98,7 @@ pub(crate) fn diagnostics(
|
|||
};
|
||||
|
||||
res.borrow_mut().push(Diagnostic {
|
||||
name: Some(d.name()),
|
||||
range: sema.diagnostics_range(d).range,
|
||||
message: d.message(),
|
||||
severity: Severity::Error,
|
||||
|
|
@ -108,6 +112,7 @@ pub(crate) fn diagnostics(
|
|||
let source_change = SourceFileEdit { file_id, edit }.into();
|
||||
let fix = Fix::new("Wrap with ok", source_change);
|
||||
res.borrow_mut().push(Diagnostic {
|
||||
name: Some(d.name()),
|
||||
range: sema.diagnostics_range(d).range,
|
||||
message: d.message(),
|
||||
severity: Severity::Error,
|
||||
|
|
@ -116,6 +121,7 @@ pub(crate) fn diagnostics(
|
|||
})
|
||||
.on::<hir::diagnostics::NoSuchField, _>(|d| {
|
||||
res.borrow_mut().push(Diagnostic {
|
||||
name: Some(d.name()),
|
||||
range: sema.diagnostics_range(d).range,
|
||||
message: d.message(),
|
||||
severity: Severity::Error,
|
||||
|
|
@ -123,10 +129,20 @@ pub(crate) fn diagnostics(
|
|||
})
|
||||
})
|
||||
// Only collect experimental diagnostics when they're enabled.
|
||||
.filter(|diag| !diag.is_experimental() || enable_experimental)
|
||||
.filter(|diag| !diag.is_experimental() || enable_experimental);
|
||||
|
||||
if !analysis_config.disabled_diagnostics.is_empty() {
|
||||
// Do not collect disabled diagnostics.
|
||||
sink_builder = sink_builder
|
||||
.filter(|diag| !analysis_config.disabled_diagnostics.contains(&diag.name()));
|
||||
}
|
||||
|
||||
// Finalize the `DiagnosticSink` building process.
|
||||
let mut sink = sink_builder
|
||||
// Diagnostics not handled above get no fix and default treatment.
|
||||
.build(|d| {
|
||||
res.borrow_mut().push(Diagnostic {
|
||||
name: Some(d.name()),
|
||||
message: d.message(),
|
||||
range: sema.diagnostics_range(d).range,
|
||||
severity: Severity::Error,
|
||||
|
|
@ -234,6 +250,7 @@ fn check_unnecessary_braces_in_use_statement(
|
|||
});
|
||||
|
||||
acc.push(Diagnostic {
|
||||
name: None,
|
||||
range,
|
||||
message: "Unnecessary braces in use statement".to_string(),
|
||||
severity: Severity::WeakWarning,
|
||||
|
|
@ -279,6 +296,7 @@ fn check_struct_shorthand_initialization(
|
|||
let edit = edit_builder.finish();
|
||||
|
||||
acc.push(Diagnostic {
|
||||
name: None,
|
||||
range: record_field.syntax().text_range(),
|
||||
message: "Shorthand struct initialization".to_string(),
|
||||
severity: Severity::WeakWarning,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ mod syntax_highlighting;
|
|||
mod syntax_tree;
|
||||
mod typing;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_db::{
|
||||
|
|
@ -100,8 +100,15 @@ pub use ra_text_edit::{Indel, TextEdit};
|
|||
|
||||
pub type Cancelable<T> = Result<T, Canceled>;
|
||||
|
||||
/// Configuration parameters for the analysis run.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct AnalysisConfig {
|
||||
pub disabled_diagnostics: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Diagnostic {
|
||||
pub name: Option<String>,
|
||||
pub message: String,
|
||||
pub range: TextRange,
|
||||
pub severity: Severity,
|
||||
|
|
@ -139,11 +146,16 @@ impl<T> RangeInfo<T> {
|
|||
#[derive(Debug)]
|
||||
pub struct AnalysisHost {
|
||||
db: RootDatabase,
|
||||
config: AnalysisConfig,
|
||||
}
|
||||
|
||||
impl AnalysisHost {
|
||||
pub fn new(lru_capacity: Option<usize>) -> AnalysisHost {
|
||||
AnalysisHost { db: RootDatabase::new(lru_capacity) }
|
||||
pub fn new(lru_capacity: Option<usize>) -> Self {
|
||||
Self::with_config(lru_capacity, AnalysisConfig::default())
|
||||
}
|
||||
|
||||
pub fn with_config(lru_capacity: Option<usize>, config: AnalysisConfig) -> Self {
|
||||
AnalysisHost { db: RootDatabase::new(lru_capacity), config }
|
||||
}
|
||||
|
||||
pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
|
||||
|
|
@ -153,7 +165,7 @@ impl AnalysisHost {
|
|||
/// Returns a snapshot of the current state, which you can query for
|
||||
/// semantic information.
|
||||
pub fn analysis(&self) -> Analysis {
|
||||
Analysis { db: self.db.snapshot() }
|
||||
Analysis { db: self.db.snapshot(), config: self.config.clone() }
|
||||
}
|
||||
|
||||
/// Applies changes to the current state of the world. If there are
|
||||
|
|
@ -197,6 +209,7 @@ impl Default for AnalysisHost {
|
|||
#[derive(Debug)]
|
||||
pub struct Analysis {
|
||||
db: salsa::Snapshot<RootDatabase>,
|
||||
config: AnalysisConfig,
|
||||
}
|
||||
|
||||
// As a general design guideline, `Analysis` API are intended to be independent
|
||||
|
|
@ -492,7 +505,7 @@ impl Analysis {
|
|||
file_id: FileId,
|
||||
enable_experimental: bool,
|
||||
) -> Cancelable<Vec<Diagnostic>> {
|
||||
self.with_db(|db| diagnostics::diagnostics(db, file_id, enable_experimental))
|
||||
self.with_db(|db| diagnostics::diagnostics(db, file_id, enable_experimental, &self.config))
|
||||
}
|
||||
|
||||
/// Returns the edit required to rename reference at the position to the new
|
||||
|
|
@ -518,6 +531,11 @@ impl Analysis {
|
|||
})
|
||||
}
|
||||
|
||||
/// Sets the provided config.
|
||||
pub fn set_config(&mut self, config: AnalysisConfig) {
|
||||
self.config = config;
|
||||
}
|
||||
|
||||
/// Performs an operation on that may be Canceled.
|
||||
fn with_db<F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, T>(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
//! configure the server itself, feature flags are passed into analysis, and
|
||||
//! tweak things like automatic insertion of `()` in completions.
|
||||
|
||||
use std::{ffi::OsString, path::PathBuf};
|
||||
use std::{collections::HashSet, ffi::OsString, path::PathBuf};
|
||||
|
||||
use flycheck::FlycheckConfig;
|
||||
use lsp_types::ClientCapabilities;
|
||||
use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
|
||||
use ra_ide::{AnalysisConfig, AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
|
||||
use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
|
||||
use serde::Deserialize;
|
||||
use vfs::AbsPathBuf;
|
||||
|
|
@ -45,6 +45,8 @@ pub struct Config {
|
|||
pub with_sysroot: bool,
|
||||
pub linked_projects: Vec<LinkedProject>,
|
||||
pub root_path: AbsPathBuf,
|
||||
|
||||
pub analysis: AnalysisConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
@ -176,6 +178,8 @@ impl Config {
|
|||
hover: HoverConfig::default(),
|
||||
linked_projects: Vec::new(),
|
||||
root_path,
|
||||
|
||||
analysis: AnalysisConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -293,6 +297,8 @@ impl Config {
|
|||
goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef,
|
||||
};
|
||||
|
||||
self.analysis = AnalysisConfig { disabled_diagnostics: data.analysis_disabledDiagnostics };
|
||||
|
||||
log::info!("Config::update() = {:#?}", self);
|
||||
}
|
||||
|
||||
|
|
@ -444,5 +450,7 @@ config_data! {
|
|||
rustfmt_overrideCommand: Option<Vec<String>> = None,
|
||||
|
||||
withSysroot: bool = true,
|
||||
|
||||
analysis_disabledDiagnostics: HashSet<String> = HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ impl GlobalState {
|
|||
Handle { handle, receiver }
|
||||
};
|
||||
|
||||
let analysis_host = AnalysisHost::new(config.lru_capacity);
|
||||
let analysis_host = AnalysisHost::with_config(config.lru_capacity, config.analysis.clone());
|
||||
let (flycheck_sender, flycheck_receiver) = unbounded();
|
||||
GlobalState {
|
||||
sender,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue