Skip to content

Commit 3d8df2a

Browse files
bors[bot]matklad
andauthored
Merge #9248
9248: internal: refactor unresolved macro call diagnostic r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents e6fa9b0 + fa9ed4e commit 3d8df2a

File tree

7 files changed

+220
-186
lines changed

7 files changed

+220
-186
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub use crate::diagnostics_sink::{
1717
};
1818

1919
macro_rules! diagnostics {
20-
($($diag:ident),*) => {
20+
($($diag:ident,)*) => {
2121
pub enum AnyDiagnostic {$(
2222
$diag(Box<$diag>),
2323
)*}
@@ -32,7 +32,13 @@ macro_rules! diagnostics {
3232
};
3333
}
3434

35-
diagnostics![UnresolvedModule, UnresolvedExternCrate, MissingFields];
35+
diagnostics![
36+
UnresolvedModule,
37+
UnresolvedExternCrate,
38+
UnresolvedImport,
39+
UnresolvedMacroCall,
40+
MissingFields,
41+
];
3642

3743
#[derive(Debug)]
3844
pub struct UnresolvedModule {
@@ -47,61 +53,15 @@ pub struct UnresolvedExternCrate {
4753

4854
#[derive(Debug)]
4955
pub struct UnresolvedImport {
50-
pub file: HirFileId,
51-
pub node: AstPtr<ast::UseTree>,
52-
}
53-
54-
impl Diagnostic for UnresolvedImport {
55-
fn code(&self) -> DiagnosticCode {
56-
DiagnosticCode("unresolved-import")
57-
}
58-
fn message(&self) -> String {
59-
"unresolved import".to_string()
60-
}
61-
fn display_source(&self) -> InFile<SyntaxNodePtr> {
62-
InFile::new(self.file, self.node.clone().into())
63-
}
64-
fn as_any(&self) -> &(dyn Any + Send + 'static) {
65-
self
66-
}
67-
fn is_experimental(&self) -> bool {
68-
// This currently results in false positives in the following cases:
69-
// - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
70-
// - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
71-
// - proc macros and/or proc macro generated code
72-
true
73-
}
56+
pub decl: InFile<AstPtr<ast::UseTree>>,
7457
}
7558

76-
// Diagnostic: unresolved-macro-call
77-
//
78-
// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
79-
// macro in a macro invocation.
8059
#[derive(Debug, Clone, Eq, PartialEq)]
8160
pub struct UnresolvedMacroCall {
82-
pub file: HirFileId,
83-
pub node: AstPtr<ast::MacroCall>,
61+
pub macro_call: InFile<AstPtr<ast::MacroCall>>,
8462
pub path: ModPath,
8563
}
8664

87-
impl Diagnostic for UnresolvedMacroCall {
88-
fn code(&self) -> DiagnosticCode {
89-
DiagnosticCode("unresolved-macro-call")
90-
}
91-
fn message(&self) -> String {
92-
format!("unresolved macro `{}!`", self.path)
93-
}
94-
fn display_source(&self) -> InFile<SyntaxNodePtr> {
95-
InFile::new(self.file, self.node.clone().into())
96-
}
97-
fn as_any(&self) -> &(dyn Any + Send + 'static) {
98-
self
99-
}
100-
fn is_experimental(&self) -> bool {
101-
true
102-
}
103-
}
104-
10565
// Diagnostic: inactive-code
10666
//
10767
// This diagnostic is shown for code with inactive `#[cfg]` attributes.

crates/hir/src/lib.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,10 @@ impl Module {
498498
let import = &item_tree[id.value];
499499

500500
let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
501-
sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) });
501+
acc.push(
502+
UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }
503+
.into(),
504+
);
502505
}
503506

504507
DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
@@ -577,11 +580,13 @@ impl Module {
577580

578581
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
579582
let node = ast.to_node(db.upcast());
580-
sink.push(UnresolvedMacroCall {
581-
file: ast.file_id,
582-
node: AstPtr::new(&node),
583-
path: path.clone(),
584-
});
583+
acc.push(
584+
UnresolvedMacroCall {
585+
macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
586+
path: path.clone(),
587+
}
588+
.into(),
589+
);
585590
}
586591

587592
DefDiagnosticKind::MacroError { ast, message } => {
@@ -1057,13 +1062,9 @@ impl Function {
10571062
precise_location: None,
10581063
macro_name: None,
10591064
}),
1060-
BodyDiagnostic::UnresolvedMacroCall { node, path } => {
1061-
sink.push(UnresolvedMacroCall {
1062-
file: node.file_id,
1063-
node: node.value.clone(),
1064-
path: path.clone(),
1065-
})
1066-
}
1065+
BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
1066+
UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(),
1067+
),
10671068
}
10681069
}
10691070

crates/hir_def/src/nameres/tests/diagnostics.rs

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,6 @@ fn check_no_diagnostics(ra_fixture: &str) {
1212
db.check_no_diagnostics();
1313
}
1414

