]> git.lizzy.rs Git - rust.git/commitdiff
Power up goto_implementation
authorLukas Wirth <lukastw97@gmail.com>
Mon, 15 Mar 2021 09:11:48 +0000 (10:11 +0100)
committerLukas Wirth <lukastw97@gmail.com>
Mon, 15 Mar 2021 11:10:18 +0000 (12:10 +0100)
by allowing it to be invoked on references of names, showing all (trait)
implementations of the given type in all crates including builtin types

crates/hir/src/lib.rs
crates/ide/src/goto_implementation.rs
crates/ide/src/inlay_hints.rs

index eb1cd66fb15c505076bdeed44927acc0374ec490..a9d3c915665fea84273d7a1994e705189d39fc67 100644 (file)
@@ -696,8 +696,8 @@ pub fn module(self, db: &dyn HirDatabase) -> Module {
         }
     }
 
-    pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
-        Some(self.module(db).krate())
+    pub fn krate(self, db: &dyn HirDatabase) -> Crate {
+        self.module(db).krate()
     }
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
@@ -1019,8 +1019,8 @@ pub fn module(self, db: &dyn HirDatabase) -> Module {
         Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
     }
 
-    pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
-        Some(self.module(db).krate())
+    pub fn krate(self, db: &dyn HirDatabase) -> Crate {
+        self.module(db).krate()
     }
 
     pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -1483,9 +1483,42 @@ pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
 
         inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
     }
-    pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> {
-        let impls = db.trait_impls_in_crate(krate.id);
-        impls.for_trait(trait_.id).map(Self::from).collect()
+
+    pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty }: Type) -> Vec<Impl> {
+        let def_crates = match ty.value.def_crates(db, krate) {
+            Some(def_crates) => def_crates,
+            None => return vec![],
+        };
+
+        let filter = |impl_def: &Impl| {
+            let target_ty = impl_def.target_ty(db);
+            let rref = target_ty.remove_ref();
+            ty.value.equals_ctor(rref.as_ref().map_or(&target_ty.ty.value, |it| &it.ty.value))
+        };
+
+        let mut all = Vec::new();
+        def_crates.iter().for_each(|&id| {
+            all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter))
+        });
+        for id in def_crates
+            .iter()
+            .flat_map(|&id| Crate { id }.reverse_dependencies(db))
+            .map(|Crate { id }| id)
+            .chain(def_crates.iter().copied())
+        {
+            all.extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter));
+        }
+        all
+    }
+
+    pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
+        let krate = trait_.module(db).krate();
+        let mut all = Vec::new();
+        for Crate { id } in krate.reverse_dependencies(db).into_iter().chain(Some(krate)) {
+            let impls = db.trait_impls_in_crate(id);
+            all.extend(impls.for_trait(trait_.id).map(Self::from))
+        }
+        all
     }
 
     // FIXME: the return type is wrong. This should be a hir version of
@@ -1913,12 +1946,6 @@ pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Tr
         self.ty.value.associated_type_parent_trait(db).map(Into::into)
     }
 
