]> git.lizzy.rs Git - rust.git/commitdiff
Use FamousDefs for shorten_iterator hint
authorLukas Wirth <lukastw97@gmail.com>
Tue, 6 Oct 2020 19:05:57 +0000 (21:05 +0200)
committerLukas Wirth <lukastw97@gmail.com>
Tue, 6 Oct 2020 19:25:39 +0000 (21:25 +0200)
crates/assists/src/utils.rs
crates/ide/src/inlay_hints.rs

index eb69c49a499350fa542fb50c943ee69df2903db6..0335969fd91b8d15e82d367bf9616640639089f3 100644 (file)
@@ -274,24 +274,54 @@ fn type_name(self) -> &'static str {
 /// somewhat similar to the known paths infra inside hir, but it different; We
 /// want to make sure that IDE specific paths don't become interesting inside
 /// the compiler itself as well.
-pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate);
+pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
 
 #[allow(non_snake_case)]
 impl FamousDefs<'_, '_> {
-    #[cfg(test)]
-    pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
+    pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
 pub mod convert {
     pub trait From<T> {
         fn from(T) -> Self;
     }
 }
 
+pub mod iter {
+    pub use self::traits::iterator::Iterator;
+    mod traits { mod iterator {
+        use crate::option::Option;
+        pub trait Iterator {
+            type Item;
+            fn next(&mut self) -> Option<Self::Item>;
+        }
+    } }
+
+    pub use self::sources::*;
+    mod sources {
+        use super::Iterator;
+        pub struct Repeat<A> {
+            element: A,
+        }
+
+        pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
+            Repeat { element: elt }
+        }
+
+        impl<A: Clone> Iterator for Repeat<A> {
+            type Item = A;
+
+            fn next(&mut self) -> Option<A> {
+                Some(self.element.clone())
+            }
+        }
+    }
+}
+
 pub mod option {
     pub enum Option<T> { None, Some(T)}
 }
 
 pub mod prelude {
-    pub use crate::{convert::From, option::Option::{self, *}};
+    pub use crate::{convert::From, iter::Iterator, option::Option::{self, *}};
 }
 #[prelude_import]
 pub use prelude::*;
@@ -305,6 +335,10 @@ pub(crate) fn core_option_Option(&self) -> Option<Enum> {
         self.find_enum("core:option:Option")
     }
 
