]> git.lizzy.rs Git - rust.git/blob - crates/ide_db/src/helpers.rs
d988588ff3eb9d979631e5a5682371d61266dafe
[rust.git] / crates / ide_db / src / helpers.rs
1 //! A module with ide helpers for high-level ide features.
2 use crate::RootDatabase;
3 use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
4 use syntax::ast::{self, make};
5
6 pub mod insert_use;
7
8 /// Converts the mod path struct into its ast representation.
9 pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
10     let _p = profile::span("mod_path_to_ast");
11
12     let mut segments = Vec::new();
13     let mut is_abs = false;
14     match path.kind {
15         hir::PathKind::Plain => {}
16         hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
17         hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
18         hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
19             segments.push(make::path_segment_crate())
20         }
21         hir::PathKind::Abs => is_abs = true,
22     }
23
24     segments.extend(
25         path.segments
26             .iter()
27             .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
28     );
29     make::path_from_segments(segments, is_abs)
30 }
31
32 /// Helps with finding well-know things inside the standard library. This is
33 /// somewhat similar to the known paths infra inside hir, but it different; We
34 /// want to make sure that IDE specific paths don't become interesting inside
35 /// the compiler itself as well.
36 pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
37
38 #[allow(non_snake_case)]
39 impl FamousDefs<'_, '_> {
40     pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
41 pub mod convert {
42     pub trait From<T> {
43         fn from(t: T) -> Self;
44     }
45 }
46
47 pub mod default {
48     pub trait Default {
49        fn default() -> Self;
50     }
51 }
52
53 pub mod iter {
54     pub use self::traits::{collect::IntoIterator, iterator::Iterator};
55     mod traits {
56         pub(crate) mod iterator {
57             use crate::option::Option;
58             pub trait Iterator {
59                 type Item;
60                 fn next(&mut self) -> Option<Self::Item>;
61                 fn by_ref(&mut self) -> &mut Self {
62                     self
63                 }
64                 fn take(self, n: usize) -> crate::iter::Take<Self> {
65                     crate::iter::Take { inner: self }
66                 }
67             }
68
69             impl<I: Iterator> Iterator for &mut I {
70                 type Item = I::Item;
71                 fn next(&mut self) -> Option<I::Item> {
72                     (**self).next()
73                 }
74             }
75         }
76         pub(crate) mod collect {
77             pub trait IntoIterator {
78                 type Item;
79             }
80         }
81     }
82
83     pub use self::sources::*;
84     pub(crate) mod sources {
85         use super::Iterator;
86         use crate::option::Option::{self, *};
87         pub struct Repeat<A> {
88             element: A,
89         }
90
91         pub fn repeat<T>(elt: T) -> Repeat<T> {
92             Repeat { element: elt }
93         }
94
95         impl<A> Iterator for Repeat<A> {
96             type Item = A;
97
98             fn next(&mut self) -> Option<A> {
99                 None
100             }
101         }
102     }
103
104     pub use self::adapters::*;
105     pub(crate) mod adapters {
106         use super::Iterator;
107         use crate::option::Option::{self, *};
108         pub struct Take<I> { pub(crate) inner: I }
109         impl<I> Iterator for Take<I> where I: Iterator {
110             type Item = <I as Iterator>::Item;
111             fn next(&mut self) -> Option<<I as Iterator>::Item> {
112                 None
113             }
114         }
115     }
116 }
117
118 pub mod option {
119     pub enum Option<T> { None, Some(T)}
120 }
121
122 pub mod prelude {
123     pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
124 }
125 #[prelude_import]
126 pub use prelude::*;
127 "#;
128
129     pub fn core(&self) -> Option<Crate> {
130         self.find_crate("core")
131     }
132
133     pub fn core_convert_From(&self) -> Option<Trait> {
134         self.find_trait("core:convert:From")
135     }
136
137     pub fn core_option_Option(&self) -> Option<Enum> {
138         self.find_enum("core:option:Option")
139     }
140
141     pub fn core_default_Default(&self) -> Option<Trait> {
142         self.find_trait("core:default:Default")
143     }
144
145     pub fn core_iter_Iterator(&self) -> Option<Trait> {
146         self.find_trait("core:iter:traits:iterator:Iterator")
147     }
148
149     pub fn core_iter(&self) -> Option<Module> {
150         self.find_module("core:iter")
151     }
152
153     fn find_trait(&self, path: &str) -> Option<Trait> {
154         match self.find_def(path)? {
155             hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
156             _ => None,
157         }
158     }
159
160     fn find_enum(&self, path: &str) -> Option<Enum> {
161         match self.find_def(path)? {
162             hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
163             _ => None,
164         }
165     }
166
167     fn find_module(&self, path: &str) -> Option<Module> {
168         match self.find_def(path)? {
169             hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
170             _ => None,
171         }
172     }
173
174     fn find_crate(&self, name: &str) -> Option<Crate> {
175         let krate = self.1?;
176         let db = self.0.db;
177         let res =
178             krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
179         Some(res)
180     }
181
182     fn find_def(&self, path: &str) -> Option<ScopeDef> {
183         let db = self.0.db;
184         let mut path = path.split(':');
185         let trait_ = path.next_back()?;
186         let std_crate = path.next()?;
187         let std_crate = self.find_crate(std_crate)?;
188         let mut module = std_crate.root_module(db);
189         for segment in path {
190             module = module.children(db).find_map(|child| {
191                 let name = child.name(db)?;
192                 if name.to_string() == segment {
193                     Some(child)
194                 } else {
195                     None
196                 }
197             })?;
198         }
199         let def =
200             module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
201         Some(def)
202     }
203 }