diff options
author | Seivan Heidari <[email protected]> | 2019-11-04 12:45:27 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-04 12:45:27 +0000 |
commit | dad9bc6caad71e6aebb92ad9883c08d30431e9b1 (patch) | |
tree | 6495d47108bc56ab0fbb358125fe65ebece8934f /crates/ra_hir/src/diagnostics.rs | |
parent | 1d8bb4c6c1fef1f8ea513e07d0a7d4c5483129d2 (diff) | |
parent | cc2d75d0f88bdcb1b3e20db36decb6ee6eca517a (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_hir/src/diagnostics.rs')
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 102 |
1 files changed, 7 insertions, 95 deletions
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 9acdaf8ed..1751e7be3 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 | |||
5 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; | ||
6 | use relative_path::RelativePathBuf; | ||
7 | |||
8 | use crate::{db::HirDatabase, 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 | 4 | ||
36 | impl dyn Diagnostic { | 5 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
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 | 6 | ||
42 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | 7 | use crate::{db::AstDatabase, HirFileId, Name, Source}; |
43 | self.as_any().downcast_ref() | ||
44 | } | ||
45 | } | ||
46 | 8 | ||
47 | pub struct DiagnosticSink<'a> { | 9 | pub use hir_def::diagnostics::UnresolvedModule; |
48 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, | 10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; |
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 { |
@@ -99,25 +30,6 @@ impl Diagnostic for NoSuchField { | |||
99 | } | 30 | } |
100 | 31 | ||
101 | #[derive(Debug)] | 32 | #[derive(Debug)] |
102 | pub struct UnresolvedModule { | ||
103 | pub file: HirFileId, | ||
104 | pub decl: AstPtr<ast::Module>, | ||
105 | pub candidate: RelativePathBuf, | ||
106 | } | ||
107 | |||
108 | impl Diagnostic for UnresolvedModule { | ||
109 | fn message(&self) -> String { | ||
110 | "unresolved module".to_string() | ||
111 | } | ||
112 | fn source(&self) -> Source<SyntaxNodePtr> { | ||
113 | Source { file_id: self.file, ast: self.decl.into() } | ||
114 | } | ||
115 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
116 | self | ||
117 | } | ||
118 | } | ||
119 | |||
120 | #[derive(Debug)] | ||
121 | pub struct MissingFields { | 33 | pub struct MissingFields { |
122 | pub file: HirFileId, | 34 | pub file: HirFileId, |
123 | pub field_list: AstPtr<ast::RecordFieldList>, | 35 | pub field_list: AstPtr<ast::RecordFieldList>, |
@@ -139,7 +51,7 @@ impl Diagnostic for MissingFields { | |||
139 | impl AstDiagnostic for MissingFields { | 51 | impl AstDiagnostic for MissingFields { |
140 | type AST = ast::RecordFieldList; | 52 | type AST = ast::RecordFieldList; |
141 | 53 | ||
142 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 54 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { |
143 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | 55 | let root = db.parse_or_expand(self.source().file_id).unwrap(); |
144 | let node = self.source().ast.to_node(&root); | 56 | let node = self.source().ast.to_node(&root); |
145 | ast::RecordFieldList::cast(node).unwrap() | 57 | ast::RecordFieldList::cast(node).unwrap() |
@@ -167,7 +79,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
167 | impl AstDiagnostic for MissingOkInTailExpr { | 79 | impl AstDiagnostic for MissingOkInTailExpr { |
168 | type AST = ast::Expr; | 80 | type AST = ast::Expr; |
169 | 81 | ||
170 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 82 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { |
171 | let root = db.parse_or_expand(self.file).unwrap(); | 83 | let root = db.parse_or_expand(self.file).unwrap(); |
172 | let node = self.source().ast.to_node(&root); | 84 | let node = self.source().ast.to_node(&root); |
173 | ast::Expr::cast(node).unwrap() | 85 | ast::Expr::cast(node).unwrap() |