aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/utils.rs')
-rw-r--r--crates/assists/src/utils.rs131
1 files changed, 117 insertions, 14 deletions
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index b0511ceb6..c1847f601 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -3,7 +3,7 @@ pub(crate) mod insert_use;
3 3
4use std::{iter, ops}; 4use std::{iter, ops};
5 5
6use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; 6use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type};
7use ide_db::RootDatabase; 7use ide_db::RootDatabase;
8use itertools::Itertools; 8use itertools::Itertools;
9use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
@@ -19,6 +19,27 @@ use crate::assist_config::SnippetCap;
19pub use insert_use::MergeBehaviour; 19pub use insert_use::MergeBehaviour;
20pub(crate) use insert_use::{insert_use, ImportScope}; 20pub(crate) use insert_use::{insert_use, ImportScope};
21 21
22pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
23 let mut segments = Vec::new();
24 let mut is_abs = false;
25 match path.kind {
26 hir::PathKind::Plain => {}
27 hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
28 hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
29 hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
30 segments.push(make::path_segment_crate())
31 }
32 hir::PathKind::Abs => is_abs = true,
33 }
34
35 segments.extend(
36 path.segments
37 .iter()
38 .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
39 );
40 make::path_from_segments(segments, is_abs)
41}
42
22pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { 43pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
23 extract_trivial_expression(&block) 44 extract_trivial_expression(&block)
24 .filter(|expr| !expr.syntax().text().contains_char('\n')) 45 .filter(|expr| !expr.syntax().text().contains_char('\n'))
@@ -253,15 +274,79 @@ impl TryEnum {
253/// somewhat similar to the known paths infra inside hir, but it different; We 274/// somewhat similar to the known paths infra inside hir, but it different; We
254/// want to make sure that IDE specific paths don't become interesting inside 275/// want to make sure that IDE specific paths don't become interesting inside
255/// the compiler itself as well. 276/// the compiler itself as well.
256pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate); 277pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
257 278
258#[allow(non_snake_case)] 279#[allow(non_snake_case)]
259impl FamousDefs<'_, '_> { 280impl FamousDefs<'_, '_> {
260 #[cfg(test)] 281 pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
261 pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
262pub mod convert { 282pub mod convert {
263 pub trait From<T> { 283 pub trait From<T> {
264 fn from(T) -> Self; 284 fn from(t: T) -> Self;
285 }
286}
287
288pub mod iter {
289 pub use self::traits::{collect::IntoIterator, iterator::Iterator};
290 mod traits {
291 pub(crate) mod iterator {
292 use crate::option::Option;
293 pub trait Iterator {
294 type Item;
295 fn next(&mut self) -> Option<Self::Item>;
296 fn by_ref(&mut self) -> &mut Self {
297 self
298 }
299 fn take(self, n: usize) -> crate::iter::Take<Self> {
300 crate::iter::Take { inner: self }
301 }
302 }
303
304 impl<I: Iterator> Iterator for &mut I {
305 type Item = I::Item;
306 fn next(&mut self) -> Option<I::Item> {
307 (**self).next()
308 }
309 }
310 }
311 pub(crate) mod collect {
312 pub trait IntoIterator {
313 type Item;
314 }
315 }
316 }
317
318 pub use self::sources::*;
319 pub(crate) mod sources {
320 use super::Iterator;
321 use crate::option::Option::{self, *};
322 pub struct Repeat<A> {
323 element: A,
324 }
325
326 pub fn repeat<T>(elt: T) -> Repeat<T> {
327 Repeat { element: elt }
328 }
329
330 impl<A> Iterator for Repeat<A> {
331 type Item = A;
332
333 fn next(&mut self) -> Option<A> {
334 None
335 }
336 }
337 }
338
339 pub use self::adapters::*;
340 pub(crate) mod adapters {
341 use super::Iterator;
342 use crate::option::Option::{self, *};
343 pub struct Take<I> { pub(crate) inner: I }
344 impl<I> Iterator for Take<I> where I: Iterator {
345 type Item = <I as Iterator>::Item;
346 fn next(&mut self) -> Option<<I as Iterator>::Item> {
347 None
348 }
349 }
265 } 350 }
266} 351}
267 352
@@ -270,7 +355,7 @@ pub mod option {
270} 355}
271 356
272pub mod prelude { 357pub mod prelude {
273 pub use crate::{convert::From, option::Option::{self, *}}; 358 pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}};
274} 359}
275#[prelude_import] 360#[prelude_import]
276pub use prelude::*; 361pub use prelude::*;
@@ -284,6 +369,14 @@ pub use prelude::*;
284 self.find_enum("core:option:Option") 369 self.find_enum("core:option:Option")
285 } 370 }
286 371
372 pub fn core_iter_Iterator(&self) -> Option<Trait> {
373 self.find_trait("core:iter:traits:iterator:Iterator")
374 }
375
376 pub fn core_iter(&self) -> Option<Module> {
377 self.find_module("core:iter")
378 }
379
287 fn find_trait(&self, path: &str) -> Option<Trait> { 380 fn find_trait(&self, path: &str) -> Option<Trait> {
288 match self.find_def(path)? { 381 match self.find_def(path)? {
289 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), 382 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
@@ -298,23 +391,33 @@ pub use prelude::*;
298 } 391 }
299 } 392 }
300 393
394 fn find_module(&self, path: &str) -> Option<Module> {
395 match self.find_def(path)? {
396 hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
397 _ => None,
398 }
399 }
400
301 fn find_def(&self, path: &str) -> Option<ScopeDef> { 401 fn find_def(&self, path: &str) -> Option<ScopeDef> {
302 let db = self.0.db; 402 let db = self.0.db;
303 let mut path = path.split(':'); 403 let mut path = path.split(':');
304 let trait_ = path.next_back()?; 404 let trait_ = path.next_back()?;
305 let std_crate = path.next()?; 405 let std_crate = path.next()?;
306 let std_crate = self 406 let std_crate = if self
307 .1 407 .1
308 .dependencies(db) 408 .declaration_name(db)
309 .into_iter() 409 .map(|name| name.to_string() == std_crate)
310 .find(|dep| &dep.name.to_string() == std_crate)? 410 .unwrap_or(false)
311 .krate; 411 {
312 412 self.1
413 } else {
414 self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
415 };
313 let mut module = std_crate.root_module(db); 416 let mut module = std_crate.root_module(db);
314 for segment in path { 417 for segment in path {
315 module = module.children(db).find_map(|child| { 418 module = module.children(db).find_map(|child| {
316 let name = child.name(db)?; 419 let name = child.name(db)?;
317 if &name.to_string() == segment { 420 if name.to_string() == segment {
318 Some(child) 421 Some(child)
319 } else { 422 } else {
320 None 423 None
@@ -322,7 +425,7 @@ pub use prelude::*;
322 })?; 425 })?;
323 } 426 }
324 let def = 427 let def =
325 module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; 428 module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
326 Some(def) 429 Some(def)
327 } 430 }
328} 431}