mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Move the DiagnosticsWithFix trait on the ide level
This commit is contained in:
parent
9368619939
commit
29fbc8e021
7 changed files with 75 additions and 63 deletions
|
@ -1,8 +1,6 @@
|
||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
pub use hir_def::diagnostics::UnresolvedModule;
|
pub use hir_def::diagnostics::UnresolvedModule;
|
||||||
pub use hir_expand::diagnostics::{
|
pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder};
|
||||||
Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, DiagnosticWithFix,
|
|
||||||
};
|
|
||||||
pub use hir_ty::diagnostics::{
|
pub use hir_ty::diagnostics::{
|
||||||
MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
|
MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ use hir_def::{
|
||||||
resolver::{self, HasResolver, Resolver},
|
resolver::{self, HasResolver, Resolver},
|
||||||
AsMacroCall, FunctionId, TraitId, VariantId,
|
AsMacroCall, FunctionId, TraitId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::{diagnostics::DiagnosticWithFix, hygiene::Hygiene, name::AsName, ExpansionInfo};
|
use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo};
|
||||||
use hir_ty::associated_type_shorthand_candidates;
|
use hir_ty::associated_type_shorthand_candidates;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ra_db::{FileId, FileRange};
|
use ra_db::{FileId, FileRange};
|
||||||
|
@ -109,14 +109,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
self.imp.parse(file_id)
|
self.imp.parse(file_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diagnostic_fix_source<T: DiagnosticWithFix + Diagnostic>(
|
pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
|
||||||
&self,
|
self.imp.cache(root_node, file_id)
|
||||||
d: &T,
|
|
||||||
) -> Option<<T as DiagnosticWithFix>::AST> {
|
|
||||||
let file_id = d.presentation().file_id;
|
|
||||||
let root = self.db.parse_or_expand(file_id)?;
|
|
||||||
self.imp.cache(root, file_id);
|
|
||||||
d.fix_source(self.db.upcast())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
|
pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use hir_expand::diagnostics::{Diagnostic, DiagnosticWithFix};
|
use hir_expand::diagnostics::Diagnostic;
|
||||||
use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
|
use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
|
||||||
|
|
||||||
use hir_expand::{HirFileId, InFile};
|
use hir_expand::{HirFileId, InFile};
|
||||||
|
@ -25,11 +25,3 @@ impl Diagnostic for UnresolvedModule {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticWithFix for UnresolvedModule {
|
|
||||||
type AST = ast::Module;
|
|
||||||
fn fix_source(&self, db: &dyn hir_expand::db::AstDatabase) -> Option<Self::AST> {
|
|
||||||
let root = db.parse_or_expand(self.file)?;
|
|
||||||
Some(self.decl.to_node(&root))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::{any::Any, fmt};
|
||||||
|
|
||||||
use ra_syntax::SyntaxNodePtr;
|
use ra_syntax::SyntaxNodePtr;
|
||||||
|
|
||||||
use crate::{db::AstDatabase, InFile};
|
use crate::InFile;
|
||||||
|
|
||||||
pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
|
pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
|
||||||
fn message(&self) -> String;
|
fn message(&self) -> String;
|
||||||
|
@ -29,11 +29,6 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DiagnosticWithFix {
|
|
||||||
type AST;
|
|
||||||
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DiagnosticSink<'a> {
|
pub struct DiagnosticSink<'a> {
|
||||||
callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
|
callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
|
||||||
filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
|
filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
|
||||||
|
|
|
@ -6,8 +6,8 @@ mod unsafe_check;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use hir_def::DefWithBodyId;
|
use hir_def::DefWithBodyId;
|
||||||
use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticWithFix};
|
use hir_expand::diagnostics::{Diagnostic, DiagnosticSink};
|
||||||
use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
|
use hir_expand::{name::Name, HirFileId, InFile};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
|
use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
|
@ -46,15 +46,6 @@ impl Diagnostic for NoSuchField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticWithFix for NoSuchField {
|
|
||||||
type AST = ast::RecordExprField;
|
|
||||||
|
|
||||||
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
|
||||||
let root = db.parse_or_expand(self.file)?;
|
|
||||||
Some(self.field.to_node(&root))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MissingFields {
|
pub struct MissingFields {
|
||||||
pub file: HirFileId,
|
pub file: HirFileId,
|
||||||
|
@ -88,15 +79,6 @@ impl Diagnostic for MissingFields {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticWithFix for MissingFields {
|
|
||||||
type AST = ast::RecordExpr;
|
|
||||||
|
|
||||||
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
|
||||||
let root = db.parse_or_expand(self.file)?;
|
|
||||||
Some(self.field_list_parent.to_node(&root))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MissingPatFields {
|
pub struct MissingPatFields {
|
||||||
pub file: HirFileId,
|
pub file: HirFileId,
|
||||||
|
@ -163,15 +145,6 @@ impl Diagnostic for MissingOkInTailExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticWithFix for MissingOkInTailExpr {
|
|
||||||
type AST = ast::Expr;
|
|
||||||
|
|
||||||
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
|
||||||
let root = db.parse_or_expand(self.file)?;
|
|
||||||
Some(self.expr.to_node(&root))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BreakOutsideOfLoop {
|
pub struct BreakOutsideOfLoop {
|
||||||
pub file: HirFileId,
|
pub file: HirFileId,
|
||||||
|
|
|
@ -7,11 +7,12 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
|
db::AstDatabase,
|
||||||
diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
|
diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
|
||||||
HasSource, HirDisplay, Semantics, VariantDef,
|
HasSource, HirDisplay, Semantics, VariantDef,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ra_db::SourceDatabase;
|
use ra_db::{SourceDatabase, Upcast};
|
||||||
use ra_ide_db::RootDatabase;
|
use ra_ide_db::RootDatabase;
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
|
@ -23,6 +24,9 @@ use ra_text_edit::{TextEdit, TextEditBuilder};
|
||||||
|
|
||||||
use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit};
|
use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit};
|
||||||
|
|
||||||
|
mod diagnostics_with_fix;
|
||||||
|
use diagnostics_with_fix::DiagnosticWithFix;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Severity {
|
pub enum Severity {
|
||||||
Error,
|
Error,
|
||||||
|
@ -62,8 +66,7 @@ pub(crate) fn diagnostics(
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
let fix = sema
|
let fix = diagnostic_fix_source(&sema, d)
|
||||||
.diagnostic_fix_source(d)
|
|
||||||
.map(|unresolved_module| unresolved_module.syntax().text_range())
|
.map(|unresolved_module| unresolved_module.syntax().text_range())
|
||||||
.map(|fix_range| (fix, fix_range));
|
.map(|fix_range| (fix, fix_range));
|
||||||
|
|
||||||
|
@ -84,7 +87,7 @@ pub(crate) fn diagnostics(
|
||||||
let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
|
let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
sema.diagnostic_fix_source(d)
|
diagnostic_fix_source(&sema, d)
|
||||||
.and_then(|record_expr| record_expr.record_expr_field_list())
|
.and_then(|record_expr| record_expr.record_expr_field_list())
|
||||||
.map(|old_field_list| {
|
.map(|old_field_list| {
|
||||||
let mut new_field_list = old_field_list.clone();
|
let mut new_field_list = old_field_list.clone();
|
||||||
|
@ -105,6 +108,7 @@ pub(crate) fn diagnostics(
|
||||||
(
|
(
|
||||||
Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()),
|
Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()),
|
||||||
sema.original_range(&old_field_list.syntax()).range,
|
sema.original_range(&old_field_list.syntax()).range,
|
||||||
|
// old_field_list.syntax().text_range(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -118,7 +122,7 @@ pub(crate) fn diagnostics(
|
||||||
Some(())
|
Some(())
|
||||||
})
|
})
|
||||||
.on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
|
.on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
|
||||||
let fix = sema.diagnostic_fix_source(d).map(|tail_expr| {
|
let fix = diagnostic_fix_source(&sema, d).map(|tail_expr| {
|
||||||
let tail_expr_range = tail_expr.syntax().text_range();
|
let tail_expr_range = tail_expr.syntax().text_range();
|
||||||
let edit =
|
let edit =
|
||||||
TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax()));
|
TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax()));
|
||||||
|
@ -140,7 +144,7 @@ pub(crate) fn diagnostics(
|
||||||
message: d.message(),
|
message: d.message(),
|
||||||
severity: Severity::Error,
|
severity: Severity::Error,
|
||||||
fix: missing_struct_field_fix(&sema, file_id, d).and_then(|fix| {
|
fix: missing_struct_field_fix(&sema, file_id, d).and_then(|fix| {
|
||||||
Some((fix, sema.diagnostic_fix_source(d)?.syntax().text_range()))
|
Some((fix, diagnostic_fix_source(&sema, d)?.syntax().text_range()))
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
Some(())
|
Some(())
|
||||||
|
@ -164,12 +168,22 @@ pub(crate) fn diagnostics(
|
||||||
res.into_inner()
|
res.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn diagnostic_fix_source<T: DiagnosticWithFix + hir::diagnostics::Diagnostic>(
|
||||||
|
sema: &Semantics<RootDatabase>,
|
||||||
|
d: &T,
|
||||||
|
) -> Option<<T as DiagnosticWithFix>::AST> {
|
||||||
|
let file_id = d.presentation().file_id;
|
||||||
|
let root = sema.db.parse_or_expand(file_id)?;
|
||||||
|
sema.cache(root, file_id);
|
||||||
|
d.fix_source(sema.db.upcast())
|
||||||
|
}
|
||||||
|
|
||||||
fn missing_struct_field_fix(
|
fn missing_struct_field_fix(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
usage_file_id: FileId,
|
usage_file_id: FileId,
|
||||||
d: &hir::diagnostics::NoSuchField,
|
d: &hir::diagnostics::NoSuchField,
|
||||||
) -> Option<Fix> {
|
) -> Option<Fix> {
|
||||||
let record_expr_field = sema.diagnostic_fix_source(d)?;
|
let record_expr_field = diagnostic_fix_source(&sema, d)?;
|
||||||
|
|
||||||
let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
|
let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
|
||||||
let def_id = sema.resolve_variant(record_lit)?;
|
let def_id = sema.resolve_variant(record_lit)?;
|
||||||
|
|
46
crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs
Normal file
46
crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use hir::{
|
||||||
|
db::AstDatabase,
|
||||||
|
diagnostics::{MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule},
|
||||||
|
};
|
||||||
|
use ra_syntax::ast;
|
||||||
|
|
||||||
|
// TODO kb
|
||||||
|
pub trait DiagnosticWithFix {
|
||||||
|
type AST;
|
||||||
|
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticWithFix for UnresolvedModule {
|
||||||
|
type AST = ast::Module;
|
||||||
|
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
||||||
|
let root = db.parse_or_expand(self.file)?;
|
||||||
|
Some(self.decl.to_node(&root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticWithFix for NoSuchField {
|
||||||
|
type AST = ast::RecordExprField;
|
||||||
|
|
||||||
|
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
||||||
|
let root = db.parse_or_expand(self.file)?;
|
||||||
|
Some(self.field.to_node(&root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticWithFix for MissingFields {
|
||||||
|
type AST = ast::RecordExpr;
|
||||||
|
|
||||||
|
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
||||||
|
let root = db.parse_or_expand(self.file)?;
|
||||||
|
Some(self.field_list_parent.to_node(&root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticWithFix for MissingOkInTailExpr {
|
||||||
|
type AST = ast::Expr;
|
||||||
|
|
||||||
|
fn fix_source(&self, db: &dyn AstDatabase) -> Option<Self::AST> {
|
||||||
|
let root = db.parse_or_expand(self.file)?;
|
||||||
|
Some(self.expr.to_node(&root))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue