Respect attributes in Hygiene token up-mapping

This commit is contained in:
Lukas Wirth 2021-08-22 19:12:45 +02:00
parent 5fb8c0ddfd
commit 4933beca87
2 changed files with 60 additions and 29 deletions

View file

@ -9,12 +9,15 @@ use db::TokenExpander;
use either::Either; use either::Either;
use mbe::Origin; use mbe::Origin;
use parser::SyntaxKind; use parser::SyntaxKind;
use syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize}; use syntax::{
ast::{self, AttrsOwner},
AstNode, SyntaxNode, TextRange, TextSize,
};
use crate::{ use crate::{
db::{self, AstDatabase}, db::{self, AstDatabase},
name::{AsName, Name}, name::{AsName, Name},
HirFileId, HirFileIdRepr, InFile, MacroCallLoc, MacroDefKind, MacroFile, HirFileId, HirFileIdRepr, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -121,11 +124,12 @@ impl HygieneFrames {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
struct HygieneInfo { struct HygieneInfo {
file: MacroFile, file: MacroFile,
/// The `macro_rules!` arguments. /// The start offset of the `macro_rules!` arguments or attribute input.
def_start: Option<InFile<TextSize>>, attr_input_or_mac_def_start: Option<InFile<TextSize>>,
macro_def: Arc<TokenExpander>, macro_def: Arc<TokenExpander>,
macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
macro_arg_shift: mbe::Shift,
exp_map: Arc<mbe::TokenMap>, exp_map: Arc<mbe::TokenMap>,
} }
@ -136,23 +140,35 @@ impl HygieneInfo {
token: TextRange, token: TextRange,
) -> Option<(InFile<TextRange>, Origin)> { ) -> Option<(InFile<TextRange>, Origin)> {
let token_id = self.exp_map.token_by_range(token)?; let token_id = self.exp_map.token_by_range(token)?;
let (mut token_id, origin) = self.macro_def.map_id_up(token_id);
let (token_id, origin) = self.macro_def.map_id_up(token_id); let loc = db.lookup_intern_macro(self.file.macro_call_id);
let (token_map, tt) = match origin {
mbe::Origin::Call => { let (token_map, tt) = match &loc.kind {
let call_id = self.file.macro_call_id; MacroCallKind::Attr { attr_args, .. } => match self.macro_arg_shift.unshift(token_id) {
let loc: MacroCallLoc = db.lookup_intern_macro(call_id); Some(unshifted) => {
let arg_start = loc.kind.arg(db)?.text_range().start(); token_id = unshifted;
(&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) (&attr_args.1, self.attr_input_or_mac_def_start?)
} }
mbe::Origin::Def => match (&*self.macro_def, self.def_start) { None => (
&self.macro_arg.1,
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
),
},
_ => match origin {
mbe::Origin::Call => (
&self.macro_arg.1,
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
),
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def_start) {
( (
TokenExpander::MacroDef { def_site_token_map, .. } TokenExpander::MacroDef { def_site_token_map, .. }
| TokenExpander::MacroRules { def_site_token_map, .. }, | TokenExpander::MacroRules { def_site_token_map, .. },
Some(tt), Some(tt),
) => (def_site_token_map, tt), ) => (def_site_token_map, *tt),
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
}, },
},
}; };
let range = token_map.range_by_token(token_id, SyntaxKind::IDENT)?; let range = token_map.range_by_token(token_id, SyntaxKind::IDENT)?;
@ -165,19 +181,34 @@ fn make_hygiene_info(
macro_file: MacroFile, macro_file: MacroFile,
loc: &MacroCallLoc, loc: &MacroCallLoc,
) -> Option<HygieneInfo> { ) -> Option<HygieneInfo> {
let def_offset = loc.def.ast_id().left().and_then(|id| { let def = loc.def.ast_id().left().and_then(|id| {
let def_tt = match id.to_node(db) { let def_tt = match id.to_node(db) {
ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), ast::Macro::MacroRules(mac) => mac.token_tree()?,
ast::Macro::MacroDef(mac) => mac.body()?.syntax().text_range().start(), ast::Macro::MacroDef(mac) => mac.body()?,
}; };
Some(InFile::new(id.file_id, def_tt)) Some(InFile::new(id.file_id, def_tt))
}); });
let attr_input_or_mac_def = def.or_else(|| match loc.kind {
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
let tt = ast_id.to_node(db).attrs().nth(invoc_attr_index as usize)?.token_tree()?;
Some(InFile::new(ast_id.file_id, tt))
}
_ => None,
});
let macro_def = db.macro_def(loc.def)?; let macro_def = db.macro_def(loc.def)?;
let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; let (_, exp_map) = db.parse_macro_expansion(macro_file).value?;
let macro_arg = db.macro_arg(macro_file.macro_call_id)?; let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map }) Some(HygieneInfo {
file: macro_file,
attr_input_or_mac_def_start: attr_input_or_mac_def
.map(|it| it.map(|tt| tt.syntax().text_range().start())),
macro_arg_shift: mbe::Shift::new(&macro_arg.0),
macro_arg,
macro_def,
exp_map,
})
} }
impl HygieneFrame { impl HygieneFrame {
@ -214,7 +245,7 @@ impl HygieneFrame {
Some(it) => it, Some(it) => it,
}; };
let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); let def_site = info.attr_input_or_mac_def_start.map(|it| db.hygiene_frame(it.file_id));
let call_site = Some(db.hygiene_frame(calling_file)); let call_site = Some(db.hygiene_frame(calling_file));
HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site }

View file

@ -133,13 +133,13 @@ impl HirFileId {
}; };
Some(InFile::new(id.file_id, def_tt)) Some(InFile::new(id.file_id, def_tt))
}); });
let def_or_attr_input = def.or_else(|| match loc.kind { let attr_input_or_mac_def = def.or_else(|| match loc.kind {
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
let tt = ast_id let tt = ast_id
.to_node(db) .to_node(db)
.attrs() .attrs()
.nth(invoc_attr_index as usize) .nth(invoc_attr_index as usize)?
.and_then(|attr| attr.token_tree())?; .token_tree()?;
Some(InFile::new(ast_id.file_id, tt)) Some(InFile::new(ast_id.file_id, tt))
} }
_ => None, _ => None,
@ -152,7 +152,7 @@ impl HirFileId {
Some(ExpansionInfo { Some(ExpansionInfo {
expanded: InFile::new(self, parse.syntax_node()), expanded: InFile::new(self, parse.syntax_node()),
arg: InFile::new(loc.kind.file_id(), arg_tt), arg: InFile::new(loc.kind.file_id(), arg_tt),
attr_input_or_mac_def: def_or_attr_input, attr_input_or_mac_def,
macro_arg_shift: mbe::Shift::new(&macro_arg.0), macro_arg_shift: mbe::Shift::new(&macro_arg.0),
macro_arg, macro_arg,
macro_def, macro_def,
@ -443,7 +443,7 @@ impl ExpansionInfo {
}, },
_ => match origin { _ => match origin {
mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
mbe::Origin::Def => match (&*self.macro_def, self.attr_input_or_mac_def.as_ref()) { mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
( (
TokenExpander::MacroRules { def_site_token_map, .. } TokenExpander::MacroRules { def_site_token_map, .. }
| TokenExpander::MacroDef { def_site_token_map, .. }, | TokenExpander::MacroDef { def_site_token_map, .. },