Skip to content

Commit 4933bec

Browse files
committed
Respect attributes in Hygiene token up-mapping
1 parent 5fb8c0d commit 4933bec

File tree

2 files changed

+60
-29
lines changed

2 files changed

+60
-29
lines changed

crates/hir_expand/src/hygiene.rs

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ use db::TokenExpander;
99
use either::Either;
1010
use mbe::Origin;
1111
use parser::SyntaxKind;
12-
use syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize};
12+
use syntax::{
13+
ast::{self, AttrsOwner},
14+
AstNode, SyntaxNode, TextRange, TextSize,
15+
};
1316

1417
use crate::{
1518
db::{self, AstDatabase},
1619
name::{AsName, Name},
17-
HirFileId, HirFileIdRepr, InFile, MacroCallLoc, MacroDefKind, MacroFile,
20+
HirFileId, HirFileIdRepr, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile,
1821
};
1922

2023
#[derive(Clone, Debug)]
@@ -121,11 +124,12 @@ impl HygieneFrames {
121124
#[derive(Debug, Clone, PartialEq, Eq)]
122125
struct HygieneInfo {
123126
file: MacroFile,
124-
/// The `macro_rules!` arguments.
125-
def_start: Option<InFile<TextSize>>,
127+
/// The start offset of the `macro_rules!` arguments or attribute input.
128+
attr_input_or_mac_def_start: Option<InFile<TextSize>>,
126129

127130
macro_def: Arc<TokenExpander>,
128131
macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
132+
macro_arg_shift: mbe::Shift,
129133
exp_map: Arc<mbe::TokenMap>,
130134
}
131135

@@ -136,22 +140,34 @@ impl HygieneInfo {
136140
token: TextRange,
137141
) -> Option<(InFile<TextRange>, Origin)> {
138142
let token_id = self.exp_map.token_by_range(token)?;
143+
let (mut token_id, origin) = self.macro_def.map_id_up(token_id);
139144

140-
let (token_id, origin) = self.macro_def.map_id_up(token_id);
141-
let (token_map, tt) = match origin {
142-
mbe::Origin::Call => {
143-
let call_id = self.file.macro_call_id;
144-
let loc: MacroCallLoc = db.lookup_intern_macro(call_id);
145-
let arg_start = loc.kind.arg(db)?.text_range().start();
146-
(&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start))
147-
}
148-
mbe::Origin::Def => match (&*self.macro_def, self.def_start) {
149-
(
150-
TokenExpander::MacroDef { def_site_token_map, .. }
151-
| TokenExpander::MacroRules { def_site_token_map, .. },
152-
Some(tt),
153-
) => (def_site_token_map, tt),
154-
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
145+
let loc = db.lookup_intern_macro(self.file.macro_call_id);
146+
147+
let (token_map, tt) = match &loc.kind {
148+
MacroCallKind::Attr { attr_args, .. } => match self.macro_arg_shift.unshift(token_id) {
149+
Some(unshifted) => {
150+
token_id = unshifted;
151+
(&attr_args.1, self.attr_input_or_mac_def_start?)
152+
}
153+
None => (
154+
&self.macro_arg.1,
155+
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
156+
),
157+
},
158+
_ => match origin {
159+
mbe::Origin::Call => (
160+
&self.macro_arg.1,
161+
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
162+
),
163+
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def_start) {
164+
(
165+
TokenExpander::MacroDef { def_site_token_map, .. }
166+
| TokenExpander::MacroRules { def_site_token_map, .. },
167+
Some(tt),
168+
) => (def_site_token_map, *tt),
169+
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
170+
},
155171
},
156172
};
157173

@@ -165,19 +181,34 @@ fn make_hygiene_info(
165181
macro_file: MacroFile,
166182
loc: &MacroCallLoc,
167183
) -> Option<HygieneInfo> {
168-
let def_offset = loc.def.ast_id().left().and_then(|id| {
184+
let def = loc.def.ast_id().left().and_then(|id| {
169185
let def_tt = match id.to_node(db) {
170-
ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
171-
ast::Macro::MacroDef(mac) => mac.body()?.syntax().text_range().start(),
186+
ast::Macro::MacroRules(mac) => mac.token_tree()?,
187+
ast::Macro::MacroDef(mac) => mac.body()?,
172188
};
173189
Some(InFile::new(id.file_id, def_tt))
174190
});
191+
let attr_input_or_mac_def = def.or_else(|| match loc.kind {
192+
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
193+
let tt = ast_id.to_node(db).attrs().nth(invoc_attr_index as usize)?.token_tree()?;
194+
Some(InFile::new(ast_id.file_id, tt))
195+
}
196+
_ => None,
197+
});
175198

176199
let macro_def = db.macro_def(loc.def)?;
177200
let (_, exp_map) = db.parse_macro_expansion(macro_file).value?;
178201
let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
179202

180-
Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map })
203+
Some(HygieneInfo {
204+
file: macro_file,
205+
attr_input_or_mac_def_start: attr_input_or_mac_def
206+
.map(|it| it.map(|tt| tt.syntax().text_range().start())),
207+
macro_arg_shift: mbe::Shift::new(&macro_arg.0),
208+
macro_arg,
209+
macro_def,
210+
exp_map,
211+
})
181212
}
182213

183214
impl HygieneFrame {
@@ -214,7 +245,7 @@ impl HygieneFrame {
214245
Some(it) => it,
215246
};
216247

217-
let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id));
248+
let def_site = info.attr_input_or_mac_def_start.map(|it| db.hygiene_frame(it.file_id));
218249
let call_site = Some(db.hygiene_frame(calling_file));
219250

220251
HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site }

crates/hir_expand/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@ impl HirFileId {
133133
};
134134
Some(InFile::new(id.file_id, def_tt))
135135
});
136-
let def_or_attr_input = def.or_else(|| match loc.kind {
136+
let attr_input_or_mac_def = def.or_else(|| match loc.kind {
137137
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
138138
let tt = ast_id
139139
.to_node(db)
140140
.attrs()
141-
.nth(invoc_attr_index as usize)
142-
.and_then(|attr| attr.token_tree())?;
141+
.nth(invoc_attr_index as usize)?
142+
.token_tree()?;
143143
Some(InFile::new(ast_id.file_id, tt))
144144
}
145145
_ => None,
@@ -152,7 +152,7 @@ impl HirFileId {
152152
Some(ExpansionInfo {
153153
expanded: InFile::new(self, parse.syntax_node()),
154154
arg: InFile::new(loc.kind.file_id(), arg_tt),
155-
attr_input_or_mac_def: def_or_attr_input,
155+
attr_input_or_mac_def,
156156
macro_arg_shift: mbe::Shift::new(&macro_arg.0),
157157
macro_arg,
158158
macro_def,
@@ -443,7 +443,7 @@ impl ExpansionInfo {
443443
},
444444
_ => match origin {
445445
mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
446-
mbe::Origin::Def => match (&*self.macro_def, self.attr_input_or_mac_def.as_ref()) {
446+
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
447447
(
448448
TokenExpander::MacroRules { def_site_token_map, .. }
449449
| TokenExpander::MacroDef { def_site_token_map, .. },

0 commit comments

Comments
 (0)