15-
#[test]
16-
fn unresolved_import() {
17-
check_diagnostics(
18-
r"
19-
use does_exist;
20-
use does_not_exist;
21-
//^^^^^^^^^^^^^^^^^^^ UnresolvedImport
22-
23-
mod does_exist {}
24-
",
25-
);
26-
}
27-
28-
#[test]
29-
fn dedup_unresolved_import_from_unresolved_crate() {
30-
check_diagnostics(
31-
r"
32-
//- /main.rs crate:main
33-
mod a {
34-
extern crate doesnotexist;
35-
//^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
36-
37-
// Should not error, since we already errored for the missing crate.
38-
use doesnotexist::{self, bla, *};
39-
40-
use crate::doesnotexist;
41-
//^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport
42-
}
43-
44-
mod m {
45-
use super::doesnotexist;
46-
//^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport
47-
}
48-
",
49-
);
50-
}
51-
5215
#[test]
5316
fn inactive_item() {
5417
// Additional tests in `cfg` crate. This only tests disabled cfgs.
@@ -91,37 +54,6 @@ fn inactive_via_cfg_attr() {
9154
);
9255
}
9356

94-
#[test]
95-
fn unresolved_legacy_scope_macro() {
96-
check_diagnostics(
97-
r#"
98-
//- /lib.rs
99-
macro_rules! m { () => {} }
100-
101-
m!();
102-
m2!();
103-
//^^^^^^ UnresolvedMacroCall
104-
"#,
105-
);
106-
}
107-
108-
#[test]
109-
fn unresolved_module_scope_macro() {
110-
check_diagnostics(
111-
r#"
112-
//- /lib.rs
113-
mod mac {
114-
#[macro_export]
115-
macro_rules! m { () => {} }
116-
}
117-
118-
self::m!();
119-
self::m2!();
120-
//^^^^^^^^^^^^ UnresolvedMacroCall
121-
"#,
122-
);
123-
}
124-
12557
#[test]
12658
fn builtin_macro_fails_expansion() {
12759
check_diagnostics(

crates/ide/src/diagnostics.rs

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
77
mod unresolved_module;
88
mod unresolved_extern_crate;
9+
mod unresolved_import;
10+
mod unresolved_macro_call;
911
mod missing_fields;
1012

1113
mod fixes;
@@ -15,9 +17,8 @@ mod unlinked_file;
1517
use std::cell::RefCell;
1618

1719
use hir::{
18-
db::AstDatabase,
1920
diagnostics::{AnyDiagnostic, Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
20-
InFile, Semantics,
21+
Semantics,
2122
};
2223
use ide_assists::AssistResolveStrategy;
2324
use ide_db::{base_db::SourceDatabase, RootDatabase};
@@ -43,17 +44,39 @@ pub struct Diagnostic {
4344
pub fixes: Option<Vec<Assist>>,
4445
pub unused: bool,
4546
pub code: Option<DiagnosticCode>,
47+
pub experimental: bool,
4648
}
4749

4850
impl Diagnostic {
4951
fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
5052
let message = message.into();
5153
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
5368
}
5469

5570
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+
}
5780
}
5881

5982
fn hint(range: TextRange, message: String) -> Self {
@@ -64,6 +87,7 @@ impl Diagnostic {
6487
fixes: None,
6588
unused: false,
6689
code: None,
90+
experimental: false,
6791
}
6892
}
6993

@@ -179,20 +203,6 @@ pub(crate) fn diagnostics(
179203
res.borrow_mut()
180204
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
181205
})
182-
.on::<hir::diagnostics::UnresolvedMacroCall, _>(|d| {
183-
let last_path_segment = sema.db.parse_or_expand(d.file).and_then(|root| {
184-
d.node
185-
.to_node(&root)
186-
.path()
187-
.and_then(|it| it.segment())
188-
.and_then(|it| it.name_ref())
189-
.map(|it| InFile::new(d.file, SyntaxNodePtr::new(it.syntax())))
190-
});
191-
let diagnostics = last_path_segment.unwrap_or_else(|| d.display_source());
192-
let display_range = sema.diagnostics_display_range(diagnostics).range;
193-
res.borrow_mut()
194-
.push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code())));
195-
})
196206
.on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
197207
let display_range = sema.diagnostics_display_range(d.display_source()).range;
198208
res.borrow_mut()
@@ -234,13 +244,18 @@ pub(crate) fn diagnostics(
234244
let d = match diag {
235245
AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
236246
AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
247+
AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
248+
AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d),
237249
AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
238250
};
239251
if let Some(code) = d.code {
240252
if ctx.config.disabled.contains(code.as_str()) {
241253
continue;
242254
}
243255
}
256+
if ctx.config.disable_experimental && d.experimental {
257+
continue;
258+
}
244259
res.push(d)
245260
}
246261

@@ -452,43 +467,6 @@ mod tests {
452467
assert_eq!(expected, actual);
453468
}
454469

455-
#[test]
456-
fn test_unresolved_macro_range() {
457-
check_diagnostics(
458-
r#"
459-
foo::bar!(92);
460-
//^^^ unresolved macro `foo::bar!`
461-
"#,
462-
);
463-
}
464-
465-
#[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#"
470-
use does_exist::{Exists, DoesntExist};
471-
//^^^^^^^^^^^ unresolved import
472-
473-
use {does_not_exist::*, does_exist};
474-
//^^^^^^^^^^^^^^^^^ unresolved import
475-
476-
use does_not_exist::{
477-
a,
478-
//^ unresolved import
479-
b,
480-
//^ unresolved import
481-
c,
482-
//^ unresolved import
483-
};
484-
485-
mod does_exist {
486-
pub struct Exists;
487-
}
488-
"#,
489-
);
490-
}
491-
492470
#[test]
493471
fn range_mapping_out_of_macros() {
494472
// FIXME: this is very wrong, but somewhat tricky to fix.

0 commit comments

Comments
 (0)