+    pub fn core_iter_Iterator(&self) -> Option<Trait> {
+        self.find_trait("core:iter:traits:iterator:Iterator")
+    }
+
     fn find_trait(&self, path: &str) -> Option<Trait> {
         match self.find_def(path)? {
             hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
@@ -324,18 +358,21 @@ fn find_def(&self, path: &str) -> Option<ScopeDef> {
         let mut path = path.split(':');
         let trait_ = path.next_back()?;
         let std_crate = path.next()?;
-        let std_crate = self
+        let std_crate = if self
             .1
-            .dependencies(db)
-            .into_iter()
-            .find(|dep| &dep.name.to_string() == std_crate)?
-            .krate;
-
+            .declaration_name(db)
+            .map(|name| name.to_string() == std_crate)
+            .unwrap_or(false)
+        {
+            self.1
+        } else {
+            self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
+        };
         let mut module = std_crate.root_module(db);
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
-                if &name.to_string() == segment {
+                if name.to_string() == segment {
                     Some(child)
                 } else {
                     None
@@ -343,7 +380,7 @@ fn find_def(&self, path: &str) -> Option<ScopeDef> {
             })?;
         }
         let def =
-            module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1;
+            module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
         Some(def)
     }
 }
index d8e67bbd90939171facdbf21a2df626324ca7ab5..27bd1e37f4bea918d7a6410a13b8b366d1f6e48b 100644 (file)
@@ -1,4 +1,5 @@
-use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type};
+use assists::utils::FamousDefs;
+use hir::{known, Adt, AssocItem, Callable, HirDisplay, Semantics, Type};
 use ide_db::RootDatabase;
 use stdx::to_lower_snake_case;
 use syntax::{
@@ -194,7 +195,7 @@ fn get_bind_pat_hints(
     }
 
     let db = sema.db;
-    if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) {
+    if let Some(hint) = hint_iterator(sema, config, &ty, pat.clone()) {
         acc.push(hint);
     } else {
         acc.push(InlayHint {
@@ -209,45 +210,44 @@ fn get_bind_pat_hints(
 
 /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
 fn hint_iterator(
-    db: &RootDatabase,
+    sema: &Semantics<RootDatabase>,
     config: &InlayHintsConfig,
     ty: &Type,
     pat: ast::IdentPat,
 ) -> Option<InlayHint> {
+    let db = sema.db;
     let strukt = ty.as_adt()?;
     let krate = strukt.krate(db)?;
-    let module = strukt.module(db);
     if krate.declaration_name(db).as_deref() != Some("core") {
         return None;
     }
-    let module = module
+    // assert this type comes from `core::iter`
+    strukt
+        .module(db)
         .path_to_root(db)
         .into_iter()
         .rev()
         .find(|module| module.name(db) == Some(known::iter))?;
-    let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def {
-        hir::ScopeDef::ModuleDef(ModuleDef::Trait(r#trait)) if name == known::Iterator => {
-            Some(r#trait)
-        }
-        _ => None,
-    })?;
+    let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
     if ty.impls_trait(db, iter_trait, &[]) {
         let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
             AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
             _ => None,
         })?;
         if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) {
+            const LABEL_START: &str = "impl Iterator<Item = ";
+            const LABEL_END: &str = ">";
+
+            let ty_display = ty.display_truncated(
+                db,
+                config
+                    .max_length
+                    .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
+            );
             return Some(InlayHint {
                 range: pat.syntax().text_range(),
                 kind: InlayKind::TypeHint,
-                label: format!(
-                    "impl Iterator<Item = {}>",
-                    ty.display_truncated(
-                        db,
-                        config.max_length.map(|len| len - 22 /*len of the template string above*/)
-                    )
-                )
-                .into(),
+                label: format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into(),
             });
         }
     }
@@ -401,6 +401,7 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Call
 
 #[cfg(test)]
 mod tests {
+    use assists::utils::FamousDefs;
     use expect_test::{expect, Expect};
     use test_utils::extract_annotations;
 
@@ -1124,15 +1125,26 @@ fn shorten_iterator_hints() {
                 chaining_hints: true,
                 max_length: None,
             },
-            r#"
+            &format!(
+                "{}\n{}\n",
+                r#"
 //- /main.rs crate:main deps:std
 use std::{Option::{self, Some, None}, iter};
 
+struct MyIter;
+
+impl iter::Iterator for MyIter {
+    type Item = ();
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
+
 fn main() {
+    let _x = MyIter;
+      //^^ MyIter
     let _x = iter::repeat(0);
       //^^ impl Iterator<Item = i32>
-    let _y = iter::Chain(iter::repeat(0), iter::repeat(0));
-      //^^ impl Iterator<Item = i32>
     fn generic<T: Clone>(t: T) {
         let _x = iter::repeat(t);
           //^^ impl Iterator<Item = T>
@@ -1141,42 +1153,9 @@ fn generic<T: Clone>(t: T) {
 
 //- /std.rs crate:std deps:core
 use core::*;
-
-//- /core.rs crate:core
-pub enum Option<T> {
-    Some(T),
-    None
-}
-
-pub mod iter {
-    pub use self::traits::iterator::Iterator;
-    pub mod traits { pub mod iterator {
-        pub trait Iterator {
-            type Item;
-        }
-    } }
-
-    pub use self::sources::*;
-    pub mod sources {
-        use super::Iterator;
-        pub struct Repeat<T: Clone>(pub T);
-
-        pub fn repeat<T: Clone>(t: T) -> Repeat<T> {
-            Repeat(f)
-        }
-
-        impl<T: Clone> Iterator for Repeat<T> {
-            type Item = T;
-        }
-
-        pub struct Chain<A, B>(pub A, pub B);
-
-        impl<T, A, B> Iterator for Chain<A, B> where A: Iterator<Item = T>, B: Iterator<Item = T> {
-            type Item = T;
-        }
-    }
-}
 "#,
+                FamousDefs::FIXTURE
+            ),
         );
     }
 }