mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Respect attributes in Hygiene token up-mapping
This commit is contained in:
parent
5fb8c0ddfd
commit
4933beca87
2 changed files with 60 additions and 29 deletions
|
@ -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(¯o_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 }
|
||||||
|
|
|
@ -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(¯o_arg.0),
|
macro_arg_shift: mbe::Shift::new(¯o_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, .. },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue