diff options
Diffstat (limited to 'crates/ide_db/src/helpers.rs')
-rw-r--r-- | crates/ide_db/src/helpers.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs new file mode 100644 index 000000000..d988588ff --- /dev/null +++ b/crates/ide_db/src/helpers.rs | |||
@@ -0,0 +1,203 @@ | |||
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 | } | ||