aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src/hygiene.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src/hygiene.rs')
-rw-r--r--crates/hir_expand/src/hygiene.rs57
1 files changed, 35 insertions, 22 deletions
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index ed61ebca3..aca69e35a 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -32,10 +32,14 @@ impl Hygiene {
32 } 32 }
33 33
34 // FIXME: this should just return name 34 // FIXME: this should just return name
35 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { 35 pub fn name_ref_to_name(
36 &self,
37 db: &dyn AstDatabase,
38 name_ref: ast::NameRef,
39 ) -> Either<Name, CrateId> {
36 if let Some(frames) = &self.frames { 40 if let Some(frames) = &self.frames {
37 if name_ref.text() == "$crate" { 41 if name_ref.text() == "$crate" {
38 if let Some(krate) = frames.root_crate(name_ref.syntax()) { 42 if let Some(krate) = frames.root_crate(db, name_ref.syntax()) {
39 return Either::Right(krate); 43 return Either::Right(krate);
40 } 44 }
41 } 45 }
@@ -44,15 +48,19 @@ impl Hygiene {
44 Either::Left(name_ref.as_name()) 48 Either::Left(name_ref.as_name())
45 } 49 }
46 50
47 pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { 51 pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> {
48 let mut token = path.syntax().first_token()?.text_range(); 52 let mut token = path.syntax().first_token()?.text_range();
49 let frames = self.frames.as_ref()?; 53 let frames = self.frames.as_ref()?;
50 let mut current = frames.0.clone(); 54 let mut current = frames.0.clone();
51 55
52 loop { 56 loop {
53 let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?; 57 let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?;
54 if origin == Origin::Def { 58 if origin == Origin::Def {
55 return if current.local_inner { frames.root_crate(path.syntax()) } else { None }; 59 return if current.local_inner {
60 frames.root_crate(db, path.syntax())
61 } else {
62 None
63 };
56 } 64 }
57 current = current.call_site.as_ref()?.clone(); 65 current = current.call_site.as_ref()?.clone();
58 token = mapped.value; 66 token = mapped.value;
@@ -82,13 +90,13 @@ impl HygieneFrames {
82 HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) 90 HygieneFrames(Arc::new(HygieneFrame::new(db, file_id)))
83 } 91 }
84 92
85 fn root_crate(&self, node: &SyntaxNode) -> Option<CrateId> { 93 fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> {
86 let mut token = node.first_token()?.text_range(); 94 let mut token = node.first_token()?.text_range();
87 let mut result = self.0.krate; 95 let mut result = self.0.krate;
88 let mut current = self.0.clone(); 96 let mut current = self.0.clone();
89 97
90 while let Some((mapped, origin)) = 98 while let Some((mapped, origin)) =
91 current.expansion.as_ref().and_then(|it| it.map_ident_up(token)) 99 current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token))
92 { 100 {
93 result = current.krate; 101 result = current.krate;
94 102
@@ -112,7 +120,7 @@ impl HygieneFrames {
112 120
113#[derive(Debug, Clone, PartialEq, Eq)] 121#[derive(Debug, Clone, PartialEq, Eq)]
114struct HygieneInfo { 122struct HygieneInfo {
115 arg_start: InFile<TextSize>, 123 file: MacroFile,
116 /// The `macro_rules!` arguments. 124 /// The `macro_rules!` arguments.
117 def_start: Option<InFile<TextSize>>, 125 def_start: Option<InFile<TextSize>>,
118 126
@@ -122,12 +130,24 @@ struct HygieneInfo {
122} 130}
123 131
124impl HygieneInfo { 132impl HygieneInfo {
125 fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> { 133 fn map_ident_up(
134 &self,
135 db: &dyn AstDatabase,
136 token: TextRange,
137 ) -> Option<(InFile<TextRange>, Origin)> {
126 let token_id = self.exp_map.token_by_range(token)?; 138 let token_id = self.exp_map.token_by_range(token)?;
127 139
128 let (token_id, origin) = self.macro_def.map_id_up(token_id); 140 let (token_id, origin) = self.macro_def.map_id_up(token_id);
129 let (token_map, tt) = match origin { 141 let (token_map, tt) = match origin {
130 mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), 142 mbe::Origin::Call => {
143 let call_id = match self.file.macro_call_id {
144 MacroCallId::LazyMacro(lazy) => lazy,
145 MacroCallId::EagerMacro(_) => unreachable!(),
146 };
147 let loc: MacroCallLoc = db.lookup_intern_macro(call_id);
148 let arg_start = loc.kind.arg(db)?.text_range().start();
149 (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start))
150 }
131 mbe::Origin::Def => match (&*self.macro_def, self.def_start) { 151 mbe::Origin::Def => match (&*self.macro_def, self.def_start) {
132 (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) 152 (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt))
133 | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { 153 | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => {
@@ -147,8 +167,6 @@ fn make_hygiene_info(
147 macro_file: MacroFile, 167 macro_file: MacroFile,
148 loc: &MacroCallLoc, 168 loc: &MacroCallLoc,
149) -> Option<HygieneInfo> { 169) -> Option<HygieneInfo> {
150 let arg_tt = loc.kind.arg(db)?;
151
152 let def_offset = loc.def.ast_id().left().and_then(|id| { 170 let def_offset = loc.def.ast_id().left().and_then(|id| {
153 let def_tt = match id.to_node(db) { 171 let def_tt = match id.to_node(db) {
154 ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), 172 ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
@@ -161,13 +179,7 @@ fn make_hygiene_info(
161 let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; 179 let (_, exp_map) = db.parse_macro_expansion(macro_file).value?;
162 let macro_arg = db.macro_arg(macro_file.macro_call_id)?; 180 let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
163 181
164 Some(HygieneInfo { 182 Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map })
165 arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()),
166 def_start: def_offset,
167 macro_arg,
168 macro_def,
169 exp_map,
170 })
171} 183}
172 184
173impl HygieneFrame { 185impl HygieneFrame {
@@ -178,7 +190,8 @@ impl HygieneFrame {
178 MacroCallId::EagerMacro(_id) => (None, None, false), 190 MacroCallId::EagerMacro(_id) => (None, None, false),
179 MacroCallId::LazyMacro(id) => { 191 MacroCallId::LazyMacro(id) => {
180 let loc = db.lookup_intern_macro(id); 192 let loc = db.lookup_intern_macro(id);
181 let info = make_hygiene_info(db, macro_file, &loc); 193 let info = make_hygiene_info(db, macro_file, &loc)
194 .map(|info| (loc.kind.file_id(), info));
182 match loc.def.kind { 195 match loc.def.kind {
183 MacroDefKind::Declarative(_) => { 196 MacroDefKind::Declarative(_) => {
184 (info, Some(loc.def.krate), loc.def.local_inner) 197 (info, Some(loc.def.krate), loc.def.local_inner)
@@ -192,7 +205,7 @@ impl HygieneFrame {
192 }, 205 },
193 }; 206 };
194 207
195 let info = match info { 208 let (calling_file, info) = match info {
196 None => { 209 None => {
197 return HygieneFrame { 210 return HygieneFrame {
198 expansion: None, 211 expansion: None,
@@ -206,7 +219,7 @@ impl HygieneFrame {
206 }; 219 };
207 220
208 let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); 221 let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id));
209 let call_site = Some(db.hygiene_frame(info.arg_start.file_id)); 222 let call_site = Some(db.hygiene_frame(calling_file));
210 223
211 HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } 224 HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site }
212 } 225 }