diff options
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model/src.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/diagnostics.rs | 85 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 21 |
11 files changed, 130 insertions, 109 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index c97ea18a2..5b78bdfef 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -11,14 +11,16 @@ use hir_def::{ | |||
11 | type_ref::{Mutability, TypeRef}, | 11 | type_ref::{Mutability, TypeRef}, |
12 | CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, | 12 | CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, |
13 | }; | 13 | }; |
14 | use hir_expand::name::{self, AsName}; | 14 | use hir_expand::{ |
15 | diagnostics::DiagnosticSink, | ||
16 | name::{self, AsName}, | ||
17 | }; | ||
15 | use ra_db::{CrateId, Edition}; | 18 | use ra_db::{CrateId, Edition}; |
16 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 19 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; |
17 | 20 | ||
18 | use crate::{ | 21 | use crate::{ |
19 | adt::VariantDef, | 22 | adt::VariantDef, |
20 | db::{AstDatabase, DefDatabase, HirDatabase}, | 23 | db::{AstDatabase, DefDatabase, HirDatabase}, |
21 | diagnostics::DiagnosticSink, | ||
22 | expr::{validation::ExprValidator, Body, BodySourceMap}, | 24 | expr::{validation::ExprValidator, Body, BodySourceMap}, |
23 | generics::HasGenericParams, | 25 | generics::HasGenericParams, |
24 | ids::{ | 26 | ids::{ |
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index 0f4c78df7..bd0c3c226 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs | |||
@@ -10,7 +10,7 @@ use crate::{ | |||
10 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, | 10 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | pub use hir_def::Source; | 13 | pub use hir_expand::Source; |
14 | 14 | ||
15 | pub trait HasSource { | 15 | pub trait HasSource { |
16 | type Ast; | 16 | type Ast; |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 9acdaf8ed..a33af8f46 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -1,82 +1,13 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{any::Any, fmt}; | 3 | use std::any::Any; |
4 | 4 | ||
5 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; | 5 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
6 | use relative_path::RelativePathBuf; | 6 | use relative_path::RelativePathBuf; |
7 | 7 | ||
8 | use crate::{db::HirDatabase, HirFileId, Name, Source}; | 8 | use crate::{db::AstDatabase, HirFileId, Name, Source}; |
9 | |||
10 | /// Diagnostic defines hir API for errors and warnings. | ||
11 | /// | ||
12 | /// It is used as a `dyn` object, which you can downcast to a concrete | ||
13 | /// diagnostic. DiagnosticSink are structured, meaning that they include rich | ||
14 | /// information which can be used by IDE to create fixes. DiagnosticSink are | ||
15 | /// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea | ||
16 | /// to diagnostic in a salsa value). | ||
17 | /// | ||
18 | /// Internally, various subsystems of hir produce diagnostics specific to a | ||
19 | /// subsystem (typically, an `enum`), which are safe to store in salsa but do not | ||
20 | /// include source locations. Such internal diagnostic are transformed into an | ||
21 | /// instance of `Diagnostic` on demand. | ||
22 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | ||
23 | fn message(&self) -> String; | ||
24 | fn source(&self) -> Source<SyntaxNodePtr>; | ||
25 | fn highlight_range(&self) -> TextRange { | ||
26 | self.source().ast.range() | ||
27 | } | ||
28 | fn as_any(&self) -> &(dyn Any + Send + 'static); | ||
29 | } | ||
30 | |||
31 | pub trait AstDiagnostic { | ||
32 | type AST; | ||
33 | fn ast(&self, db: &impl HirDatabase) -> Self::AST; | ||
34 | } | ||
35 | |||
36 | impl dyn Diagnostic { | ||
37 | pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode { | ||
38 | let node = db.parse_or_expand(self.source().file_id).unwrap(); | ||
39 | self.source().ast.to_node(&node) | ||
40 | } | ||
41 | |||
42 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | ||
43 | self.as_any().downcast_ref() | ||
44 | } | ||
45 | } | ||
46 | 9 | ||
47 | pub struct DiagnosticSink<'a> { | 10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; |
48 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, | ||
49 | default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>, | ||
50 | } | ||
51 | |||
52 | impl<'a> DiagnosticSink<'a> { | ||
53 | pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { | ||
54 | DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } | ||
55 | } | ||
56 | |||
57 | pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> { | ||
58 | let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { | ||
59 | Some(d) => { | ||
60 | cb(d); | ||
61 | Ok(()) | ||
62 | } | ||
63 | None => Err(()), | ||
64 | }; | ||
65 | self.callbacks.push(Box::new(cb)); | ||
66 | self | ||
67 | } | ||
68 | |||
69 | pub(crate) fn push(&mut self, d: impl Diagnostic) { | ||
70 | let d: &dyn Diagnostic = &d; | ||
71 | for cb in self.callbacks.iter_mut() { | ||
72 | match cb(d) { | ||
73 | Ok(()) => return, | ||
74 | Err(()) => (), | ||
75 | } | ||
76 | } | ||
77 | (self.default_callback)(d) | ||
78 | } | ||
79 | } | ||
80 | 11 | ||
81 | #[derive(Debug)] | 12 | #[derive(Debug)] |
82 | pub struct NoSuchField { | 13 | pub struct NoSuchField { |
@@ -139,7 +70,7 @@ impl Diagnostic for MissingFields { | |||
139 | impl AstDiagnostic for MissingFields { | 70 | impl AstDiagnostic for MissingFields { |
140 | type AST = ast::RecordFieldList; | 71 | type AST = ast::RecordFieldList; |
141 | 72 | ||
142 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 73 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { |
143 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | 74 | let root = db.parse_or_expand(self.source().file_id).unwrap(); |
144 | let node = self.source().ast.to_node(&root); | 75 | let node = self.source().ast.to_node(&root); |
145 | ast::RecordFieldList::cast(node).unwrap() | 76 | ast::RecordFieldList::cast(node).unwrap() |
@@ -167,7 +98,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
167 | impl AstDiagnostic for MissingOkInTailExpr { | 98 | impl AstDiagnostic for MissingOkInTailExpr { |
168 | type AST = ast::Expr; | 99 | type AST = ast::Expr; |
169 | 100 | ||
170 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 101 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { |
171 | let root = db.parse_or_expand(self.file).unwrap(); | 102 | let root = db.parse_or_expand(self.file).unwrap(); |
172 | let node = self.source().ast.to_node(&root); | 103 | let node = self.source().ast.to_node(&root); |
173 | ast::Expr::cast(node).unwrap() | 104 | ast::Expr::cast(node).unwrap() |
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index c685edda1..3054f1dce 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -3,12 +3,13 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::path::known; | 5 | use hir_def::path::known; |
6 | use hir_expand::diagnostics::DiagnosticSink; | ||
6 | use ra_syntax::ast; | 7 | use ra_syntax::ast; |
7 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | db::HirDatabase, | 11 | db::HirDatabase, |
11 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, | 12 | diagnostics::{MissingFields, MissingOkInTailExpr}, |
12 | expr::AstPtr, | 13 | expr::AstPtr, |
13 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | 14 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, |
14 | Adt, Function, Name, Path, | 15 | Adt, Function, Name, Path, |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 40f5562b4..0ba17e571 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -62,7 +62,7 @@ pub use crate::{ | |||
62 | adt::VariantDef, | 62 | adt::VariantDef, |
63 | code_model::{ | 63 | code_model::{ |
64 | docs::{DocDef, Docs, Documentation}, | 64 | docs::{DocDef, Docs, Documentation}, |
65 | src::{HasBodySource, HasSource, Source}, | 65 | src::{HasBodySource, HasSource}, |
66 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, | 66 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, |
67 | EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, | 67 | EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, |
68 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, | 68 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, |
@@ -85,4 +85,4 @@ pub use hir_def::{ | |||
85 | path::{Path, PathKind}, | 85 | path::{Path, PathKind}, |
86 | type_ref::Mutability, | 86 | type_ref::Mutability, |
87 | }; | 87 | }; |
88 | pub use hir_expand::{either::Either, name::Name}; | 88 | pub use hir_expand::{either::Either, name::Name, Source}; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 35dfaf3ba..4c89c8d38 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::{panic, sync::Arc}; | 3 | use std::{panic, sync::Arc}; |
4 | 4 | ||
5 | use hir_expand::diagnostics::DiagnosticSink; | ||
5 | use parking_lot::Mutex; | 6 | use parking_lot::Mutex; |
6 | use ra_cfg::CfgOptions; | 7 | use ra_cfg::CfgOptions; |
7 | use ra_db::{ | 8 | use ra_db::{ |
@@ -12,7 +13,7 @@ use relative_path::{RelativePath, RelativePathBuf}; | |||
12 | use rustc_hash::FxHashMap; | 13 | use rustc_hash::FxHashMap; |
13 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | 14 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; |
14 | 15 | ||
15 | use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink}; | 16 | use crate::{db, debug::HirDebugHelper}; |
16 | 17 | ||
17 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 18 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
18 | 19 | ||
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 7ba031827..32a6ab474 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -55,6 +55,7 @@ mod tests; | |||
55 | use std::sync::Arc; | 55 | use std::sync::Arc; |
56 | 56 | ||
57 | use hir_def::{builtin_type::BuiltinType, CrateModuleId}; | 57 | use hir_def::{builtin_type::BuiltinType, CrateModuleId}; |
58 | use hir_expand::diagnostics::DiagnosticSink; | ||
58 | use once_cell::sync::Lazy; | 59 | use once_cell::sync::Lazy; |
59 | use ra_arena::Arena; | 60 | use ra_arena::Arena; |
60 | use ra_db::{Edition, FileId}; | 61 | use ra_db::{Edition, FileId}; |
@@ -65,7 +66,6 @@ use test_utils::tested_by; | |||
65 | 66 | ||
66 | use crate::{ | 67 | use crate::{ |
67 | db::{AstDatabase, DefDatabase}, | 68 | db::{AstDatabase, DefDatabase}, |
68 | diagnostics::DiagnosticSink, | ||
69 | ids::MacroDefId, | 69 | ids::MacroDefId, |
70 | nameres::diagnostics::DefDiagnostic, | 70 | nameres::diagnostics::DefDiagnostic, |
71 | Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, | 71 | Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, |
@@ -513,12 +513,13 @@ impl CrateDefMap { | |||
513 | } | 513 | } |
514 | 514 | ||
515 | mod diagnostics { | 515 | mod diagnostics { |
516 | use hir_expand::diagnostics::DiagnosticSink; | ||
516 | use ra_syntax::{ast, AstPtr}; | 517 | use ra_syntax::{ast, AstPtr}; |
517 | use relative_path::RelativePathBuf; | 518 | use relative_path::RelativePathBuf; |
518 | 519 | ||
519 | use crate::{ | 520 | use crate::{ |
520 | db::{AstDatabase, DefDatabase}, | 521 | db::{AstDatabase, DefDatabase}, |
521 | diagnostics::{DiagnosticSink, UnresolvedModule}, | 522 | diagnostics::UnresolvedModule, |
522 | nameres::CrateModuleId, | 523 | nameres::CrateModuleId, |
523 | AstId, | 524 | AstId, |
524 | }; | 525 | }; |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 6694467a3..2370e8d4f 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -25,7 +25,7 @@ use hir_def::{ | |||
25 | path::known, | 25 | path::known, |
26 | type_ref::{Mutability, TypeRef}, | 26 | type_ref::{Mutability, TypeRef}, |
27 | }; | 27 | }; |
28 | use hir_expand::name; | 28 | use hir_expand::{diagnostics::DiagnosticSink, name}; |
29 | use ra_arena::map::ArenaMap; | 29 | use ra_arena::map::ArenaMap; |
30 | use ra_prof::profile; | 30 | use ra_prof::profile; |
31 | use test_utils::tested_by; | 31 | use test_utils::tested_by; |
@@ -40,7 +40,6 @@ use crate::{ | |||
40 | adt::VariantDef, | 40 | adt::VariantDef, |
41 | code_model::TypeAlias, | 41 | code_model::TypeAlias, |
42 | db::HirDatabase, | 42 | db::HirDatabase, |
43 | diagnostics::DiagnosticSink, | ||
44 | expr::{BindingAnnotation, Body, ExprId, PatId}, | 43 | expr::{BindingAnnotation, Body, ExprId, PatId}, |
45 | resolve::{Resolver, TypeNs}, | 44 | resolve::{Resolver, TypeNs}, |
46 | ty::infer::diagnostics::InferenceDiagnostic, | 45 | ty::infer::diagnostics::InferenceDiagnostic, |
@@ -719,12 +718,9 @@ impl Expectation { | |||
719 | } | 718 | } |
720 | 719 | ||
721 | mod diagnostics { | 720 | mod diagnostics { |
722 | use crate::{ | 721 | use hir_expand::diagnostics::DiagnosticSink; |
723 | db::HirDatabase, | 722 | |
724 | diagnostics::{DiagnosticSink, NoSuchField}, | 723 | use crate::{db::HirDatabase, diagnostics::NoSuchField, expr::ExprId, Function, HasSource}; |
725 | expr::ExprId, | ||
726 | Function, HasSource, | ||
727 | }; | ||
728 | 724 | ||
729 | #[derive(Debug, PartialEq, Eq, Clone)] | 725 | #[derive(Debug, PartialEq, Eq, Clone)] |
730 | pub(super) enum InferenceDiagnostic { | 726 | pub(super) enum InferenceDiagnostic { |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 76d5f1852..6d66f481d 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -19,19 +19,13 @@ pub mod nameres; | |||
19 | 19 | ||
20 | use std::hash::{Hash, Hasher}; | 20 | use std::hash::{Hash, Hasher}; |
21 | 21 | ||
22 | use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; | 22 | use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, Source}; |
23 | use ra_arena::{impl_arena_id, RawId}; | 23 | use ra_arena::{impl_arena_id, RawId}; |
24 | use ra_db::{salsa, CrateId, FileId}; | 24 | use ra_db::{salsa, CrateId, FileId}; |
25 | use ra_syntax::{ast, AstNode, SyntaxNode}; | 25 | use ra_syntax::{ast, AstNode, SyntaxNode}; |
26 | 26 | ||
27 | use crate::{builtin_type::BuiltinType, db::InternDatabase}; | 27 | use crate::{builtin_type::BuiltinType, db::InternDatabase}; |
28 | 28 | ||
29 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
30 | pub struct Source<T> { | ||
31 | pub file_id: HirFileId, | ||
32 | pub ast: T, | ||
33 | } | ||
34 | |||
35 | pub enum ModuleSource { | 29 | pub enum ModuleSource { |
36 | SourceFile(ast::SourceFile), | 30 | SourceFile(ast::SourceFile), |
37 | Module(ast::Module), | 31 | Module(ast::Module), |
@@ -94,15 +88,6 @@ impl ModuleSource { | |||
94 | } | 88 | } |
95 | } | 89 | } |
96 | 90 | ||
97 | impl<T> Source<T> { | ||
98 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
99 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
100 | } | ||
101 | pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { | ||
102 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 91 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
107 | pub struct ModuleId { | 92 | pub struct ModuleId { |
108 | pub krate: CrateId, | 93 | pub krate: CrateId, |
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs new file mode 100644 index 000000000..201884b95 --- /dev/null +++ b/crates/ra_hir_expand/src/diagnostics.rs | |||
@@ -0,0 +1,85 @@ | |||
1 | //! Semantic errors and warnings. | ||
2 | //! | ||
3 | //! The `Diagnostic` trait defines a trait object which can represent any | ||
4 | //! diagnostic. | ||
5 | //! | ||
6 | //! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating | ||
7 | //! a `DiagnosticSink`, you supply a callback which can react to a `dyn | ||
8 | //! Diagnostic` or to any concrete diagnostic (downcasting is sued internally). | ||
9 | //! | ||
10 | //! Because diagnostics store file offsets, it's a bad idea to store them | ||
11 | //! directly in salsa. For this reason, every hir subsytem defines it's own | ||
12 | //! strongly-typed closed set of diagnostics which use hir ids internally, are | ||
13 | //! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a | ||
14 | //! subsystem provides a separate, non-query-based API which can walk all stored | ||
15 | //! values and transform them into instances of `Diagnostic`. | ||
16 | |||
17 | use std::{any::Any, fmt}; | ||
18 | |||
19 | use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; | ||
20 | |||
21 | use crate::{db::AstDatabase, Source}; | ||
22 | |||
23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | ||
24 | fn message(&self) -> String; | ||
25 | fn source(&self) -> Source<SyntaxNodePtr>; | ||
26 | fn highlight_range(&self) -> TextRange { | ||
27 | self.source().ast.range() | ||
28 | } | ||
29 | fn as_any(&self) -> &(dyn Any + Send + 'static); | ||
30 | } | ||
31 | |||
32 | pub trait AstDiagnostic { | ||
33 | type AST; | ||
34 | fn ast(&self, db: &impl AstDatabase) -> Self::AST; | ||
35 | } | ||
36 | |||
37 | impl dyn Diagnostic { | ||
38 | pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode { | ||
39 | let node = db.parse_or_expand(self.source().file_id).unwrap(); | ||
40 | self.source().ast.to_node(&node) | ||
41 | } | ||
42 | |||
43 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | ||
44 | self.as_any().downcast_ref() | ||
45 | } | ||
46 | } | ||
47 | |||
48 | pub struct DiagnosticSink<'a> { | ||
49 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, | ||
50 | default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>, | ||
51 | } | ||
52 | |||
53 | impl<'a> DiagnosticSink<'a> { | ||
54 | /// FIXME: split `new` and `on` into a separate builder type | ||
55 | pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { | ||
56 | DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } | ||
57 | } | ||
58 | |||
59 | pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> { | ||
60 | let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { | ||
61 | Some(d) => { | ||
62 | cb(d); | ||
63 | Ok(()) | ||
64 | } | ||
65 | None => Err(()), | ||
66 | }; | ||
67 | self.callbacks.push(Box::new(cb)); | ||
68 | self | ||
69 | } | ||
70 | |||
71 | pub fn push(&mut self, d: impl Diagnostic) { | ||
72 | let d: &dyn Diagnostic = &d; | ||
73 | self._push(d); | ||
74 | } | ||
75 | |||
76 | fn _push(&mut self, d: &dyn Diagnostic) { | ||
77 | for cb in self.callbacks.iter_mut() { | ||
78 | match cb(d) { | ||
79 | Ok(()) => return, | ||
80 | Err(()) => (), | ||
81 | } | ||
82 | } | ||
83 | (self.default_callback)(d) | ||
84 | } | ||
85 | } | ||
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 5a0e5a19c..dd07a16b4 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -9,11 +9,15 @@ pub mod ast_id_map; | |||
9 | pub mod either; | 9 | pub mod either; |
10 | pub mod name; | 10 | pub mod name; |
11 | pub mod hygiene; | 11 | pub mod hygiene; |
12 | pub mod diagnostics; | ||
12 | 13 | ||
13 | use std::hash::{Hash, Hasher}; | 14 | use std::hash::{Hash, Hasher}; |
14 | 15 | ||
15 | use ra_db::{salsa, CrateId, FileId}; | 16 | use ra_db::{salsa, CrateId, FileId}; |
16 | use ra_syntax::ast::{self, AstNode}; | 17 | use ra_syntax::{ |
18 | ast::{self, AstNode}, | ||
19 | SyntaxNode, | ||
20 | }; | ||
17 | 21 | ||
18 | use crate::ast_id_map::FileAstId; | 22 | use crate::ast_id_map::FileAstId; |
19 | 23 | ||
@@ -151,3 +155,18 @@ impl<N: AstNode> AstId<N> { | |||
151 | db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) | 155 | db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) |
152 | } | 156 | } |
153 | } | 157 | } |
158 | |||
159 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
160 | pub struct Source<T> { | ||
161 | pub file_id: HirFileId, | ||
162 | pub ast: T, | ||
163 | } | ||
164 | |||
165 | impl<T> Source<T> { | ||
166 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
167 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
168 | } | ||
169 | pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { | ||
170 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | ||
171 | } | ||
172 | } | ||