aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/path
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-05-26 00:01:58 +0100
committerJonas Schievink <[email protected]>2021-05-26 00:01:58 +0100
commitb52df9187730abbcd9cbb132f7d184c74b9a3b7f (patch)
tree06cf9ab8dcd938db5390b7da40f7e9a6db262d0d /crates/hir_def/src/path
parent5587d0a3e3599063a8993e9a44a7628abbabae8b (diff)
Stop expanding UseTrees during ItemTree lowering
Diffstat (limited to 'crates/hir_def/src/path')
-rw-r--r--crates/hir_def/src/path/lower.rs2
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs78
2 files changed, 20 insertions, 60 deletions
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 54ede7393..f6220aa92 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -15,7 +15,7 @@ use crate::{
15 type_ref::{LifetimeRef, TypeBound, TypeRef}, 15 type_ref::{LifetimeRef, TypeBound, TypeRef},
16}; 16};
17 17
18pub(super) use lower_use::lower_use_tree; 18pub(super) use lower_use::convert_path;
19 19
20/// Converts an `ast::Path` to `Path`. Works with use trees. 20/// Converts an `ast::Path` to `Path`. Works with use trees.
21/// It correctly handles `$crate` based path from macro call. 21/// It correctly handles `$crate` based path from macro call.
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs
index ee80e3df3..0ee406f63 100644
--- a/crates/hir_def/src/path/lower/lower_use.rs
+++ b/crates/hir_def/src/path/lower/lower_use.rs
@@ -4,68 +4,15 @@
4use std::iter; 4use std::iter;
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{hygiene::Hygiene, name::AsName}; 7use hir_expand::hygiene::Hygiene;
8use syntax::ast::{self, NameOwner}; 8use syntax::{ast, AstNode};
9 9
10use crate::{ 10use crate::{
11 db::DefDatabase, 11 db::DefDatabase,
12 path::{ImportAlias, ModPath, PathKind}, 12 path::{ModPath, PathKind},
13}; 13};
14 14
15pub(crate) fn lower_use_tree( 15pub(crate) fn convert_path(
16 db: &dyn DefDatabase,
17 prefix: Option<ModPath>,
18 tree: ast::UseTree,
19 hygiene: &Hygiene,
20 cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<ImportAlias>),
21) {
22 if let Some(use_tree_list) = tree.use_tree_list() {
23 let prefix = match tree.path() {
24 // E.g. use something::{{{inner}}};
25 None => prefix,
26 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
27 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
28 Some(path) => match convert_path(db, prefix, path, hygiene) {
29 Some(it) => Some(it),
30 None => return, // FIXME: report errors somewhere
31 },
32 };
33 for child_tree in use_tree_list.use_trees() {
34 lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb);
35 }
36 } else {
37 let alias = tree.rename().map(|a| {
38 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
39 });
40 let is_glob = tree.star_token().is_some();
41 if let Some(ast_path) = tree.path() {
42 // Handle self in a path.
43 // E.g. `use something::{self, <...>}`
44 if ast_path.qualifier().is_none() {
45 if let Some(segment) = ast_path.segment() {
46 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
47 if let Some(prefix) = prefix {
48 cb(prefix, &tree, false, alias);
49 return;
50 }
51 }
52 }
53 }
54 if let Some(path) = convert_path(db, prefix, ast_path, hygiene) {
55 cb(path, &tree, is_glob, alias)
56 }
57 // FIXME: report errors somewhere
58 // We get here if we do
59 } else if is_glob {
60 cov_mark::hit!(glob_enum_group);
61 if let Some(prefix) = prefix {
62 cb(prefix, &tree, is_glob, None)
63 }
64 }
65 }
66}
67
68fn convert_path(
69 db: &dyn DefDatabase, 16 db: &dyn DefDatabase,
70 prefix: Option<ModPath>, 17 prefix: Option<ModPath>,
71 path: ast::Path, 18 path: ast::Path,
@@ -78,7 +25,7 @@ fn convert_path(
78 }; 25 };
79 26
80 let segment = path.segment()?; 27 let segment = path.segment()?;
81 let res = match segment.kind()? { 28 let mut mod_path = match segment.kind()? {
82 ast::PathSegmentKind::Name(name_ref) => { 29 ast::PathSegmentKind::Name(name_ref) => {
83 match hygiene.name_ref_to_name(db.upcast(), name_ref) { 30 match hygiene.name_ref_to_name(db.upcast(), name_ref) {
84 Either::Left(name) => { 31 Either::Left(name) => {
@@ -125,5 +72,18 @@ fn convert_path(
125 return None; 72 return None;
126 } 73 }
127 }; 74 };
128 Some(res) 75
76 // handle local_inner_macros :
77 // Basically, even in rustc it is quite hacky:
78 // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
79 // We follow what it did anyway :)
80 if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain {
81 if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
82 if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) {
83 mod_path.kind = PathKind::DollarCrate(crate_id);
84 }
85 }
86 }
87
88 Some(mod_path)
129} 89}