This commit is contained in:
Aleksey Kladov 2019-03-23 20:41:59 +03:00
parent 3fb88e95aa
commit 79df62bc74
6 changed files with 70 additions and 51 deletions

View file

@ -16,7 +16,7 @@ use crate::{
ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
impl_block::ImplBlock, impl_block::ImplBlock,
resolve::Resolver, resolve::Resolver,
diagnostics::Diagnostics, diagnostics::DiagnosticSink,
}; };
/// hir::Crate describes a single crate. It's the main interface with which /// hir::Crate describes a single crate. It's the main interface with which
@ -166,7 +166,7 @@ impl Module {
db.crate_def_map(self.krate)[self.module_id].scope.clone() db.crate_def_map(self.krate)[self.module_id].scope.clone()
} }
pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut Diagnostics) { pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink); db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink);
} }
@ -515,7 +515,7 @@ impl Function {
r r
} }
pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut Diagnostics) { pub fn diagnostics(&self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
self.infer(db).add_diagnostics(db, *self, sink); self.infer(db).add_diagnostics(db, *self, sink);
} }
} }

View file

@ -8,19 +8,19 @@ use relative_path::RelativePathBuf;
/// Diagnostic defines hir API for errors and warnings. /// Diagnostic defines hir API for errors and warnings.
/// ///
/// It is used as a `dyn` object, which you can downcast to a concrete /// It is used as a `dyn` object, which you can downcast to a concrete
/// diagnostic. Diagnostics are structured, meaning that they include rich /// diagnostic. DiagnosticSink are structured, meaning that they include rich
/// information which can be used by IDE to create fixes. Diagnostics are /// information which can be used by IDE to create fixes. DiagnosticSink are
/// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea /// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea
/// to diagnostic in a salsa value). /// to diagnostic in a salsa value).
/// ///
/// Internally, various subsystems of hir produce diagnostics specific to a /// Internally, various subsystems of hir produce diagnostics specific to a
/// subsytem (typically, an `enum`), which are safe to store in salsa but do not /// subsystem (typically, an `enum`), which are safe to store in salsa but do not
/// include source locations. Such internal diagnostic are transformed into an /// include source locations. Such internal diagnostic are transformed into an
/// instance of `Diagnostic` on demand. /// instance of `Diagnostic` on demand.
pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
fn message(&self) -> String;
fn file(&self) -> HirFileId; fn file(&self) -> HirFileId;
fn syntax_node(&self) -> SyntaxNodePtr; fn syntax_node(&self) -> SyntaxNodePtr;
fn message(&self) -> String;
fn as_any(&self) -> &(Any + Send + 'static); fn as_any(&self) -> &(Any + Send + 'static);
} }
@ -31,17 +31,17 @@ impl dyn Diagnostic {
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Diagnostics { pub struct DiagnosticSink {
data: Vec<Box<dyn Diagnostic>>, data: Vec<Box<dyn Diagnostic>>,
} }
impl Diagnostics { impl DiagnosticSink {
pub fn push(&mut self, d: impl Diagnostic) { pub fn push(&mut self, d: impl Diagnostic) {
self.data.push(Box::new(d)) self.data.push(Box::new(d))
} }
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a dyn Diagnostic> + 'a { pub fn into_diagnostics(self) -> Vec<Box<dyn Diagnostic>> {
self.data.iter().map(|it| it.as_ref()) self.data
} }
} }
@ -52,15 +52,15 @@ pub struct NoSuchField {
} }
impl Diagnostic for NoSuchField { impl Diagnostic for NoSuchField {
fn message(&self) -> String {
"no such field".to_string()
}
fn file(&self) -> HirFileId { fn file(&self) -> HirFileId {
self.file self.file
} }
fn syntax_node(&self) -> SyntaxNodePtr { fn syntax_node(&self) -> SyntaxNodePtr {
self.field.into() self.field.into()
} }
fn message(&self) -> String {
"no such field".to_string()
}
fn as_any(&self) -> &(Any + Send + 'static) { fn as_any(&self) -> &(Any + Send + 'static) {
self self
} }
@ -74,15 +74,15 @@ pub struct UnresolvedModule {
} }
impl Diagnostic for UnresolvedModule { impl Diagnostic for UnresolvedModule {
fn message(&self) -> String {
"unresolved module".to_string()
}
fn file(&self) -> HirFileId { fn file(&self) -> HirFileId {
self.file self.file
} }
fn syntax_node(&self) -> SyntaxNodePtr { fn syntax_node(&self) -> SyntaxNodePtr {
self.decl.into() self.decl.into()
} }
fn message(&self) -> String {
"unresolved module".to_string()
}
fn as_any(&self) -> &(Any + Send + 'static) { fn as_any(&self) -> &(Any + Send + 'static) {
self self
} }

View file

@ -56,17 +56,16 @@ mod tests;
use std::sync::Arc; use std::sync::Arc;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use relative_path::RelativePathBuf;
use ra_arena::{Arena, RawId, impl_arena_id}; use ra_arena::{Arena, RawId, impl_arena_id};
use ra_db::{FileId, Edition}; use ra_db::{FileId, Edition};
use ra_syntax::{AstNode, AstPtr, ast};
use test_utils::tested_by; use test_utils::tested_by;
use crate::{ use crate::{
ModuleDef, Name, Crate, Module, ModuleDef, Name, Crate, Module,
DefDatabase, Path, PathKind, HirFileId, DefDatabase, Path, PathKind, HirFileId,
ids::{SourceItemId, SourceFileItemId, MacroCallId}, ids::{SourceItemId, SourceFileItemId, MacroCallId},
diagnostics::{Diagnostics, UnresolvedModule}, diagnostics::DiagnosticSink,
nameres::diagnostics::DefDiagnostic,
}; };
pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
@ -228,7 +227,7 @@ impl CrateDefMap {
&self, &self,
db: &impl DefDatabase, db: &impl DefDatabase,
module: CrateModuleId, module: CrateModuleId,
sink: &mut Diagnostics, sink: &mut DiagnosticSink,
) { ) {
self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
} }
@ -446,17 +445,32 @@ impl CrateDefMap {
} }
} }
#[derive(Debug, PartialEq, Eq)] mod diagnostics {
enum DefDiagnostic { use relative_path::RelativePathBuf;
use ra_syntax::{AstPtr, AstNode, ast};
use crate::{
SourceItemId, DefDatabase,
nameres::CrateModuleId,
diagnostics::{DiagnosticSink, UnresolvedModule},
};
#[derive(Debug, PartialEq, Eq)]
pub(super) enum DefDiagnostic {
UnresolvedModule { UnresolvedModule {
module: CrateModuleId, module: CrateModuleId,
declaration: SourceItemId, declaration: SourceItemId,
candidate: RelativePathBuf, candidate: RelativePathBuf,
}, },
} }
impl DefDiagnostic { impl DefDiagnostic {
fn add_to(&self, db: &impl DefDatabase, target_module: CrateModuleId, sink: &mut Diagnostics) { pub(super) fn add_to(
&self,
db: &impl DefDatabase,
target_module: CrateModuleId,
sink: &mut DiagnosticSink,
) {
match self { match self {
DefDiagnostic::UnresolvedModule { module, declaration, candidate } => { DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
if *module != target_module { if *module != target_module {
@ -472,4 +486,6 @@ impl DefDiagnostic {
} }
} }
} }
}
} }

View file

@ -8,12 +8,15 @@ use crate::{
Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
DefDatabase, HirFileId, Name, Path, Crate, DefDatabase, HirFileId, Name, Path, Crate,
KnownName, KnownName,
nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw, DefDiagnostic}, nameres::{
Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
CrateDefMap, CrateModuleId, ModuleData, CrateMacroId,
diagnostics::DefDiagnostic,
raw,
},
ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
}; };
use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
// populate external prelude // populate external prelude
for dep in def_map.krate.dependencies(db) { for dep in def_map.krate.dependencies(db) {

View file

@ -38,7 +38,7 @@ use crate::{
resolve::{Resolver, Resolution}, resolve::{Resolver, Resolution},
nameres::Namespace, nameres::Namespace,
ty::infer::diagnostics::InferenceDiagnostic, ty::infer::diagnostics::InferenceDiagnostic,
diagnostics::Diagnostics, diagnostics::DiagnosticSink,
}; };
use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor};
@ -120,7 +120,7 @@ impl InferenceResult {
&self, &self,
db: &impl HirDatabase, db: &impl HirDatabase,
owner: Function, owner: Function,
sink: &mut Diagnostics, sink: &mut DiagnosticSink,
) { ) {
self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
} }
@ -1269,7 +1269,7 @@ impl Expectation {
} }
mod diagnostics { mod diagnostics {
use crate::{expr::ExprId, diagnostics::{Diagnostics, NoSuchField}, HirDatabase, Function}; use crate::{expr::ExprId, diagnostics::{DiagnosticSink, NoSuchField}, HirDatabase, Function};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub(super) enum InferenceDiagnostic { pub(super) enum InferenceDiagnostic {
@ -1281,7 +1281,7 @@ mod diagnostics {
&self, &self,
db: &impl HirDatabase, db: &impl HirDatabase,
owner: Function, owner: Function,
sink: &mut Diagnostics, sink: &mut DiagnosticSink,
) { ) {
match self { match self {
InferenceDiagnostic::NoSuchField { expr, field } => { InferenceDiagnostic::NoSuchField { expr, field } => {

View file

@ -129,7 +129,7 @@ fn check_struct_shorthand_initialization(
} }
fn check_module(acc: &mut Vec<Diagnostic>, db: &RootDatabase, module: hir::Module) { fn check_module(acc: &mut Vec<Diagnostic>, db: &RootDatabase, module: hir::Module) {
let mut diagnostics = hir::diagnostics::Diagnostics::default(); let mut diagnostics = hir::diagnostics::DiagnosticSink::default();
module.diagnostics(db, &mut diagnostics); module.diagnostics(db, &mut diagnostics);
for decl in module.declarations(db) { for decl in module.declarations(db) {
match decl { match decl {
@ -138,7 +138,7 @@ fn check_module(acc: &mut Vec<Diagnostic>, db: &RootDatabase, module: hir::Modul
} }
} }
for d in diagnostics.iter() { for d in diagnostics.into_diagnostics().iter() {
if let Some(d) = d.downcast_ref::<hir::diagnostics::UnresolvedModule>() { if let Some(d) = d.downcast_ref::<hir::diagnostics::UnresolvedModule>() {
let source_root = db.file_source_root(d.file().original_file(db)); let source_root = db.file_source_root(d.file().original_file(db));
let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() }; let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() };