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