-    // FIXME: provide required accessors such that it becomes implementable from outside.
-    pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
-        let rref = other.remove_ref();
-        self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value))
-    }
-
     fn derived(&self, ty: Ty) -> Type {
         Type {
             krate: self.krate,
index 3990305fce2827301ff1457b15b192c120a916cd..f4d7c14a62e11c2cd48db7865c9cc203fe6cd060 100644 (file)
@@ -1,6 +1,9 @@
-use hir::{Crate, Impl, Semantics};
-use ide_db::RootDatabase;
-use syntax::{algo::find_node_at_offset, ast, AstNode};
+use hir::{Impl, Semantics};
+use ide_db::{
+    defs::{Definition, NameClass, NameRefClass},
+    RootDatabase,
+};
+use syntax::{ast, AstNode};
 
 use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
 
@@ -21,55 +24,42 @@ pub(crate) fn goto_implementation(
     let source_file = sema.parse(position.file_id);
     let syntax = source_file.syntax().clone();
 
-    let krate = sema.to_module_def(position.file_id)?.krate();
-
-    if let Some(nominal_def) = find_node_at_offset::<ast::Adt>(&syntax, position.offset) {
-        return Some(RangeInfo::new(
-            nominal_def.syntax().text_range(),
-            impls_for_def(&sema, &nominal_def, krate)?,
-        ));
-    } else if let Some(trait_def) = find_node_at_offset::<ast::Trait>(&syntax, position.offset) {
-        return Some(RangeInfo::new(
-            trait_def.syntax().text_range(),
-            impls_for_trait(&sema, &trait_def, krate)?,
-        ));
-    }
-
-    None
-}
-
-fn impls_for_def(
-    sema: &Semantics<RootDatabase>,
-    node: &ast::Adt,
-    krate: Crate,
-) -> Option<Vec<NavigationTarget>> {
-    let ty = match node {
-        ast::Adt::Struct(def) => sema.to_def(def)?.ty(sema.db),
-        ast::Adt::Enum(def) => sema.to_def(def)?.ty(sema.db),
-        ast::Adt::Union(def) => sema.to_def(def)?.ty(sema.db),
+    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| class.referenced_or_defined(sema.db))
+        }
+        ast::NameLike::NameRef(name_ref) => {
+            NameRefClass::classify(&sema, name_ref).map(|class| class.referenced(sema.db))
+        }
+        ast::NameLike::Lifetime(_) => None,
+    }?;
+    let def = match def {
+        Definition::ModuleDef(def) => def,
+        _ => return None,
     };
-
-    let impls = Impl::all_in_crate(sema.db, krate);
-
-    Some(
-        impls
-            .into_iter()
-            .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db)))
-            .filter_map(|imp| imp.try_to_nav(sema.db))
-            .collect(),
-    )
+    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))
+        }
+        _ => return None,
+    };
+    Some(RangeInfo { range: node.syntax().text_range(), info: navs })
 }
 
-fn impls_for_trait(
-    sema: &Semantics<RootDatabase>,
-    node: &ast::Trait,
-    krate: Crate,
-) -> Option<Vec<NavigationTarget>> {
-    let tr = sema.to_def(node)?;
-
-    let impls = Impl::for_trait(sema.db, krate, tr);
+fn impls_for_ty(sema: &Semantics<RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> {
+    Impl::all_for_type(sema.db, ty).into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()
+}
 
-    Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect())
+fn impls_for_trait(sema: &Semantics<RootDatabase>, trait_: hir::Trait) -> Vec<NavigationTarget> {
+    Impl::all_for_trait(sema.db, trait_)
+        .into_iter()
+        .filter_map(|imp| imp.try_to_nav(sema.db))
+        .collect()
 }
 
 #[cfg(test)]
@@ -223,6 +213,50 @@ trait Copy {}
 }
 #[rustc_builtin_macro]
 macro Copy {}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_implementation_type_alias() {
+        check(
+            r#"
+struct Foo;
+
+type Bar$0 = Foo;
+
+impl Foo {}
+   //^^^
+impl Bar {}
+   //^^^
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_implementation_adt_generic() {
+        check(
+            r#"
+struct Foo$0<T>;
+
+impl<T> Foo<T> {}
+      //^^^^^^
+impl Foo<str> {}
+   //^^^^^^^^
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_implementation_builtin() {
+        check(
+            r#"
+//- /lib.rs crate:main deps:core
+fn foo(_: bool$0) {{}}
+//- /libcore.rs crate:core
+#[lang = "bool"]
+impl bool {}
+   //^^^^
 "#,
         );
     }
index 4ceb2074209d62842ba53afb5bfdf801c6c6741c..16c04eeeeece33b273681c0435a71644adf522ce 100644 (file)
@@ -219,7 +219,7 @@ fn hint_iterator(
     let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref())
         .last()
         .and_then(|strukt| strukt.as_adt())?;
-    let krate = strukt.krate(db)?;
+    let krate = strukt.krate(db);
     if krate != famous_defs.core()? {
         return None;
     }