about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-09-01 12:52:29 +0000
committerGitHub <noreply@github.com>2021-09-01 12:52:29 +0000
commit1b8a294555348d128b0641e3afec4fa830624d8d (patch)
treeddd92487059a011de3d8c650bed2290f5238d5ec
parent25368d24308d6a94ffe8b99f0122bcf5a2175322 (diff)
parent68bf3593637adf9aa36cc4d1e11938720ca056eb (diff)
downloadrust-1b8a294555348d128b0641e3afec4fa830624d8d.tar.gz
rust-1b8a294555348d128b0641e3afec4fa830624d8d.zip
Merge #10108
10108: fix: make `goto_implementation` multi-token mapping aware r=Veykril a=Veykril

bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
-rw-r--r--crates/ide/src/goto_implementation.rs111
-rw-r--r--crates/ide_db/src/search.rs4
2 files changed, 67 insertions, 48 deletions
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 0fc922125ca..e5b88261275 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -1,9 +1,11 @@
 use hir::{AsAssocItem, Impl, Semantics};
 use ide_db::{
     defs::{Definition, NameClass, NameRefClass},
+    helpers::pick_best_token,
     RootDatabase,
 };
-use syntax::{ast, AstNode};
+use itertools::Itertools;
+use syntax::{ast, AstNode, SyntaxKind::*, T};
 
 use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
 
@@ -26,52 +28,71 @@ pub(crate) fn goto_implementation(
     let source_file = sema.parse(position.file_id);
     let syntax = source_file.syntax().clone();
 
-    let node = sema.find_node_at_offset_with_descend(&syntax, position.offset)?;
-    let def = match &node {
-        ast::NameLike::Name(name) => NameClass::classify(&sema, name).map(|class| match class {
-            NameClass::Definition(it) | NameClass::ConstReference(it) => it,
-            NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
-                Definition::Local(local_def)
-            }
-        }),
-        ast::NameLike::NameRef(name_ref) => {
-            NameRefClass::classify(&sema, name_ref).map(|class| match class {
-                NameRefClass::Definition(def) => def,
-                NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
-                    Definition::Local(local_ref)
+    let original_token =
+        pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind {
+            IDENT | T![self] => 1,
+            _ => 0,
+        })?;
+    let range = original_token.text_range();
+    let navs =
+        sema.descend_into_macros_many(original_token)
+            .into_iter()
+            .filter_map(|token| token.parent().and_then(ast::NameLike::cast))
+            .filter_map(|node| {
+                let def = match &node {
+                    ast::NameLike::Name(name) => {
+                        NameClass::classify(&sema, name).map(|class| match class {
+                            NameClass::Definition(it) | NameClass::ConstReference(it) => it,
+                            NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
+                                Definition::Local(local_def)
+                            }
+                        })
+                    }
+                    ast::NameLike::NameRef(name_ref) => NameRefClass::classify(&sema, name_ref)
+                        .map(|class| match class {
+                            NameRefClass::Definition(def) => def,
+                            NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
+                                Definition::Local(local_ref)
+                            }
+                        }),
+                    ast::NameLike::Lifetime(_) => None,
+                }?;
+
+                match def {
+                    Definition::ModuleDef(def) => Some(def),
+                    _ => None,
                 }
             })
-        }
-        ast::NameLike::Lifetime(_) => None,
-    }?;
-
-    let def = match def {
-        Definition::ModuleDef(def) => def,
-        _ => return None,
-    };
-    let navs = match def {
-        hir::ModuleDef::Trait(trait_) => impls_for_trait(&sema, trait_),
-        hir::ModuleDef::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
-        hir::ModuleDef::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
-        hir::ModuleDef::BuiltinType(builtin) => {
-            let module = sema.to_module_def(position.file_id)?;
-            impls_for_ty(&sema, builtin.ty(sema.db, module))
-        }
-        hir::ModuleDef::Function(f) => {
-            let assoc = f.as_assoc_item(sema.db)?;
-            let name = assoc.name(sema.db)?;
-            let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
-            impls_for_trait_item(&sema, trait_, name)
-        }
-        hir::ModuleDef::Const(c) => {
-            let assoc = c.as_assoc_item(sema.db)?;
-            let name = assoc.name(sema.db)?;
-            let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
-            impls_for_trait_item(&sema, trait_, name)
-        }
-        _ => return None,
-    };
-    Some(RangeInfo { range: node.syntax().text_range(), info: navs })
+            .unique()
+            .filter_map(|def| {
+                let navs = match def {
+                    hir::ModuleDef::Trait(trait_) => impls_for_trait(&sema, trait_),
+                    hir::ModuleDef::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
+                    hir::ModuleDef::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
+                    hir::ModuleDef::BuiltinType(builtin) => {
+                        let module = sema.to_module_def(position.file_id)?;
+                        impls_for_ty(&sema, builtin.ty(sema.db, module))
+                    }
+                    hir::ModuleDef::Function(f) => {
+                        let assoc = f.as_assoc_item(sema.db)?;
+                        let name = assoc.name(sema.db)?;
+                        let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+                        impls_for_trait_item(&sema, trait_, name)
+                    }
+                    hir::ModuleDef::Const(c) => {
+                        let assoc = c.as_assoc_item(sema.db)?;
+                        let name = assoc.name(sema.db)?;
+                        let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+                        impls_for_trait_item(&sema, trait_, name)
+                    }
+                    _ => return None,
+                };
+                Some(navs)
+            })
+            .flatten()
+            .collect();
+
+    Some(RangeInfo { range, info: navs })
 }
 
 fn impls_for_ty(sema: &Semantics<RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> {
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 855675be421..c288c5c3e08 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -442,9 +442,7 @@ impl<'a> FindUsages<'a> {
                         continue;
                     }
 
-                    if let Some(ast::NameLike::NameRef(name_ref)) =
-                        sema.find_node_at_offset_with_descend(&tree, offset)
-                    {
+                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
                         if self.found_self_module_name_ref(&name_ref, sink) {
                             return;
                         }