Move the DiagnosticsWithFix trait on the ide level

This commit is contained in:
Kirill Bulatov 2020-08-11 00:37:23 +03:00
parent 9368619939
commit 29fbc8e021
7 changed files with 75 additions and 63 deletions

View File

@ -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,
}; };

View File

@ -8,7 +8,7 @@
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 @@ pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
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> {

View File

@ -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 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
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))
}
}

View File

@ -18,7 +18,7 @@
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 @@ fn is_experimental(&self) -> bool {
} }
} }
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>>,

View File

@ -6,8 +6,8 @@
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 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
} }
} }
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 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
} }
} }
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 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
} }
} }
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,

View File

@ -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 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)?;

View 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))
}
}