aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand')
-rw-r--r--crates/hir_expand/src/hygiene.rs151
-rw-r--r--crates/hir_expand/src/lib.rs11
2 files changed, 32 insertions, 130 deletions
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 6042e15b2..7ab0a5e52 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -2,94 +2,30 @@
2//! 2//!
3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at 3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
4//! this moment, this is horribly incomplete and handles only `$crate`. 4//! this moment, this is horribly incomplete and handles only `$crate`.
5use std::sync::Arc;
6
7use arena::{Arena, Idx};
8use base_db::CrateId; 5use base_db::CrateId;
9use either::Either; 6use either::Either;
10use mbe::Origin; 7use syntax::ast;
11use syntax::{ast, AstNode};
12 8
13use crate::{ 9use crate::{
14 db::AstDatabase, 10 db::AstDatabase,
15 name::{AsName, Name}, 11 name::{AsName, Name},
16 ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, 12 HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind,
17}; 13};
18 14
19#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
20pub struct Hygiene { 16pub struct Hygiene {
21 frames: Option<Arc<HygieneFrames>>, 17 // This is what `$crate` expands to
22} 18 def_crate: Option<CrateId>,
23
24impl Hygiene {
25 pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
26 Hygiene { frames: Some(Arc::new(HygieneFrames::new(db, file_id.clone()))) }
27 }
28
29 pub fn new_unhygienic() -> Hygiene {
30 Hygiene { frames: None }
31 }
32
33 // FIXME: this should just return name
34 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
35 if let Some(frames) = &self.frames {
36 if name_ref.text() == "$crate" {
37 if let Some(krate) = frames.root_crate(&name_ref) {
38 return Either::Right(krate);
39 }
40 }
41 }
42
43 Either::Left(name_ref.as_name())
44 }
45
46 pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> {
47 let frames = self.frames.as_ref()?;
48
49 let mut token = path.syntax().first_token()?;
50 let mut current = frames.first();
51
52 while let Some((frame, data)) =
53 current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?)))
54 {
55 let (mapped, origin) = data;
56 if origin == Origin::Def {
57 return if frame.local_inner { frame.krate } else { None };
58 }
59 current = Some(&frames.0[frame.call_site?]);
60 token = mapped.value;
61 }
62 None
63 }
64}
65
66#[derive(Default, Debug)]
67struct HygieneFrames(Arena<HygieneFrame>);
68
69#[derive(Clone, Debug)]
70struct HygieneFrame {
71 expansion: Option<ExpansionInfo>,
72 19
73 // Indicate this is a local inner macro 20 // Indicate this is a local inner macro
74 local_inner: bool, 21 local_inner: bool,
75 krate: Option<CrateId>,
76
77 call_site: Option<Idx<HygieneFrame>>,
78 def_site: Option<Idx<HygieneFrame>>,
79} 22}
80 23
81impl HygieneFrames { 24impl Hygiene {
82 fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { 25 pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
83 let mut frames = HygieneFrames::default(); 26 let (def_crate, local_inner) = match file_id.0 {
84 frames.add(db, file_id);
85 frames
86 }
87
88 fn add(&mut self, db: &dyn AstDatabase, file_id: HirFileId) -> Option<Idx<HygieneFrame>> {
89 let (krate, local_inner) = match file_id.0 {
90 HirFileIdRepr::FileId(_) => (None, false), 27 HirFileIdRepr::FileId(_) => (None, false),
91 HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { 28 HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id {
92 MacroCallId::EagerMacro(_id) => (None, false),
93 MacroCallId::LazyMacro(id) => { 29 MacroCallId::LazyMacro(id) => {
94 let loc = db.lookup_intern_macro(id); 30 let loc = db.lookup_intern_macro(id);
95 match loc.def.kind { 31 match loc.def.kind {
@@ -100,68 +36,31 @@ impl HygieneFrames {
100 MacroDefKind::ProcMacro(_) => (None, false), 36 MacroDefKind::ProcMacro(_) => (None, false),
101 } 37 }
102 } 38 }
39 MacroCallId::EagerMacro(_id) => (None, false),
103 }, 40 },
104 }; 41 };
105 42 Hygiene { def_crate, local_inner }
106 let expansion = file_id.expansion_info(db);
107 let expansion = match expansion {
108 None => {
109 return Some(self.0.alloc(HygieneFrame {
110 expansion: None,
111 local_inner,
112 krate,
113 call_site: None,
114 def_site: None,
115 }));
116 }
117 Some(it) => it,
118 };
119
120 let def_site = expansion.def.clone();
121 let call_site = expansion.arg.file_id;
122 let idx = self.0.alloc(HygieneFrame {
123 expansion: Some(expansion),
124 local_inner,
125 krate,
126 call_site: None,
127 def_site: None,
128 });
129
130 self.0[idx].call_site = self.add(db, call_site);
131 self.0[idx].def_site = def_site.and_then(|it| self.add(db, it.file_id));
132
133 Some(idx)
134 } 43 }
135 44
136 fn first(&self) -> Option<&HygieneFrame> { 45 pub fn new_unhygienic() -> Hygiene {
137 self.0.iter().next().map(|it| it.1) 46 Hygiene { def_crate: None, local_inner: false }
138 } 47 }
139 48
140 fn root_crate(&self, name_ref: &ast::NameRef) -> Option<CrateId> { 49 // FIXME: this should just return name
141 let mut token = name_ref.syntax().first_token()?; 50 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
142 let first = self.first()?; 51 if let Some(def_crate) = self.def_crate {
143 let mut result = first.krate; 52 if name_ref.text() == "$crate" {
144 let mut current = Some(first); 53 return Either::Right(def_crate);
145 54 }
146 while let Some((frame, (mapped, origin))) =
147 current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?)))
148 {
149 result = frame.krate;
150
151 let site = match origin {
152 Origin::Def => frame.def_site,
153 Origin::Call => frame.call_site,
154 };
155
156 let site = match site {
157 None => break,
158 Some(it) => it,
159 };
160
161 current = Some(&self.0[site]);
162 token = mapped.value;
163 } 55 }
56 Either::Left(name_ref.as_name())
57 }
164 58
165 result 59 pub fn local_inner_macros(&self) -> Option<CrateId> {
60 if self.local_inner {
61 self.def_crate
62 } else {
63 None
64 }
166 } 65 }
167} 66}
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 5b6734a5f..3fa1b1d77 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -340,8 +340,11 @@ impl ExpansionInfo {
340 Some(self.expanded.with_value(token)) 340 Some(self.expanded.with_value(token))
341 } 341 }
342 342
343 pub fn map_token_up(&self, token: &SyntaxToken) -> Option<(InFile<SyntaxToken>, Origin)> { 343 pub fn map_token_up(
344 let token_id = self.exp_map.token_by_range(token.text_range())?; 344 &self,
345 token: InFile<&SyntaxToken>,
346 ) -> Option<(InFile<SyntaxToken>, Origin)> {
347 let token_id = self.exp_map.token_by_range(token.value.text_range())?;
345 348
346 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 349 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
347 let (token_map, tt) = match origin { 350 let (token_map, tt) = match origin {
@@ -356,7 +359,7 @@ impl ExpansionInfo {
356 ), 359 ),
357 }; 360 };
358 361
359 let range = token_map.range_by_token(token_id)?.by_kind(token.kind())?; 362 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
360 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) 363 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
361 .into_token()?; 364 .into_token()?;
362 Some((tt.with_value(token), origin)) 365 Some((tt.with_value(token), origin))
@@ -492,7 +495,7 @@ fn ascend_call_token(
492 expansion: &ExpansionInfo, 495 expansion: &ExpansionInfo,
493 token: InFile<SyntaxToken>, 496 token: InFile<SyntaxToken>,
494) -> Option<InFile<SyntaxToken>> { 497) -> Option<InFile<SyntaxToken>> {
495 let (mapped, origin) = expansion.map_token_up(&token.value)?; 498 let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
496 if origin != Origin::Call { 499 if origin != Origin::Call {
497 return None; 500 return None;
498 } 501 }