diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 12:41:19 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 12:55:45 +0100 |
commit | efa069d28818dd074afd2c7cee776907b63ca012 (patch) | |
tree | 39f3ff2d5154bb62df5e4611f7054e1f7e96eb2f /crates/hir/src | |
parent | 546be18e3a91e4844b0dacc76c9f055397b6d89e (diff) |
internal: start new diagnostics API
At the moment, this moves only a single diagnostic, but the idea is
reafactor the rest to use the same pattern. We are going to have a
single file per diagnostic. This file will define diagnostics code,
rendering range and fixes, if any. It'll also have all of the tests.
This is similar to how we deal with assists.
After we refactor all diagnostics to follow this pattern, we'll probably
move them to a new `ide_diagnostics` crate.
Not that we intentionally want to test all diagnostics on this layer,
despite the fact that they are generally emitted in the guts on the
compiler. Diagnostics care to much about the end presentation
details/fixes to be worth-while "unit" testing. So, we'll unit-test only
the primary output of compilation process (types and name res tables),
and will use integrated UI tests for diagnostics.
Diffstat (limited to 'crates/hir/src')
-rw-r--r-- | crates/hir/src/diagnostics.rs | 39 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 32 |
2 files changed, 37 insertions, 34 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 8a7c3a4fd..5e2f94698 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -15,31 +15,30 @@ pub use crate::diagnostics_sink::{ | |||
15 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, | 15 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | // Diagnostic: unresolved-module | 18 | macro_rules! diagnostics { |
19 | // | 19 | ($($diag:ident)*) => { |
20 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. | 20 | pub enum AnyDiagnostic {$( |
21 | $diag(Box<$diag>), | ||
22 | )*} | ||
23 | |||
24 | $( | ||
25 | impl From<$diag> for AnyDiagnostic { | ||
26 | fn from(d: $diag) -> AnyDiagnostic { | ||
27 | AnyDiagnostic::$diag(Box::new(d)) | ||
28 | } | ||
29 | } | ||
30 | )* | ||
31 | }; | ||
32 | } | ||
33 | |||
34 | diagnostics![UnresolvedModule]; | ||
35 | |||
21 | #[derive(Debug)] | 36 | #[derive(Debug)] |
22 | pub struct UnresolvedModule { | 37 | pub struct UnresolvedModule { |
23 | pub file: HirFileId, | 38 | pub decl: InFile<AstPtr<ast::Module>>, |
24 | pub decl: AstPtr<ast::Module>, | ||
25 | pub candidate: String, | 39 | pub candidate: String, |
26 | } | 40 | } |
27 | 41 | ||
28 | impl Diagnostic for UnresolvedModule { | ||
29 | fn code(&self) -> DiagnosticCode { | ||
30 | DiagnosticCode("unresolved-module") | ||
31 | } | ||
32 | fn message(&self) -> String { | ||
33 | "unresolved module".to_string() | ||
34 | } | ||
35 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
36 | InFile::new(self.file, self.decl.clone().into()) | ||
37 | } | ||
38 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
39 | self | ||
40 | } | ||
41 | } | ||
42 | |||
43 | // Diagnostic: unresolved-extern-crate | 42 | // Diagnostic: unresolved-extern-crate |
44 | // | 43 | // |
45 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. | 44 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index bd923cba8..ff6c68dbc 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -80,18 +80,18 @@ use tt::{Ident, Leaf, Literal, TokenTree}; | |||
80 | 80 | ||
81 | use crate::{ | 81 | use crate::{ |
82 | db::{DefDatabase, HirDatabase}, | 82 | db::{DefDatabase, HirDatabase}, |
83 | diagnostics::{ | ||
84 | BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount, | ||
85 | MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, MissingPatFields, | ||
86 | MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | ||
87 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | ||
88 | UnresolvedModule, UnresolvedProcMacro, | ||
89 | }, | ||
90 | diagnostics_sink::DiagnosticSink, | 83 | diagnostics_sink::DiagnosticSink, |
91 | }; | 84 | }; |
92 | 85 | ||
93 | pub use crate::{ | 86 | pub use crate::{ |
94 | attrs::{HasAttrs, Namespace}, | 87 | attrs::{HasAttrs, Namespace}, |
88 | diagnostics::{ | ||
89 | AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, | ||
90 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | ||
91 | MissingPatFields, MissingUnsafe, NoSuchField, RemoveThisSemicolon, | ||
92 | ReplaceFilterMapNextWithFindMap, UnimplementedBuiltinMacro, UnresolvedExternCrate, | ||
93 | UnresolvedImport, UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | ||
94 | }, | ||
95 | has_source::HasSource, | 95 | has_source::HasSource, |
96 | semantics::{PathResolution, Semantics, SemanticsScope}, | 96 | semantics::{PathResolution, Semantics, SemanticsScope}, |
97 | }; | 97 | }; |
@@ -460,10 +460,11 @@ impl Module { | |||
460 | db: &dyn HirDatabase, | 460 | db: &dyn HirDatabase, |
461 | sink: &mut DiagnosticSink, | 461 | sink: &mut DiagnosticSink, |
462 | internal_diagnostics: bool, | 462 | internal_diagnostics: bool, |
463 | ) { | 463 | ) -> Vec<AnyDiagnostic> { |
464 | let _p = profile::span("Module::diagnostics").detail(|| { | 464 | let _p = profile::span("Module::diagnostics").detail(|| { |
465 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 465 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
466 | }); | 466 | }); |
467 | let mut acc: Vec<AnyDiagnostic> = Vec::new(); | ||
467 | let def_map = self.id.def_map(db.upcast()); | 468 | let def_map = self.id.def_map(db.upcast()); |
468 | for diag in def_map.diagnostics() { | 469 | for diag in def_map.diagnostics() { |
469 | if diag.in_module != self.id.local_id { | 470 | if diag.in_module != self.id.local_id { |
@@ -473,11 +474,13 @@ impl Module { | |||
473 | match &diag.kind { | 474 | match &diag.kind { |
474 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { | 475 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { |
475 | let decl = declaration.to_node(db.upcast()); | 476 | let decl = declaration.to_node(db.upcast()); |
476 | sink.push(UnresolvedModule { | 477 | acc.push( |
477 | file: declaration.file_id, | 478 | UnresolvedModule { |
478 | decl: AstPtr::new(&decl), | 479 | decl: InFile::new(declaration.file_id, AstPtr::new(&decl)), |
479 | candidate: candidate.clone(), | 480 | candidate: candidate.clone(), |
480 | }) | 481 | } |
482 | .into(), | ||
483 | ) | ||
481 | } | 484 | } |
482 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { | 485 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { |
483 | let item = ast.to_node(db.upcast()); | 486 | let item = ast.to_node(db.upcast()); |
@@ -610,7 +613,7 @@ impl Module { | |||
610 | crate::ModuleDef::Module(m) => { | 613 | crate::ModuleDef::Module(m) => { |
611 | // Only add diagnostics from inline modules | 614 | // Only add diagnostics from inline modules |
612 | if def_map[m.id.local_id].origin.is_inline() { | 615 | if def_map[m.id.local_id].origin.is_inline() { |
613 | m.diagnostics(db, sink, internal_diagnostics) | 616 | acc.extend(m.diagnostics(db, sink, internal_diagnostics)) |
614 | } | 617 | } |
615 | } | 618 | } |
616 | _ => { | 619 | _ => { |
@@ -626,6 +629,7 @@ impl Module { | |||
626 | } | 629 | } |
627 | } | 630 | } |
628 | } | 631 | } |
632 | acc | ||
629 | } | 633 | } |
630 | 634 | ||
631 | pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { | 635 | pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { |