aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/path.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-10-30 13:12:55 +0000
committerAleksey Kladov <[email protected]>2019-10-30 14:43:11 +0000
commit16e620c052016010b2f17070a98bdc1e7e849ab3 (patch)
treea00ec9181595cea9e340da3ead490348ff7b1666 /crates/ra_hir/src/path.rs
parentf996b6019bd2f388bd9994ea83f25487eb111560 (diff)
move raw_items to hir_def
Diffstat (limited to 'crates/ra_hir/src/path.rs')
-rw-r--r--crates/ra_hir/src/path.rs423
1 files changed, 1 insertions, 422 deletions
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index bbe536bcb..7f0ff4bfc 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -1,422 +1 @@
1//! FIXME: write short doc here pub use hir_def::path::*;
2
3use std::{iter, sync::Arc};
4
5use ra_syntax::{
6 ast::{self, NameOwner, TypeAscriptionOwner},
7 AstNode,
8};
9
10use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct Path {
14 pub kind: PathKind,
15 pub segments: Vec<PathSegment>,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct PathSegment {
20 pub name: Name,
21 pub args_and_bindings: Option<Arc<GenericArgs>>,
22}
23
24/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
25/// can (in the future) also include bindings of associated types, like in
26/// `Iterator<Item = Foo>`.
27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28pub struct GenericArgs {
29 pub args: Vec<GenericArg>,
30 /// This specifies whether the args contain a Self type as the first
31 /// element. This is the case for path segments like `<T as Trait>`, where
32 /// `T` is actually a type parameter for the path `Trait` specifying the
33 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
34 /// is left out.
35 pub has_self_type: bool,
36 /// Associated type bindings like in `Iterator<Item = T>`.
37 pub bindings: Vec<(Name, TypeRef)>,
38}
39
40/// A single generic argument.
41#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42pub enum GenericArg {
43 Type(TypeRef),
44 // or lifetime...
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub enum PathKind {
49 Plain,
50 Self_,
51 Super,
52 Crate,
53 // Absolute path
54 Abs,
55 // Type based path like `<T>::foo`
56 Type(Box<TypeRef>),
57 // `$crate` from macro expansion
58 DollarCrate(Crate),
59}
60
61impl Path {
62 /// Calls `cb` with all paths, represented by this use item.
63 pub fn expand_use_item(
64 item_src: Source<ast::UseItem>,
65 db: &impl AstDatabase,
66 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
67 ) {
68 if let Some(tree) = item_src.ast.use_tree() {
69 expand_use_tree(
70 None,
71 tree,
72 &|| item_src.file_id.macro_crate(db).map(|crate_id| Crate { crate_id }),
73 &mut cb,
74 );
75 }
76 }
77
78 pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
79 Path {
80 kind,
81 segments: segments
82 .into_iter()
83 .map(|name| PathSegment { name, args_and_bindings: None })
84 .collect(),
85 }
86 }
87
88 /// Converts an `ast::Path` to `Path`. Works with use trees.
89 /// DEPRECATED: It does not handle `$crate` from macro call.
90 pub fn from_ast(path: ast::Path) -> Option<Path> {
91 Path::parse(path, &|| None)
92 }
93
94 /// Converts an `ast::Path` to `Path`. Works with use trees.
95 /// It correctly handles `$crate` based path from macro call.
96 pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> {
97 let file_id = source.file_id;
98 Path::parse(source.ast, &|| file_id.macro_crate(db).map(|crate_id| Crate { crate_id }))
99 }
100
101 fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> {
102 let mut kind = PathKind::Plain;
103 let mut segments = Vec::new();
104 loop {
105 let segment = path.segment()?;
106
107 if segment.has_colon_colon() {
108 kind = PathKind::Abs;
109 }
110
111 match segment.kind()? {
112 ast::PathSegmentKind::Name(name) => {
113 if name.text() == "$crate" {
114 if let Some(macro_crate) = macro_crate() {
115 kind = PathKind::DollarCrate(macro_crate);
116 break;
117 }
118 }
119
120 let args = segment
121 .type_arg_list()
122 .and_then(GenericArgs::from_ast)
123 .or_else(|| {
124 GenericArgs::from_fn_like_path_ast(
125 segment.param_list(),
126 segment.ret_type(),
127 )
128 })
129 .map(Arc::new);
130 let segment = PathSegment { name: name.as_name(), args_and_bindings: args };
131 segments.push(segment);
132 }
133 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
134 assert!(path.qualifier().is_none()); // this can only occur at the first segment
135
136 let self_type = TypeRef::from_ast(type_ref?);
137
138 match trait_ref {
139 // <T>::foo
140 None => {
141 kind = PathKind::Type(Box::new(self_type));
142 }
143 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
144 Some(trait_ref) => {
145 let path = Path::parse(trait_ref.path()?, macro_crate)?;
146 kind = path.kind;
147 let mut prefix_segments = path.segments;
148 prefix_segments.reverse();
149 segments.extend(prefix_segments);
150 // Insert the type reference (T in the above example) as Self parameter for the trait
151 let mut last_segment = segments.last_mut()?;
152 if last_segment.args_and_bindings.is_none() {
153 last_segment.args_and_bindings =
154 Some(Arc::new(GenericArgs::empty()));
155 };
156 let args = last_segment.args_and_bindings.as_mut().unwrap();
157 let mut args_inner = Arc::make_mut(args);
158 args_inner.has_self_type = true;
159 args_inner.args.insert(0, GenericArg::Type(self_type));
160 }
161 }
162 }
163 ast::PathSegmentKind::CrateKw => {
164 kind = PathKind::Crate;
165 break;
166 }
167 ast::PathSegmentKind::SelfKw => {
168 kind = PathKind::Self_;
169 break;
170 }
171 ast::PathSegmentKind::SuperKw => {
172 kind = PathKind::Super;
173 break;
174 }
175 }
176 path = match qualifier(&path) {
177 Some(it) => it,
178 None => break,
179 };
180 }
181 segments.reverse();
182 return Some(Path { kind, segments });
183
184 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
185 if let Some(q) = path.qualifier() {
186 return Some(q);
187 }
188 // FIXME: this bottom up traversal is not too precise.
189 // Should we handle do a top-down analysis, recording results?
190 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
191 let use_tree = use_tree_list.parent_use_tree();
192 use_tree.path()
193 }
194 }
195
196 /// Converts an `ast::NameRef` into a single-identifier `Path`.
197 pub fn from_name_ref(name_ref: &ast::NameRef) -> Path {
198 name_ref.as_name().into()
199 }
200
201 /// `true` is this path is a single identifier, like `foo`
202 pub fn is_ident(&self) -> bool {
203 self.kind == PathKind::Plain && self.segments.len() == 1
204 }
205
206 /// `true` if this path is just a standalone `self`
207 pub fn is_self(&self) -> bool {
208 self.kind == PathKind::Self_ && self.segments.is_empty()
209 }
210
211 /// If this path is a single identifier, like `foo`, return its name.
212 pub fn as_ident(&self) -> Option<&Name> {
213 if self.kind != PathKind::Plain || self.segments.len() > 1 {
214 return None;
215 }
216 self.segments.first().map(|s| &s.name)
217 }
218
219 pub fn expand_macro_expr(&self) -> Option<Name> {
220 self.as_ident().and_then(|name| Some(name.clone()))
221 }
222
223 pub fn is_type_relative(&self) -> bool {
224 match self.kind {
225 PathKind::Type(_) => true,
226 _ => false,
227 }
228 }
229}
230
231impl GenericArgs {
232 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
233 let mut args = Vec::new();
234 for type_arg in node.type_args() {
235 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
236 args.push(GenericArg::Type(type_ref));
237 }
238 // lifetimes ignored for now
239 let mut bindings = Vec::new();
240 for assoc_type_arg in node.assoc_type_args() {
241 if let Some(name_ref) = assoc_type_arg.name_ref() {
242 let name = name_ref.as_name();
243 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
244 bindings.push((name, type_ref));
245 }
246 }
247 if args.is_empty() && bindings.is_empty() {
248 None
249 } else {
250 Some(GenericArgs { args, has_self_type: false, bindings })
251 }
252 }
253
254 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
255 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
256 pub(crate) fn from_fn_like_path_ast(
257 params: Option<ast::ParamList>,
258 ret_type: Option<ast::RetType>,
259 ) -> Option<GenericArgs> {
260 let mut args = Vec::new();
261 let mut bindings = Vec::new();
262 if let Some(params) = params {
263 let mut param_types = Vec::new();
264 for param in params.params() {
265 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
266 param_types.push(type_ref);
267 }
268 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
269 args.push(arg);
270 }
271 if let Some(ret_type) = ret_type {
272 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
273 bindings.push((name::OUTPUT_TYPE, type_ref))
274 }
275 if args.is_empty() && bindings.is_empty() {
276 None
277 } else {
278 Some(GenericArgs { args, has_self_type: false, bindings })
279 }
280 }
281
282 pub(crate) fn empty() -> GenericArgs {
283 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
284 }
285}
286
287impl From<Name> for Path {
288 fn from(name: Name) -> Path {
289 Path::from_simple_segments(PathKind::Plain, iter::once(name))
290 }
291}
292
293fn expand_use_tree(
294 prefix: Option<Path>,
295 tree: ast::UseTree,
296 macro_crate: &impl Fn() -> Option<Crate>,
297 cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
298) {
299 if let Some(use_tree_list) = tree.use_tree_list() {
300 let prefix = match tree.path() {
301 // E.g. use something::{{{inner}}};
302 None => prefix,
303 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
304 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
305 Some(path) => match convert_path(prefix, path, macro_crate) {
306 Some(it) => Some(it),
307 None => return, // FIXME: report errors somewhere
308 },
309 };
310 for child_tree in use_tree_list.use_trees() {
311 expand_use_tree(prefix.clone(), child_tree, macro_crate, cb);
312 }
313 } else {
314 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
315 if let Some(ast_path) = tree.path() {
316 // Handle self in a path.
317 // E.g. `use something::{self, <...>}`
318 if ast_path.qualifier().is_none() {
319 if let Some(segment) = ast_path.segment() {
320 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
321 if let Some(prefix) = prefix {
322 cb(prefix, &tree, false, alias);
323 return;
324 }
325 }
326 }
327 }
328 if let Some(path) = convert_path(prefix, ast_path, macro_crate) {
329 let is_glob = tree.has_star();
330 cb(path, &tree, is_glob, alias)
331 }
332 // FIXME: report errors somewhere
333 // We get here if we do
334 }
335 }
336}
337
338fn convert_path(
339 prefix: Option<Path>,
340 path: ast::Path,
341 macro_crate: &impl Fn() -> Option<Crate>,
342) -> Option<Path> {
343 let prefix = if let Some(qual) = path.qualifier() {
344 Some(convert_path(prefix, qual, macro_crate)?)
345 } else {
346 prefix
347 };
348
349 let segment = path.segment()?;
350 let res = match segment.kind()? {
351 ast::PathSegmentKind::Name(name) => {
352 if name.text() == "$crate" {
353 if let Some(krate) = macro_crate() {
354 return Some(Path::from_simple_segments(
355 PathKind::DollarCrate(krate),
356 iter::empty(),
357 ));
358 }
359 }
360
361 // no type args in use
362 let mut res = prefix
363 .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
364 res.segments.push(PathSegment {
365 name: name.as_name(),
366 args_and_bindings: None, // no type args in use
367 });
368 res
369 }
370 ast::PathSegmentKind::CrateKw => {
371 if prefix.is_some() {
372 return None;
373 }
374 Path::from_simple_segments(PathKind::Crate, iter::empty())
375 }
376 ast::PathSegmentKind::SelfKw => {
377 if prefix.is_some() {
378 return None;
379 }
380 Path::from_simple_segments(PathKind::Self_, iter::empty())
381 }
382 ast::PathSegmentKind::SuperKw => {
383 if prefix.is_some() {
384 return None;
385 }
386 Path::from_simple_segments(PathKind::Super, iter::empty())
387 }
388 ast::PathSegmentKind::Type { .. } => {
389 // not allowed in imports
390 return None;
391 }
392 };
393 Some(res)
394}
395
396pub mod known {
397 use super::{Path, PathKind};
398 use crate::name;
399
400 pub fn std_iter_into_iterator() -> Path {
401 Path::from_simple_segments(
402 PathKind::Abs,
403 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
404 )
405 }
406
407 pub fn std_ops_try() -> Path {
408 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
409 }
410
411 pub fn std_result_result() -> Path {
412 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
413 }
414
415 pub fn std_future_future() -> Path {
416 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
417 }
418
419 pub fn std_boxed_box() -> Path {
420 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
421 }
422}