mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 14:21:44 +00:00
Expand into pseudo-derive attribute expansions in completions
This commit is contained in:
parent
533f178a52
commit
a8b76b632c
13 changed files with 197 additions and 56 deletions
|
@ -1,7 +1,5 @@
|
|||
//! Builtin attributes.
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{db::AstDatabase, name, ExpandResult, MacroCallId, MacroCallKind};
|
||||
|
||||
macro_rules! register_builtin {
|
||||
|
@ -98,10 +96,16 @@ fn derive_attr_expand(
|
|||
) -> ExpandResult<tt::Subtree> {
|
||||
let loc = db.lookup_intern_macro_call(id);
|
||||
let derives = match &loc.kind {
|
||||
MacroCallKind::Attr { attr_args, .. } => &attr_args.0,
|
||||
_ => return ExpandResult::ok(tt.clone()),
|
||||
MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0,
|
||||
_ => return ExpandResult::ok(Default::default()),
|
||||
};
|
||||
pseudo_derive_attr_expansion(tt, derives)
|
||||
}
|
||||
|
||||
pub fn pseudo_derive_attr_expansion(
|
||||
tt: &tt::Subtree,
|
||||
args: &tt::Subtree,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let mk_leaf = |char| {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
||||
char,
|
||||
|
@ -111,21 +115,12 @@ fn derive_attr_expand(
|
|||
};
|
||||
|
||||
let mut token_trees = Vec::new();
|
||||
for (comma, group) in &derives
|
||||
.token_trees
|
||||
.iter()
|
||||
.filter_map(|tt| match tt {
|
||||
tt::TokenTree::Leaf(l) => Some(l),
|
||||
tt::TokenTree::Subtree(_) => None,
|
||||
})
|
||||
.group_by(|l| matches!(l, tt::Leaf::Punct(tt::Punct { char: ',', .. })))
|
||||
for tt in (&args.token_trees)
|
||||
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))))
|
||||
{
|
||||
if comma {
|
||||
continue;
|
||||
}
|
||||
token_trees.push(mk_leaf('#'));
|
||||
token_trees.push(mk_leaf('['));
|
||||
token_trees.extend(group.cloned().map(tt::TokenTree::Leaf));
|
||||
token_trees.extend(tt.iter().cloned());
|
||||
token_trees.push(mk_leaf(']'));
|
||||
}
|
||||
token_trees.push(mk_leaf('('));
|
||||
|
|
|
@ -14,10 +14,10 @@ use syntax::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
ast_id_map::AstIdMap, fixup, hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander,
|
||||
BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr,
|
||||
MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile,
|
||||
ProcMacroExpander,
|
||||
ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
|
||||
hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
||||
ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
|
||||
MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
|
||||
};
|
||||
|
||||
/// Total limit on the number of tokens produced by any macro invocation.
|
||||
|
@ -161,14 +161,16 @@ pub fn expand_speculative(
|
|||
);
|
||||
|
||||
let (attr_arg, token_id) = match loc.kind {
|
||||
MacroCallKind::Attr { invoc_attr_index, .. } => {
|
||||
// Attributes may have an input token tree, build the subtree and map for this as well
|
||||
// then try finding a token id for our token if it is inside this input subtree.
|
||||
let item = ast::Item::cast(speculative_args.clone())?;
|
||||
let attr = item
|
||||
.doc_comments_and_attrs()
|
||||
.nth(invoc_attr_index as usize)
|
||||
.and_then(Either::left)?;
|
||||
MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => {
|
||||
let attr = if is_derive {
|
||||
// for pseudo-derive expansion we actually pass the attribute itself only
|
||||
ast::Attr::cast(speculative_args.clone())
|
||||
} else {
|
||||
// Attributes may have an input token tree, build the subtree and map for this as well
|
||||
// then try finding a token id for our token if it is inside this input subtree.
|
||||
let item = ast::Item::cast(speculative_args.clone())?;
|
||||
item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left)
|
||||
}?;
|
||||
match attr.token_tree() {
|
||||
Some(token_tree) => {
|
||||
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
|
||||
|
@ -205,11 +207,15 @@ pub fn expand_speculative(
|
|||
|
||||
// Do the actual expansion, we need to directly expand the proc macro due to the attribute args
|
||||
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
|
||||
let mut speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind {
|
||||
tt.delimiter = None;
|
||||
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
|
||||
} else {
|
||||
macro_def.expand(db, actual_macro_call, &tt)
|
||||
let mut speculative_expansion = match loc.def.kind {
|
||||
MacroDefKind::ProcMacro(expander, ..) => {
|
||||
tt.delimiter = None;
|
||||
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
|
||||
}
|
||||
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
|
||||
pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
|
||||
}
|
||||
_ => macro_def.expand(db, actual_macro_call, &tt),
|
||||
};
|
||||
|
||||
let expand_to = macro_expand_to(db, actual_macro_call);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue