Repository: racer-rust/racer (language: rust)

Issue:
Can not find the second item in nested group
I use racer 2.1.0.

I created simple crate,
**Cargo.toml**
```toml
[package]
name = "foo"
version = "0.1.0"
authors = ["Rust Example <rust-snippet@example.com>"]

[dependencies]
spade = "1.5.1"
```
**src/main.rs**
```Rust
extern crate spade;

use spade::{rtree::RTree, PointN};
//use spade::PointN;

fn main() {}
```

If in line `use spade::{rtree::RTree, PointN};` move cursor to `PointN` and execute
`M-x racer-find-definition` it prints "No definition found",
but it works for `rtree::RTree` and also if comment nested group line and uncomment
`use spade::PointN;` line, then it jump to `PointN` without problem.


Discussion / hints:
Thanks for reporting.
I'm sure it's my bag :sweat: , sorry.

Fix patch:
diff --git a/src/racer/nameres.rs b/src/racer/nameres.rs
index f73955b5..c7565018 100644
--- a/src/racer/nameres.rs
+++ b/src/racer/nameres.rs
@@ -2009,13 +2009,21 @@ fn get_std_macros(
         if !macro_path.exists() {
             return;
         }
-        get_std_macros_(&macro_path, searchstr, search_type, session, out);
+        get_std_macros_(
+            &macro_path,
+            searchstr,
+            macro_file == &"libcore/macros.rs",
+            search_type,
+            session,
+            out
+        );
     }
 }
 
 fn get_std_macros_(
     macro_path: &Path,
     searchstr: &str,
+    is_core: bool,
     search_type: SearchType,
     session: &Session,
     out: &mut Vec<Match>,
@@ -2023,7 +2031,7 @@ fn get_std_macros_(
     let src = session.load_file(&macro_path);
     let mut export = false;
     let mut get_macro_def = |blob: &str| -> Option<(BytePos, String)> {
-        if blob.starts_with("#[macro_export]") {
+        if blob.starts_with("#[macro_export]") | blob.starts_with("#[rustc_doc_only_macro]") {
             export = true;
             return None;
         }
@@ -2057,9 +2065,9 @@ fn get_std_macros_(
        .iter_stmts()
        .filter_map(|range| {
            let blob = &src[range.to_range()];
-           // for builtin macros in libstd/macros.rs
-           if blob.starts_with("pub mod builtin") {
-               builtin_start = blob.find("#[macro_export]").map(|u| range.start + u.into());
+           // for builtin macros in libcore/macros.rs
+           if is_core && blob.starts_with("mod builtin") {
+               builtin_start = blob.find("#").map(|u| range.start + u.into());
            }
            let (offset, matchstr) = get_macro_def(blob)?;
            let start = range.start + offset;
diff --git a/src/racer/scopes.rs b/src/racer/scopes.rs
index 8a7836dc..6de3d403 100644
--- a/src/racer/scopes.rs
+++ b/src/racer/scopes.rs
@@ -577,6 +577,27 @@ fn test_use_stmt_start() {
     assert_eq!(use_stmt_start("pub(crate)   use   some::").unwrap().0, 19);
 }
 
+#[inline(always)]
+fn next_use_item(expr: &str) -> Option<usize> {
+    let bytes = expr.as_bytes();
+    let mut i = bytes.len();
+    let mut before = b' ';
+    while i > 0 {
+        i -= 1;
+        let cur = bytes[i];
+        if before == b':' && cur == b':' {
+            return Some(i);
+        }
+        if cur == b',' {
+            while i > 0 && bytes[i] != b'{' {
+                i -= 1;
+            }
+        }
+        before = cur;
+    }
+    None
+}
+
 /// get path from use statement, supposing completion point is end of expr
 /// e.g. "use std::collections::{hash_map,  Hash" -> P["std", "collections", "Hash"]
 pub(crate) fn construct_path_from_use_tree(expr: &str) -> core::Path {
@@ -595,11 +616,9 @@ pub(crate) fn construct_path_from_use_tree(expr: &str) -> core::Path {
                 segments.push(&expr[i + 1..=end]);
                 ident_end = None;
             }
-            if let Some(point) = expr[..=i].rfind("::") {
-                if point > 0 {
-                    i = point;
-                    continue
-                }
+            if let Some(point) = next_use_item(&expr[..=i]) {
+                i = point;
+                continue;
             }
             break;
         }
@@ -607,9 +626,6 @@ pub(crate) fn construct_path_from_use_tree(expr: &str) -> core::Path {
     if let Some(end) = ident_end {
         segments.push(&expr[0..=end]);
     }
-    if let Some(&"crate") = segments.last() {
-        segments.pop();
-    }
     segments.reverse();
     let is_global = expr.starts_with("::");
     core::Path::from_vec(is_global, segments)
@@ -637,6 +653,14 @@ fn test_construct_path_from_use_tree() {
         get_path_idents("std::collections::{"),
         vec!["std", "collections", ""],
     );
+    assert_eq!(
+        get_path_idents("std::{collections::HashMap, sync::Arc"),
+        vec!["std", "sync", "Arc"],
+    );
+    assert_eq!(
+        get_path_idents("{Str1, module::Str2, Str3"),
+        vec!["Str3"],
+    );
 }
 
 /// get current line string parsed by ;


Test patch:
diff --git a/tests/system.rs b/tests/system.rs
index 384fa5d9..0d6900c4 100644
--- a/tests/system.rs
+++ b/tests/system.rs
@@ -4289,24 +4289,7 @@ fn finds_std_macro_doc() {
     }
     "#;
     let got = get_definition(src, None);
-    let doc = r#"Expands to a string that represents the current module path.
-
-The current module path can be thought of as the hierarchy of modules
-leading back up to the crate root. The first component of the path
-returned is the name of the crate currently being compiled.
-
-# Examples
-
-```
-mod test {
-    pub fn foo() {
-        assert!(module_path!().ends_with("test"));
-    }
-}
-
-test::foo();
-```"#;
-    assert_eq!(got.docs, doc);
+    assert!(!got.docs.is_empty());
 }
 
 #[test]