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},
impl_block::ImplBlock,
resolve::Resolver,
diagnostics::Diagnostics,
diagnostics::DiagnosticSink,
};
/// 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()
}
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);
}
@ -515,7 +515,7 @@ impl Function {
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);
}
}

View File

@ -8,19 +8,19 @@ use relative_path::RelativePathBuf;
/// Diagnostic defines hir API for errors and warnings.
///
/// It is used as a `dyn` object, which you can downcast to a concrete
/// diagnostic. Diagnostics are structured, meaning that they include rich
/// information which can be used by IDE to create fixes. Diagnostics are
/// diagnostic. DiagnosticSink are structured, meaning that they include rich
/// 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
/// to diagnostic in a salsa value).
///
/// 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
/// instance of `Diagnostic` on demand.
pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
fn message(&self) -> String;
fn file(&self) -> HirFileId;
fn syntax_node(&self) -> SyntaxNodePtr;
fn message(&self) -> String;
fn as_any(&self) -> &(Any + Send + 'static);
}
@ -31,17 +31,17 @@ impl dyn Diagnostic {
}
#[derive(Debug, Default)]
pub struct Diagnostics {
pub struct DiagnosticSink {
data: Vec<Box<dyn Diagnostic>>,
}
impl Diagnostics {
impl DiagnosticSink {
pub fn push(&mut self, d: impl Diagnostic) {
self.data.push(Box::new(d))
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a dyn Diagnostic> + 'a {
self.data.iter().map(|it| it.as_ref())
pub fn into_diagnostics(self) -> Vec<Box<dyn Diagnostic>> {
self.data
}
}
@ -52,15 +52,15 @@ pub struct NoSuchField {
}
impl Diagnostic for NoSuchField {
fn message(&self) -> String {
"no such field".to_string()
}
fn file(&self) -> HirFileId {
self.file
}
fn syntax_node(&self) -> SyntaxNodePtr {
self.field.into()
}
fn message(&self) -> String {
"no such field".to_string()
}
fn as_any(&self) -> &(Any + Send + 'static) {
self
}
@ -74,15 +74,15 @@ pub struct UnresolvedModule {
}
impl Diagnostic for UnresolvedModule {
fn message(&self) -> String {
"unresolved module".to_string()
}
fn file(&self) -> HirFileId {
self.file
}
fn syntax_node(&self) -> SyntaxNodePtr {
self.decl.into()
}
fn message(&self) -> String {
"unresolved module".to_string()
}
fn as_any(&self) -> &(Any + Send + 'static) {
self
}

View File

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

View File

@ -8,12 +8,15 @@ use crate::{
Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
DefDatabase, HirFileId, Name, Path, Crate,
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},
};
use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
// populate external prelude
for dep in def_map.krate.dependencies(db) {

View File

@ -38,7 +38,7 @@ use crate::{
resolve::{Resolver, Resolution},
nameres::Namespace,
ty::infer::diagnostics::InferenceDiagnostic,
diagnostics::Diagnostics,
diagnostics::DiagnosticSink,
};
use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor};
@ -120,7 +120,7 @@ impl InferenceResult {
&self,
db: &impl HirDatabase,
owner: Function,
sink: &mut Diagnostics,
sink: &mut DiagnosticSink,
) {
self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
}
@ -1269,7 +1269,7 @@ impl Expectation {
}
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)]
pub(super) enum InferenceDiagnostic {
@ -1281,7 +1281,7 @@ mod diagnostics {
&self,
db: &impl HirDatabase,
owner: Function,
sink: &mut Diagnostics,
sink: &mut DiagnosticSink,
) {
match self {
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) {
let mut diagnostics = hir::diagnostics::Diagnostics::default();
let mut diagnostics = hir::diagnostics::DiagnosticSink::default();
module.diagnostics(db, &mut diagnostics);
for decl in module.declarations(db) {
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>() {
let source_root = db.file_source_root(d.file().original_file(db));
let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() };