diff options
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 110 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path/lower_use.rs | 115 |
2 files changed, 119 insertions, 106 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index e547b2f03..ec9d13e82 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. | 1 | //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. |
2 | mod lower_use; | ||
2 | 3 | ||
3 | use std::{iter, sync::Arc}; | 4 | use std::{iter, sync::Arc}; |
4 | 5 | ||
@@ -9,7 +10,7 @@ use hir_expand::{ | |||
9 | }; | 10 | }; |
10 | use ra_db::CrateId; | 11 | use ra_db::CrateId; |
11 | use ra_syntax::{ | 12 | use ra_syntax::{ |
12 | ast::{self, NameOwner, TypeAscriptionOwner}, | 13 | ast::{self, TypeAscriptionOwner}, |
13 | AstNode, | 14 | AstNode, |
14 | }; | 15 | }; |
15 | 16 | ||
@@ -28,8 +29,7 @@ pub struct PathSegment { | |||
28 | } | 29 | } |
29 | 30 | ||
30 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This | 31 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This |
31 | /// can (in the future) also include bindings of associated types, like in | 32 | /// also includes bindings of associated types, like in `Iterator<Item = Foo>`. |
32 | /// `Iterator<Item = Foo>`. | ||
33 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 33 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
34 | pub struct GenericArgs { | 34 | pub struct GenericArgs { |
35 | pub args: Vec<GenericArg>, | 35 | pub args: Vec<GenericArg>, |
@@ -72,7 +72,7 @@ impl Path { | |||
72 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | 72 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), |
73 | ) { | 73 | ) { |
74 | if let Some(tree) = item_src.value.use_tree() { | 74 | if let Some(tree) = item_src.value.use_tree() { |
75 | expand_use_tree(None, tree, hygiene, &mut cb); | 75 | lower_use::lower_use_tree(None, tree, hygiene, &mut cb); |
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
@@ -296,108 +296,6 @@ impl From<Name> for Path { | |||
296 | } | 296 | } |
297 | } | 297 | } |
298 | 298 | ||
299 | fn expand_use_tree( | ||
300 | prefix: Option<Path>, | ||
301 | tree: ast::UseTree, | ||
302 | hygiene: &Hygiene, | ||
303 | cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>), | ||
304 | ) { | ||
305 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
306 | let prefix = match tree.path() { | ||
307 | // E.g. use something::{{{inner}}}; | ||
308 | None => prefix, | ||
309 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
310 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
311 | Some(path) => match convert_path(prefix, path, hygiene) { | ||
312 | Some(it) => Some(it), | ||
313 | None => return, // FIXME: report errors somewhere | ||
314 | }, | ||
315 | }; | ||
316 | for child_tree in use_tree_list.use_trees() { | ||
317 | expand_use_tree(prefix.clone(), child_tree, hygiene, cb); | ||
318 | } | ||
319 | } else { | ||
320 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); | ||
321 | if let Some(ast_path) = tree.path() { | ||
322 | // Handle self in a path. | ||
323 | // E.g. `use something::{self, <...>}` | ||
324 | if ast_path.qualifier().is_none() { | ||
325 | if let Some(segment) = ast_path.segment() { | ||
326 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
327 | if let Some(prefix) = prefix { | ||
328 | cb(prefix, &tree, false, alias); | ||
329 | return; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | if let Some(path) = convert_path(prefix, ast_path, hygiene) { | ||
335 | let is_glob = tree.has_star(); | ||
336 | cb(path, &tree, is_glob, alias) | ||
337 | } | ||
338 | // FIXME: report errors somewhere | ||
339 | // We get here if we do | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | ||
345 | let prefix = if let Some(qual) = path.qualifier() { | ||
346 | Some(convert_path(prefix, qual, hygiene)?) | ||
347 | } else { | ||
348 | prefix | ||
349 | }; | ||
350 | |||
351 | let segment = path.segment()?; | ||
352 | let res = match segment.kind()? { | ||
353 | ast::PathSegmentKind::Name(name_ref) => { | ||
354 | match hygiene.name_ref_to_name(name_ref) { | ||
355 | Either::Left(name) => { | ||
356 | // no type args in use | ||
357 | let mut res = prefix.unwrap_or_else(|| Path { | ||
358 | kind: PathKind::Plain, | ||
359 | segments: Vec::with_capacity(1), | ||
360 | }); | ||
361 | res.segments.push(PathSegment { | ||
362 | name, | ||
363 | args_and_bindings: None, // no type args in use | ||
364 | }); | ||
365 | res | ||
366 | } | ||
367 | Either::Right(crate_id) => { | ||
368 | return Some(Path::from_simple_segments( | ||
369 | PathKind::DollarCrate(crate_id), | ||
370 | iter::empty(), | ||
371 | )) | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | ast::PathSegmentKind::CrateKw => { | ||
376 | if prefix.is_some() { | ||
377 | return None; | ||
378 | } | ||
379 | Path::from_simple_segments(PathKind::Crate, iter::empty()) | ||
380 | } | ||
381 | ast::PathSegmentKind::SelfKw => { | ||
382 | if prefix.is_some() { | ||
383 | return None; | ||
384 | } | ||
385 | Path::from_simple_segments(PathKind::Self_, iter::empty()) | ||
386 | } | ||
387 | ast::PathSegmentKind::SuperKw => { | ||
388 | if prefix.is_some() { | ||
389 | return None; | ||
390 | } | ||
391 | Path::from_simple_segments(PathKind::Super, iter::empty()) | ||
392 | } | ||
393 | ast::PathSegmentKind::Type { .. } => { | ||
394 | // not allowed in imports | ||
395 | return None; | ||
396 | } | ||
397 | }; | ||
398 | Some(res) | ||
399 | } | ||
400 | |||
401 | pub mod known { | 299 | pub mod known { |
402 | use hir_expand::name; | 300 | use hir_expand::name; |
403 | 301 | ||
diff --git a/crates/ra_hir_def/src/path/lower_use.rs b/crates/ra_hir_def/src/path/lower_use.rs new file mode 100644 index 000000000..e2e1f716d --- /dev/null +++ b/crates/ra_hir_def/src/path/lower_use.rs | |||
@@ -0,0 +1,115 @@ | |||
1 | //! Lowers a single complex use like `use foo::{bar, baz};` into a list of paths like | ||
2 | //! `foo::bar`, `foo::baz`; | ||
3 | |||
4 | use std::iter; | ||
5 | |||
6 | use either::Either; | ||
7 | use hir_expand::{ | ||
8 | hygiene::Hygiene, | ||
9 | name::{AsName, Name}, | ||
10 | }; | ||
11 | use ra_syntax::ast::{self, NameOwner}; | ||
12 | |||
13 | use crate::path::{Path, PathKind, PathSegment}; | ||
14 | |||
15 | pub(crate) fn lower_use_tree( | ||
16 | prefix: Option<Path>, | ||
17 | tree: ast::UseTree, | ||
18 | hygiene: &Hygiene, | ||
19 | cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>), | ||
20 | ) { | ||
21 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
22 | let prefix = match tree.path() { | ||
23 | // E.g. use something::{{{inner}}}; | ||
24 | None => prefix, | ||
25 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
26 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
27 | Some(path) => match convert_path(prefix, path, hygiene) { | ||
28 | Some(it) => Some(it), | ||
29 | None => return, // FIXME: report errors somewhere | ||
30 | }, | ||
31 | }; | ||
32 | for child_tree in use_tree_list.use_trees() { | ||
33 | lower_use_tree(prefix.clone(), child_tree, hygiene, cb); | ||
34 | } | ||
35 | } else { | ||
36 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); | ||
37 | if let Some(ast_path) = tree.path() { | ||
38 | // Handle self in a path. | ||
39 | // E.g. `use something::{self, <...>}` | ||
40 | if ast_path.qualifier().is_none() { | ||
41 | if let Some(segment) = ast_path.segment() { | ||
42 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
43 | if let Some(prefix) = prefix { | ||
44 | cb(prefix, &tree, false, alias); | ||
45 | return; | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | if let Some(path) = convert_path(prefix, ast_path, hygiene) { | ||
51 | let is_glob = tree.has_star(); | ||
52 | cb(path, &tree, is_glob, alias) | ||
53 | } | ||
54 | // FIXME: report errors somewhere | ||
55 | // We get here if we do | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | ||
61 | let prefix = if let Some(qual) = path.qualifier() { | ||
62 | Some(convert_path(prefix, qual, hygiene)?) | ||
63 | } else { | ||
64 | prefix | ||
65 | }; | ||
66 | |||
67 | let segment = path.segment()?; | ||
68 | let res = match segment.kind()? { | ||
69 | ast::PathSegmentKind::Name(name_ref) => { | ||
70 | match hygiene.name_ref_to_name(name_ref) { | ||
71 | Either::Left(name) => { | ||
72 | // no type args in use | ||
73 | let mut res = prefix.unwrap_or_else(|| Path { | ||
74 | kind: PathKind::Plain, | ||
75 | segments: Vec::with_capacity(1), | ||
76 | }); | ||
77 | res.segments.push(PathSegment { | ||
78 | name, | ||
79 | args_and_bindings: None, // no type args in use | ||
80 | }); | ||
81 | res | ||
82 | } | ||
83 | Either::Right(crate_id) => { | ||
84 | return Some(Path::from_simple_segments( | ||
85 | PathKind::DollarCrate(crate_id), | ||
86 | iter::empty(), | ||
87 | )) | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | ast::PathSegmentKind::CrateKw => { | ||
92 | if prefix.is_some() { | ||
93 | return None; | ||
94 | } | ||
95 | Path::from_simple_segments(PathKind::Crate, iter::empty()) | ||
96 | } | ||
97 | ast::PathSegmentKind::SelfKw => { | ||
98 | if prefix.is_some() { | ||
99 | return None; | ||
100 | } | ||
101 | Path::from_simple_segments(PathKind::Self_, iter::empty()) | ||
102 | } | ||
103 | ast::PathSegmentKind::SuperKw => { | ||
104 | if prefix.is_some() { | ||
105 | return None; | ||
106 | } | ||
107 | Path::from_simple_segments(PathKind::Super, iter::empty()) | ||
108 | } | ||
109 | ast::PathSegmentKind::Type { .. } => { | ||
110 | // not allowed in imports | ||
111 | return None; | ||
112 | } | ||
113 | }; | ||
114 | Some(res) | ||
115 | } | ||