diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 93 |
1 files changed, 36 insertions, 57 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index d8e67bbd9..27bd1e37f 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type}; | 1 | use assists::utils::FamousDefs; |
2 | use hir::{known, Adt, AssocItem, Callable, HirDisplay, Semantics, Type}; | ||
2 | use ide_db::RootDatabase; | 3 | use ide_db::RootDatabase; |
3 | use stdx::to_lower_snake_case; | 4 | use stdx::to_lower_snake_case; |
4 | use syntax::{ | 5 | use syntax::{ |
@@ -194,7 +195,7 @@ fn get_bind_pat_hints( | |||
194 | } | 195 | } |
195 | 196 | ||
196 | let db = sema.db; | 197 | let db = sema.db; |
197 | if let Some(hint) = hint_iterator(db, config, &ty, pat.clone()) { | 198 | if let Some(hint) = hint_iterator(sema, config, &ty, pat.clone()) { |
198 | acc.push(hint); | 199 | acc.push(hint); |
199 | } else { | 200 | } else { |
200 | acc.push(InlayHint { | 201 | acc.push(InlayHint { |
@@ -209,45 +210,44 @@ fn get_bind_pat_hints( | |||
209 | 210 | ||
210 | /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`. | 211 | /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`. |
211 | fn hint_iterator( | 212 | fn hint_iterator( |
212 | db: &RootDatabase, | 213 | sema: &Semantics<RootDatabase>, |
213 | config: &InlayHintsConfig, | 214 | config: &InlayHintsConfig, |
214 | ty: &Type, | 215 | ty: &Type, |
215 | pat: ast::IdentPat, | 216 | pat: ast::IdentPat, |
216 | ) -> Option<InlayHint> { | 217 | ) -> Option<InlayHint> { |
218 | let db = sema.db; | ||
217 | let strukt = ty.as_adt()?; | 219 | let strukt = ty.as_adt()?; |
218 | let krate = strukt.krate(db)?; | 220 | let krate = strukt.krate(db)?; |
219 | let module = strukt.module(db); | ||
220 | if krate.declaration_name(db).as_deref() != Some("core") { | 221 | if krate.declaration_name(db).as_deref() != Some("core") { |
221 | return None; | 222 | return None; |
222 | } | 223 | } |
223 | let module = module | 224 | // assert this type comes from `core::iter` |
225 | strukt | ||
226 | .module(db) | ||
224 | .path_to_root(db) | 227 | .path_to_root(db) |
225 | .into_iter() | 228 | .into_iter() |
226 | .rev() | 229 | .rev() |
227 | .find(|module| module.name(db) == Some(known::iter))?; | 230 | .find(|module| module.name(db) == Some(known::iter))?; |
228 | let iter_trait = module.scope(db, None).into_iter().find_map(|(name, def)| match def { | 231 | let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; |
229 | hir::ScopeDef::ModuleDef(ModuleDef::Trait(r#trait)) if name == known::Iterator => { | ||
230 | Some(r#trait) | ||
231 | } | ||
232 | _ => None, | ||
233 | })?; | ||
234 | if ty.impls_trait(db, iter_trait, &[]) { | 232 | if ty.impls_trait(db, iter_trait, &[]) { |
235 | let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { | 233 | let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { |
236 | AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), | 234 | AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), |
237 | _ => None, | 235 | _ => None, |
238 | })?; | 236 | })?; |
239 | if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { | 237 | if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { |
238 | const LABEL_START: &str = "impl Iterator<Item = "; | ||
239 | const LABEL_END: &str = ">"; | ||
240 | |||
241 | let ty_display = ty.display_truncated( | ||
242 | db, | ||
243 | config | ||
244 | .max_length | ||
245 | .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())), | ||
246 | ); | ||
240 | return Some(InlayHint { | 247 | return Some(InlayHint { |
241 | range: pat.syntax().text_range(), | 248 | range: pat.syntax().text_range(), |
242 | kind: InlayKind::TypeHint, | 249 | kind: InlayKind::TypeHint, |
243 | label: format!( | 250 | label: format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into(), |
244 | "impl Iterator<Item = {}>", | ||
245 | ty.display_truncated( | ||
246 | db, | ||
247 | config.max_length.map(|len| len - 22 /*len of the template string above*/) | ||
248 | ) | ||
249 | ) | ||
250 | .into(), | ||
251 | }); | 251 | }); |
252 | } | 252 | } |
253 | } | 253 | } |
@@ -401,6 +401,7 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Call | |||
401 | 401 | ||
402 | #[cfg(test)] | 402 | #[cfg(test)] |
403 | mod tests { | 403 | mod tests { |
404 | use assists::utils::FamousDefs; | ||
404 | use expect_test::{expect, Expect}; | 405 | use expect_test::{expect, Expect}; |
405 | use test_utils::extract_annotations; | 406 | use test_utils::extract_annotations; |
406 | 407 | ||
@@ -1124,15 +1125,26 @@ fn main() { | |||
1124 | chaining_hints: true, | 1125 | chaining_hints: true, |
1125 | max_length: None, | 1126 | max_length: None, |
1126 | }, | 1127 | }, |
1127 | r#" | 1128 | &format!( |
1129 | "{}\n{}\n", | ||
1130 | r#" | ||
1128 | //- /main.rs crate:main deps:std | 1131 | //- /main.rs crate:main deps:std |
1129 | use std::{Option::{self, Some, None}, iter}; | 1132 | use std::{Option::{self, Some, None}, iter}; |
1130 | 1133 | ||
1134 | struct MyIter; | ||
1135 | |||
1136 | impl iter::Iterator for MyIter { | ||
1137 | type Item = (); | ||
1138 | fn next(&mut self) -> Option<Self::Item> { | ||
1139 | None | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1131 | fn main() { | 1143 | fn main() { |
1144 | let _x = MyIter; | ||
1145 | //^^ MyIter | ||
1132 | let _x = iter::repeat(0); | 1146 | let _x = iter::repeat(0); |
1133 | //^^ impl Iterator<Item = i32> | 1147 | //^^ impl Iterator<Item = i32> |
1134 | let _y = iter::Chain(iter::repeat(0), iter::repeat(0)); | ||
1135 | //^^ impl Iterator<Item = i32> | ||
1136 | fn generic<T: Clone>(t: T) { | 1148 | fn generic<T: Clone>(t: T) { |
1137 | let _x = iter::repeat(t); | 1149 | let _x = iter::repeat(t); |
1138 | //^^ impl Iterator<Item = T> | 1150 | //^^ impl Iterator<Item = T> |
@@ -1141,42 +1153,9 @@ fn main() { | |||
1141 | 1153 | ||
1142 | //- /std.rs crate:std deps:core | 1154 | //- /std.rs crate:std deps:core |
1143 | use core::*; | 1155 | use core::*; |
1144 | |||
1145 | //- /core.rs crate:core | ||
1146 | pub enum Option<T> { | ||
1147 | Some(T), | ||
1148 | None | ||
1149 | } | ||
1150 | |||
1151 | pub mod iter { | ||
1152 | pub use self::traits::iterator::Iterator; | ||
1153 | pub mod traits { pub mod iterator { | ||
1154 | pub trait Iterator { | ||
1155 | type Item; | ||
1156 | } | ||
1157 | } } | ||
1158 | |||
1159 | pub use self::sources::*; | ||
1160 | pub mod sources { | ||
1161 | use super::Iterator; | ||
1162 | pub struct Repeat<T: Clone>(pub T); | ||
1163 | |||
1164 | pub fn repeat<T: Clone>(t: T) -> Repeat<T> { | ||
1165 | Repeat(f) | ||
1166 | } | ||
1167 | |||
1168 | impl<T: Clone> Iterator for Repeat<T> { | ||
1169 | type Item = T; | ||
1170 | } | ||
1171 | |||
1172 | pub struct Chain<A, B>(pub A, pub B); | ||
1173 | |||
1174 | impl<T, A, B> Iterator for Chain<A, B> where A: Iterator<Item = T>, B: Iterator<Item = T> { | ||
1175 | type Item = T; | ||
1176 | } | ||
1177 | } | ||
1178 | } | ||
1179 | "#, | 1156 | "#, |
1157 | FamousDefs::FIXTURE | ||
1158 | ), | ||
1180 | ); | 1159 | ); |
1181 | } | 1160 | } |
1182 | } | 1161 | } |