Skip to content

Commit 3f9f63c

Browse files
committed
Improve expand_macro
1 parent ce4670f commit 3f9f63c

File tree

2 files changed

+63
-36
lines changed

2 files changed

+63
-36
lines changed

crates/hir_def/src/item_scope.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind};
88
use once_cell::sync::Lazy;
99
use profile::Count;
1010
use rustc_hash::{FxHashMap, FxHashSet};
11+
use smallvec::SmallVec;
1112
use stdx::format_to;
1213
use syntax::ast;
1314

@@ -61,7 +62,7 @@ pub struct ItemScope {
6162
// be all resolved to the last one defined if shadowing happens.
6263
legacy_macros: FxHashMap<Name, MacroDefId>,
6364
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
64-
derive_macros: FxHashMap<AstId<ast::Item>, (AttrId, MacroCallId)>,
65+
derive_macros: FxHashMap<AstId<ast::Item>, SmallVec<[(AttrId, MacroCallId); 1]>>,
6566
}
6667

6768
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
@@ -189,13 +190,13 @@ impl ItemScope {
189190
call: MacroCallId,
190191
attr_id: AttrId,
191192
) {
192-
self.derive_macros.insert(item, (attr_id, call));
193+
self.derive_macros.entry(item).or_default().push((attr_id, call));
193194
}
194195

195196
pub(crate) fn derive_macro_invocs(
196197
&self,
197198
) -> impl Iterator<Item = (AstId<ast::Item>, (AttrId, MacroCallId))> + '_ {
198-
self.derive_macros.iter().map(|(k, v)| (*k, *v))
199+
self.derive_macros.iter().flat_map(|(k, v)| v.iter().map(move |v| (*k, *v)))
199200
}
200201

201202
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {

crates/ide/src/expand_macro.rs

+59-33
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::iter;
33
use hir::Semantics;
44
use ide_db::{helpers::pick_best_token, RootDatabase};
55
use itertools::Itertools;
6-
use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*, SyntaxNode, WalkEvent, T};
6+
use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T};
77

88
use crate::FilePosition;
99

@@ -31,29 +31,29 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
3131
SyntaxKind::IDENT => 1,
3232
_ => 0,
3333
})?;
34+
let descended = sema.descend_into_macros(tok.clone());
35+
if let Some(attr) = descended.ancestors().find_map(ast::Attr::cast) {
36+
if let Some((path, tt)) = attr.as_simple_call() {
37+
if path == "derive" {
38+
let mut tt = tt.syntax().children_with_tokens().skip(1).join("");
39+
tt.pop();
40+
return sema
41+
.expand_derive_macro(&attr)
42+
.map(insert_whitespaces)
43+
.map(|expansion| ExpandedMacro { name: tt, expansion });
44+
}
45+
}
46+
}
3447
let mut expanded = None;
3548
let mut name = None;
3649
for node in tok.ancestors() {
37-
if let Some(attr) = ast::Attr::cast(node.clone()) {
38-
if let Some((path, tt)) = attr.as_simple_call() {
39-
if path == "derive" {
40-
let mut tt = tt.syntax().children_with_tokens().skip(1).join("");
41-
tt.pop();
42-
name = Some(tt);
43-
expanded = sema.expand_derive_macro(&attr);
44-
break;
45-
}
46-
}
47-
}
48-
4950
if let Some(item) = ast::Item::cast(node.clone()) {
5051
if let Some(def) = sema.resolve_attr_macro_call(&item) {
5152
name = def.name(db).map(|name| name.to_string());
5253
expanded = expand_attr_macro_recur(&sema, &item);
5354
break;
5455
}
5556
}
56-
5757
if let Some(mac) = ast::MacroCall::cast(node) {
5858
name = Some(mac.path()?.segment()?.name_ref()?.to_string());
5959
expanded = expand_macro_recur(&sema, &mac);
@@ -107,24 +107,26 @@ fn expand<T: AstNode>(
107107
// FIXME: It would also be cool to share logic here and in the mbe tests,
108108
// which are pretty unreadable at the moment.
109109
fn insert_whitespaces(syn: SyntaxNode) -> String {
110+
use SyntaxKind::*;
110111
let mut res = String::new();
111-
let mut token_iter = syn
112-
.preorder_with_tokens()
113-
.filter_map(|event| {
114-
if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
115-
Some(token)
116-
} else {
117-
None
118-
}
119-
})
120-
.peekable();
121112

122113
let mut indent = 0;
123114
let mut last: Option<SyntaxKind> = None;
124115

125-
while let Some(token) = token_iter.next() {
126-
let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
127-
token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
116+
for event in syn.preorder_with_tokens() {
117+
let token = match event {
118+
WalkEvent::Enter(NodeOrToken::Token(token)) => token,
119+
WalkEvent::Leave(NodeOrToken::Node(node))
120+
if matches!(node.kind(), ATTR | MATCH_ARM | STRUCT | ENUM | UNION | FN | IMPL) =>
121+
{
122+
res.push('\n');
123+
res.extend(iter::repeat(" ").take(2 * indent));
124+
continue;
125+
}
126+
_ => continue,
127+
};
128+
let is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
129+
token.next_token().map(|it| f(it.kind())).unwrap_or(default)
128130
};
129131
let is_last =
130132
|f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
@@ -182,6 +184,7 @@ mod tests {
182184

183185
use crate::fixture;
184186

187+
#[track_caller]
185188
fn check(ra_fixture: &str, expect: Expect) {
186189
let (analysis, pos) = fixture::position(ra_fixture);
187190
let expansion = analysis.expand_macro(pos).unwrap().unwrap();
@@ -207,6 +210,7 @@ f$0oo!();
207210
expect![[r#"
208211
foo
209212
fn b(){}
213+
210214
"#]],
211215
);
212216
}
@@ -226,11 +230,12 @@ macro_rules! foo {
226230
f$0oo!();
227231
"#,
228232
expect![[r#"
229-
foo
230-
fn some_thing() -> u32 {
231-
let a = 0;
232-
a+10
233-
}"#]],
233+
foo
234+
fn some_thing() -> u32 {
235+
let a = 0;
236+
a+10
237+
}
238+
"#]],
234239
);
235240
}
236241

@@ -343,7 +348,6 @@ fn main() {
343348
fn macro_expand_derive() {
344349
check(
345350
r#"
346-
347351
#[rustc_builtin_macro]
348352
pub macro Clone {}
349353
@@ -353,6 +357,28 @@ struct Foo {}
353357
expect![[r#"
354358
Clone
355359
impl< >crate::clone::Clone for Foo< >{}
360+
361+
"#]],
362+
);
363+
}
364+
365+
#[test]
366+
fn macro_expand_derive2() {
367+
check(
368+
r#"
369+
#[rustc_builtin_macro]
370+
pub macro Clone {}
371+
#[rustc_builtin_macro]
372+
pub macro Copy {}
373+
374+
#[derive(Cop$0y)]
375+
#[derive(Clone)]
376+
struct Foo {}
377+
"#,
378+
expect![[r#"
379+
Copy
380+
impl< >crate::marker::Copy for Foo< >{}
381+
356382
"#]],
357383
);
358384
}

0 commit comments

Comments
 (0)