Skip to content

Commit 49763c3

Browse files
bors[bot]Veykril
andauthored
Merge #10029
10029: internal: Improve expand_macro r=Veykril a=Veykril - Adds a few more newlines to the output making it more readable - Fixes a bug with multiple derives not being expandable There seems to be an issue with multiple derives in one attribute only showing the expansion of the last derive which I'll have to investigate. bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents cbbb7f3 + 3f9f63c commit 49763c3

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)