Speculatively expand attributes in completions

This commit is contained in:
Lukas Wirth 2021-09-02 18:54:09 +02:00
parent c3eb646487
commit 2b907652ee
7 changed files with 238 additions and 66 deletions

View file

@ -141,27 +141,40 @@ pub trait AstDatabase: SourceDatabase {
pub fn expand_speculative(
db: &dyn AstDatabase,
actual_macro_call: MacroCallId,
speculative_args: &ast::TokenTree,
speculative_args: &SyntaxNode,
token_to_map: SyntaxToken,
) -> Option<(SyntaxNode, SyntaxToken)> {
let (tt, tmap_1) = mbe::syntax_node_to_token_tree(speculative_args.syntax());
let range =
token_to_map.text_range().checked_sub(speculative_args.syntax().text_range().start())?;
let token_id = tmap_1.token_by_range(range)?;
let loc = db.lookup_intern_macro(actual_macro_call);
let macro_def = db.macro_def(loc.def)?;
let macro_def = {
let loc: MacroCallLoc = db.lookup_intern_macro(actual_macro_call);
db.macro_def(loc.def)?
// Fetch token id in the speculative args
let censor = censor_for_macro_input(&loc, &speculative_args);
let (tt, args_tmap) = mbe::syntax_node_to_token_tree_censored(&speculative_args, censor);
let range = token_to_map.text_range().checked_sub(speculative_args.text_range().start())?;
let token_id = args_tmap.token_by_range(range)?;
let speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind {
let attr_arg = match &loc.kind {
// FIXME make attr arg speculative as well
MacroCallKind::Attr { attr_args, .. } => {
let mut attr_args = attr_args.0.clone();
mbe::Shift::new(&tt).shift_all(&mut attr_args);
Some(attr_args)
}
_ => None,
};
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
} else {
macro_def.expand(db, actual_macro_call, &tt)
};
let speculative_expansion = macro_def.expand(db, actual_macro_call, &tt);
let expand_to = macro_expand_to(db, actual_macro_call);
let (node, tmap_2) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to).ok()?;
let (node, rev_tmap) =
token_tree_to_syntax_node(&speculative_expansion.value, expand_to).ok()?;
let token_id = macro_def.map_id_down(token_id);
let range = tmap_2.first_range_by_token(token_id, token_to_map.kind())?;
let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
let token = node.syntax_node().covering_element(range).into_token()?;
Some((node.syntax_node(), token))
}
@ -259,7 +272,19 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree,
let loc = db.lookup_intern_macro(id);
let node = SyntaxNode::new_root(arg);
let censor = match loc.kind {
let censor = censor_for_macro_input(&loc, &node);
let (mut tt, tmap) = mbe::syntax_node_to_token_tree_censored(&node, censor);
if loc.def.is_proc_macro() {
// proc macros expect their inputs without parentheses, MBEs expect it with them included
tt.delimiter = None;
}
Some(Arc::new((tt, tmap)))
}
fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> Option<TextRange> {
match loc.kind {
MacroCallKind::FnLike { .. } => None,
MacroCallKind::Derive { derive_attr_index, .. } => match ast::Item::cast(node.clone()) {
Some(item) => item
@ -275,15 +300,7 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree,
}
None => None,
},
};
let (mut tt, tmap) = mbe::syntax_node_to_token_tree_censored(&node, censor);
if loc.def.is_proc_macro() {
// proc macros expect their inputs without parentheses, MBEs expect it with them included
tt.delimiter = None;
}
Some(Arc::new((tt, tmap)))
}
fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
@ -367,11 +384,11 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Ar
None => return ExpandResult::str_err("Failed to lower macro args to token tree".into()),
};
let macro_rules = match db.macro_def(loc.def) {
let expander = match db.macro_def(loc.def) {
Some(it) => it,
None => return ExpandResult::str_err("Failed to find macro definition".into()),
};
let ExpandResult { value: tt, err } = macro_rules.expand(db, id, &macro_arg.0);
let ExpandResult { value: tt, err } = expander.expand(db, id, &macro_arg.0);
// Set a hard limit for the expanded tt
let count = tt.count();
// XXX: Make ExpandResult a real error and use .map_err instead?

View file

@ -370,6 +370,7 @@ impl ExpansionInfo {
) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> {
assert_eq!(token.file_id, self.arg.file_id);
let token_id = if let Some(item) = item {
// check if we are mapping down in an attribute input
let call_id = match self.expanded.file_id.0 {
HirFileIdRepr::FileId(_) => return None,
HirFileIdRepr::MacroFile(macro_file) => macro_file.macro_call_id,