aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/inlay_hints.rs93
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 @@
1use hir::{known, Adt, AssocItem, Callable, HirDisplay, ModuleDef, Semantics, Type}; 1use assists::utils::FamousDefs;
2use hir::{known, Adt, AssocItem, Callable, HirDisplay, Semantics, Type};
2use ide_db::RootDatabase; 3use ide_db::RootDatabase;
3use stdx::to_lower_snake_case; 4use stdx::to_lower_snake_case;
4use syntax::{ 5use 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>`.
211fn hint_iterator( 212fn 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)]
403mod tests { 403mod 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
1129use std::{Option::{self, Some, None}, iter}; 1132use std::{Option::{self, Some, None}, iter};
1130 1133
1134struct MyIter;
1135
1136impl iter::Iterator for MyIter {
1137 type Item = ();
1138 fn next(&mut self) -> Option<Self::Item> {
1139 None
1140 }
1141}
1142
1131fn main() { 1143fn 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
1143use core::*; 1155use core::*;
1144
1145//- /core.rs crate:core
1146pub enum Option<T> {
1147 Some(T),
1148 None
1149}
1150
1151pub 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}