aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-06-13 14:42:34 +0100
committerAleksey Kladov <[email protected]>2021-06-13 14:42:34 +0100
commit6d104de15aee6a24a442871c59528c39d410c161 (patch)
treeae46a9d15e866b2887f24167152523ba3cef3a57 /crates/ide/src
parent39f190b72ccab9a166529f6ae1c8d5d562b15571 (diff)
internal: refactor unresolved import diagnostic
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/diagnostics.rs59
-rw-r--r--crates/ide/src/diagnostics/unresolved_import.rs90
-rw-r--r--crates/ide/src/diagnostics/unresolved_module.rs1
3 files changed, 121 insertions, 29 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 1fbb7131d..3d05dd093 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -6,6 +6,7 @@
6 6
7mod unresolved_module; 7mod unresolved_module;
8mod unresolved_extern_crate; 8mod unresolved_extern_crate;
9mod unresolved_import;
9mod missing_fields; 10mod missing_fields;
10 11
11mod fixes; 12mod fixes;
@@ -43,17 +44,39 @@ pub struct Diagnostic {
43 pub fixes: Option<Vec<Assist>>, 44 pub fixes: Option<Vec<Assist>>,
44 pub unused: bool, 45 pub unused: bool,
45 pub code: Option<DiagnosticCode>, 46 pub code: Option<DiagnosticCode>,
47 pub experimental: bool,
46} 48}
47 49
48impl Diagnostic { 50impl Diagnostic {
49 fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic { 51 fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
50 let message = message.into(); 52 let message = message.into();
51 let code = Some(DiagnosticCode(code)); 53 let code = Some(DiagnosticCode(code));
52 Self { message, range, severity: Severity::Error, fixes: None, unused: false, code } 54 Self {
55 message,
56 range,
57 severity: Severity::Error,
58 fixes: None,
59 unused: false,
60 code,
61 experimental: false,
62 }
63 }
64
65 fn experimental(mut self) -> Diagnostic {
66 self.experimental = true;
67 self
53 } 68 }
54 69
55 fn error(range: TextRange, message: String) -> Self { 70 fn error(range: TextRange, message: String) -> Self {
56 Self { message, range, severity: Severity::Error, fixes: None, unused: false, code: None } 71 Self {
72 message,
73 range,
74 severity: Severity::Error,
75 fixes: None,
76 unused: false,
77 code: None,
78 experimental: false,
79 }
57 } 80 }
58 81
59 fn hint(range: TextRange, message: String) -> Self { 82 fn hint(range: TextRange, message: String) -> Self {
@@ -64,6 +87,7 @@ impl Diagnostic {
64 fixes: None, 87 fixes: None,
65 unused: false, 88 unused: false,
66 code: None, 89 code: None,
90 experimental: false,
67 } 91 }
68 } 92 }
69 93
@@ -234,6 +258,7 @@ pub(crate) fn diagnostics(
234 let d = match diag { 258 let d = match diag {
235 AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d), 259 AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
236 AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), 260 AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
261 AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
237 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), 262 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
238 }; 263 };
239 if let Some(code) = d.code { 264 if let Some(code) = d.code {
@@ -241,6 +266,9 @@ pub(crate) fn diagnostics(
241 continue; 266 continue;
242 } 267 }
243 } 268 }
269 if ctx.config.disable_experimental && d.experimental {
270 continue;
271 }
244 res.push(d) 272 res.push(d)
245 } 273 }
246 274
@@ -463,33 +491,6 @@ foo::bar!(92);
463 } 491 }
464 492
465 #[test] 493 #[test]
466 fn unresolved_import_in_use_tree() {
467 // Only the relevant part of a nested `use` item should be highlighted.
468 check_diagnostics(
469 r#"
470use does_exist::{Exists, DoesntExist};
471 //^^^^^^^^^^^ unresolved import
472
473use {does_not_exist::*, does_exist};
474 //^^^^^^^^^^^^^^^^^ unresolved import
475
476use does_not_exist::{
477 a,
478 //^ unresolved import
479 b,
480 //^ unresolved import
481 c,
482 //^ unresolved import
483};
484
485mod does_exist {
486 pub struct Exists;
487}
488"#,
489 );
490 }
491
492 #[test]
493 fn range_mapping_out_of_macros() { 494 fn range_mapping_out_of_macros() {
494 // FIXME: this is very wrong, but somewhat tricky to fix. 495 // FIXME: this is very wrong, but somewhat tricky to fix.
495 check_fix( 496 check_fix(
diff --git a/crates/ide/src/diagnostics/unresolved_import.rs b/crates/ide/src/diagnostics/unresolved_import.rs
new file mode 100644
index 000000000..1cbf96ba1
--- /dev/null
+++ b/crates/ide/src/diagnostics/unresolved_import.rs
@@ -0,0 +1,90 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext};
2
3// Diagnostic: unresolved-import
4//
5// This diagnostic is triggered if rust-analyzer is unable to resolve a path in
6// a `use` declaration.
7pub(super) fn unresolved_import(
8 ctx: &DiagnosticsContext<'_>,
9 d: &hir::UnresolvedImport,
10) -> Diagnostic {
11 Diagnostic::new(
12 "unresolved-import",
13 "unresolved import",
14 ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range,
15 )
16 // This currently results in false positives in the following cases:
17 // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
18 // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
19 // - proc macros and/or proc macro generated code
20 .experimental()
21}
22
23#[cfg(test)]
24mod tests {
25 use crate::diagnostics::tests::check_diagnostics;
26
27 #[test]
28 fn unresolved_import() {
29 check_diagnostics(
30 r#"
31use does_exist;
32use does_not_exist;
33 //^^^^^^^^^^^^^^ unresolved import
34
35mod does_exist {}
36"#,
37 );
38 }
39
40 #[test]
41 fn unresolved_import_in_use_tree() {
42 // Only the relevant part of a nested `use` item should be highlighted.
43 check_diagnostics(
44 r#"
45use does_exist::{Exists, DoesntExist};
46 //^^^^^^^^^^^ unresolved import
47
48use {does_not_exist::*, does_exist};
49 //^^^^^^^^^^^^^^^^^ unresolved import
50
51use does_not_exist::{
52 a,
53 //^ unresolved import
54 b,
55 //^ unresolved import
56 c,
57 //^ unresolved import
58};
59
60mod does_exist {
61 pub struct Exists;
62}
63"#,
64 );
65 }
66
67 #[test]
68 fn dedup_unresolved_import_from_unresolved_crate() {
69 check_diagnostics(
70 r#"
71//- /main.rs crate:main
72mod a {
73 extern crate doesnotexist;
74 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
75
76 // Should not error, since we already errored for the missing crate.
77 use doesnotexist::{self, bla, *};
78
79 use crate::doesnotexist;
80 //^^^^^^^^^^^^^^^^^^^ unresolved import
81}
82
83mod m {
84 use super::doesnotexist;
85 //^^^^^^^^^^^^^^^^^^^ unresolved import
86}
87"#,
88 );
89 }
90}
diff --git a/crates/ide/src/diagnostics/unresolved_module.rs b/crates/ide/src/diagnostics/unresolved_module.rs
index 4c8c74ff7..b1da8f0e1 100644
--- a/crates/ide/src/diagnostics/unresolved_module.rs
+++ b/crates/ide/src/diagnostics/unresolved_module.rs
@@ -104,6 +104,7 @@ mod baz {}
104 "unresolved-module", 104 "unresolved-module",
105 ), 105 ),
106 ), 106 ),
107 experimental: false,
107 }, 108 },
108 ] 109 ]
109 "#]], 110 "#]],