7970: Fix incorrect diagnostics for failing built in macros r=jonas-schievink a=brandondong

**Reproduction:**
1. Use a built in macro in such a way that rust-analyzer fails to expand it. For example:

**lib.rs**
```
include!("<valid file but without a .rs extension so it is not indexed by rust-analyzer>");
```
2. rust-analyzer highlights the macro call and says the macro itself cannot be resolved even though include! is in the standard library (unresolved-macro-call diagnostic).
3. No macro-error diagnostic is raised.

**Root cause for incorrect unresolved-macro-call diagnostic:**
1. collector:collect_macro_call is able to resolve include! in legacy scope but the expansion fails. Therefore, it's pushed into unexpanded_macros to be retried with module scope.
2. include! fails at the resolution step in collector:resolve_macros now that it's using module scope. Therefore, it's retained in unexpanded_macros.
3. Finally, collector:finish tries resolving the remaining unexpanded macros but only with module scope. include! again fails at the resolution step so a diagnostic is created.

**Root cause for missing macro-error diagnostic:**
1. In collector:resolve_macros, directive.legacy is None since eager expansion failed in collector:collect_macro_call. The macro_call_as_call_id fails to resolve since we're retrying in module scope. Therefore, collect_macro_expansion is not called for the macro and no macro-error diagnostic is generated.

**Fix:**
- In collector:collect_macro_call, do not add failing built-in macros to the unexpanded_macros list and immediately raise the macro-error diagnostic. This is in contrast to lazy macros which are resolved in collector::resolve_macros and later expanded in collect_macro_expansion where a macro-error diagnostic may be raised.

Co-authored-by: Brandon <brandondong604@hotmail.com>
Co-authored-by: brandondong <brandondong604@hotmail.com>
This commit is contained in:
bors[bot] 2021-03-15 18:24:22 +00:00 committed by GitHub
commit 47b74cadf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 11 deletions

View File

@ -97,7 +97,7 @@ impl Diagnostic for UnresolvedImport {
// Diagnostic: unresolved-macro-call
//
// This diagnostic is triggered if rust-analyzer is unable to resolove path to a
// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
// macro in a macro invocation.
#[derive(Debug)]
pub struct UnresolvedMacroCall {

View File

@ -13,7 +13,7 @@ use hir_expand::{
builtin_macro::find_builtin_macro,
name::{AsName, Name},
proc_macro::ProcMacroExpander,
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
};
use hir_expand::{InFile, MacroCallLoc};
use rustc_hash::{FxHashMap, FxHashSet};
@ -1455,7 +1455,8 @@ impl ModCollector<'_, '_> {
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
// Case 1: try to resolve in legacy scope and expand macro_rules
if let Ok(Ok(macro_call_id)) = macro_call_as_call_id(
let mut error = None;
match macro_call_as_call_id(
&ast_id,
self.def_collector.db,
self.def_collector.def_map.krate,
@ -1468,16 +1469,28 @@ impl ModCollector<'_, '_> {
)
})
},
&mut |_err| (),
&mut |err| error = Some(err),
) {
self.def_collector.unexpanded_macros.push(MacroDirective {
module_id: self.module_id,
ast_id,
legacy: Some(macro_call_id),
depth: self.macro_depth + 1,
});
Ok(Ok(macro_call_id)) => {
self.def_collector.unexpanded_macros.push(MacroDirective {
module_id: self.module_id,
ast_id,
legacy: Some(macro_call_id),
depth: self.macro_depth + 1,
});
return;
return;
}
Ok(Err(_)) => {
// Built-in macro failed eager expansion.
self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
self.module_id,
MacroCallKind::FnLike(ast_id.ast_id),
error.unwrap().to_string(),
));
return;
}
Err(UnresolvedMacro) => (),
}
// Case 2: resolve in module scope, expand during name resolution.

View File

@ -155,3 +155,48 @@ fn inactive_via_cfg_attr() {
"#,
);
}
#[test]
fn unresolved_legacy_scope_macro() {
check_diagnostics(
r#"
//- /lib.rs
macro_rules! m { () => {} }
m!();
m2!();
//^^^^^^ unresolved macro call
"#,
);
}
#[test]
fn unresolved_module_scope_macro() {
check_diagnostics(
r#"
//- /lib.rs
mod mac {
#[macro_export]
macro_rules! m { () => {} }
}
self::m!();
self::m2!();
//^^^^^^^^^^^^ unresolved macro call
"#,
);
}
#[test]
fn builtin_macro_fails_expansion() {
check_diagnostics(
r#"
//- /lib.rs
#[rustc_builtin_macro]
macro_rules! include { () => {} }
include!("doesntexist");
//^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
"#,
);
}