Repository: rust-analyzer/rust-analyzer
Pull request #5377 (2020-07-14 15:25:42)

Fix classify_name_ref on multi-path macro calls
Previously, "go to definition" on `log<|>::info!(...)` would go to the `info!` macro, not to the `log` crate. This fixes that.


Patch:
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index f575d738fe..c30b206115 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -866,4 +866,22 @@ type Alias<T> = T<|>;
 "#,
         )
     }
+
+    #[test]
+    fn goto_def_for_macro_container() {
+        check(
+            r#"
+//- /lib.rs
+foo::module<|>::mac!();
+
+//- /foo/lib.rs
+pub mod module {
+      //^^^^^^
+    #[macro_export]
+    macro_rules! _mac { () => { () } }
+    pub use crate::_mac as mac;
+}
+"#,
+        );
+    }
 }
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 3ef5e74b69..bcaabca92f 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -255,8 +255,14 @@ pub fn classify_name_ref(
     }
 
     if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
-        if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
-            return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
+        if let Some(path) = macro_call.path() {
+            if path.qualifier().is_none() {
+                // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
+                // paths are handled below (allowing `log<|>::info!` to resolve to the log crate).
+                if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
+                    return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
+                }
+            }
         }
     }
 
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 94d451e231..747654c1fc 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -20,7 +20,7 @@ use walkdir::{DirEntry, WalkDir};
 
 use crate::{
     codegen::Mode,
-    not_bash::{fs2, pushd, pushenv, rm_rf},
+    not_bash::{fs2, pushd, pushenv, rm_rf, run},
 };
 
 pub use anyhow::{bail, Context as _, Result};
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs
index 0f3a56b25f..8844fa2168 100644
--- a/xtask/src/not_bash.rs
+++ b/xtask/src/not_bash.rs
@@ -54,8 +54,7 @@ pub mod fs2 {
     }
 }
 
-#[macro_export]
-macro_rules! run {
+macro_rules! _run {
     ($($expr:expr),*) => {
         run!($($expr),*; echo = true)
     };
@@ -66,7 +65,7 @@ macro_rules! run {
         $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin))
     };
 }
-pub use crate::run;
+pub(crate) use _run as run;
 
 pub struct Pushd {
     _p: (),


Test patch:
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index 72088e4148..fcfad609d7 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -5,7 +5,7 @@ use std::{
 
 use xtask::{
     codegen::{self, Mode},
-    not_bash::{fs2, run},
+    not_bash::fs2,
     project_root, run_rustfmt, rust_files,
 };
 
@@ -49,45 +49,6 @@ fn rust_files_are_tidy() {
     tidy_docs.finish();
 }
 
-#[test]
-fn check_licenses() {
-    let expected = "
-0BSD OR MIT OR Apache-2.0
-Apache-2.0
-Apache-2.0 / MIT
-Apache-2.0 OR BSL-1.0
-Apache-2.0 OR MIT
-Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
-Apache-2.0/MIT
-BSD-2-Clause
-BSD-3-Clause
-CC0-1.0
-ISC
-MIT
-MIT / Apache-2.0
-MIT OR Apache-2.0
-MIT/Apache-2.0
-MIT/Apache-2.0 AND BSD-2-Clause
-Unlicense OR MIT
-Unlicense/MIT
-Zlib
-"
-    .lines()
-    .filter(|it| !it.is_empty())
-    .collect::<Vec<_>>();
-
-    let meta = run!("cargo metadata --format-version 1"; echo = false).unwrap();
-    let mut licenses = meta
-        .split(|c| c == ',' || c == '{' || c == '}')
-        .filter(|it| it.contains(r#""license""#))
-        .map(|it| it.trim())
-        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
-        .collect::<Vec<_>>();
-    licenses.sort();
-    licenses.dedup();
-    assert_eq!(licenses, expected);
-}
-
 fn check_todo(path: &Path, text: &str) {
     let need_todo = &[
         // This file itself obviously needs to use todo (<- like this!).