Skip to content

Commit 08c706f

Browse files
committed
Auto merge of #16057 - Veykril:macro-arm, r=Veykril
Render matched macro arm on hover of macro calls Fixes #4028, its a different take on the idea. I don't like go to being changed here simply because we can't point the focus range on the name anymore as we usually do, and some editors might use this feature (and the focus range) for certain other things. We could instead add a new hover action for this to move to the arm directly (or maybe make `go to implementation` jump to the arm?)
2 parents 68b1a28 + 4135696 commit 08c706f

File tree

11 files changed

+140
-67
lines changed

11 files changed

+140
-67
lines changed

crates/hir-expand/src/db.rs

+24-17
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use base_db::{salsa, CrateId, FileId, SourceDatabase};
44
use either::Either;
55
use limit::Limit;
6-
use mbe::syntax_node_to_token_tree;
6+
use mbe::{syntax_node_to_token_tree, MatchedArmIndex};
77
use rustc_hash::FxHashSet;
88
use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
99
use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
@@ -313,16 +313,18 @@ fn parse_macro_expansion(
313313
let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
314314
let edition = loc.def.edition;
315315
let expand_to = loc.expand_to();
316-
let mbe::ValueResult { value: tt, err } = macro_expand(db, macro_file.macro_call_id, loc);
316+
let mbe::ValueResult { value: (tt, matched_arm), err } =
317+
macro_expand(db, macro_file.macro_call_id, loc);
317318

318-
let (parse, rev_token_map) = token_tree_to_syntax_node(
319+
let (parse, mut rev_token_map) = token_tree_to_syntax_node(
319320
match &tt {
320321
CowArc::Arc(it) => it,
321322
CowArc::Owned(it) => it,
322323
},
323324
expand_to,
324325
edition,
325326
);
327+
rev_token_map.matched_arm = matched_arm;
326328

327329
ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
328330
}
@@ -544,11 +546,13 @@ fn macro_expand(
544546
db: &dyn ExpandDatabase,
545547
macro_call_id: MacroCallId,
546548
loc: MacroCallLoc,
547-
) -> ExpandResult<CowArc<tt::Subtree>> {
549+
) -> ExpandResult<(CowArc<tt::Subtree>, MatchedArmIndex)> {
548550
let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered();
549551

550-
let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
551-
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
552+
let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
553+
MacroDefKind::ProcMacro(..) => {
554+
return db.expand_proc_macro(macro_call_id).map(CowArc::Arc).zip_val(None)
555+
}
552556
_ => {
553557
let (macro_arg, undo_info, span) =
554558
db.macro_arg_considering_derives(macro_call_id, &loc.kind);
@@ -560,10 +564,10 @@ fn macro_expand(
560564
.decl_macro_expander(loc.def.krate, id)
561565
.expand(db, arg.clone(), macro_call_id, span),
562566
MacroDefKind::BuiltIn(it, _) => {
563-
it.expand(db, macro_call_id, arg, span).map_err(Into::into)
567+
it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
564568
}
565569
MacroDefKind::BuiltInDerive(it, _) => {
566-
it.expand(db, macro_call_id, arg, span).map_err(Into::into)
570+
it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
567571
}
568572
MacroDefKind::BuiltInEager(it, _) => {
569573
// This might look a bit odd, but we do not expand the inputs to eager macros here.
@@ -574,7 +578,8 @@ fn macro_expand(
574578
// As such we just return the input subtree here.
575579
let eager = match &loc.kind {
576580
MacroCallKind::FnLike { eager: None, .. } => {
577-
return ExpandResult::ok(CowArc::Arc(macro_arg.clone()));
581+
return ExpandResult::ok(CowArc::Arc(macro_arg.clone()))
582+
.zip_val(None);
578583
}
579584
MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
580585
_ => None,
@@ -586,12 +591,12 @@ fn macro_expand(
586591
// FIXME: We should report both errors!
587592
res.err = error.clone().or(res.err);
588593
}
589-
res
594+
res.zip_val(None)
590595
}
591596
MacroDefKind::BuiltInAttr(it, _) => {
592597
let mut res = it.expand(db, macro_call_id, arg, span);
593598
fixup::reverse_fixups(&mut res.value, &undo_info);
594-
res
599+
res.zip_val(None)
595600
}
596601
_ => unreachable!(),
597602
};
@@ -603,16 +608,18 @@ fn macro_expand(
603608
if !loc.def.is_include() {
604609
// Set a hard limit for the expanded tt
605610
if let Err(value) = check_tt_count(&tt) {
606-
return value.map(|()| {
607-
CowArc::Owned(tt::Subtree {
608-
delimiter: tt::Delimiter::invisible_spanned(span),
609-
token_trees: Box::new([]),
611+
return value
612+
.map(|()| {
613+
CowArc::Owned(tt::Subtree {
614+
delimiter: tt::Delimiter::invisible_spanned(span),
615+
token_trees: Box::new([]),
616+
})
610617
})
611-
});
618+
.zip_val(matched_arm);
612619
}
613620
}
614621

615-
ExpandResult { value: CowArc::Owned(tt), err }
622+
ExpandResult { value: (CowArc::Owned(tt), matched_arm), err }
616623
}
617624

618625
fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {

crates/hir-expand/src/declarative.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::sync::OnceLock;
33

44
use base_db::{CrateId, VersionReq};
55
use span::{Edition, MacroCallId, Span, SyntaxContextId};
6+
use stdx::TupleExt;
67
use syntax::{ast, AstNode};
78
use triomphe::Arc;
89

@@ -30,7 +31,7 @@ impl DeclarativeMacroExpander {
3031
tt: tt::Subtree,
3132
call_id: MacroCallId,
3233
span: Span,
33-
) -> ExpandResult<tt::Subtree> {
34+
) -> ExpandResult<(tt::Subtree, Option<u32>)> {
3435
let loc = db.lookup_intern_macro_call(call_id);
3536
let toolchain = db.toolchain(loc.def.krate);
3637
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
@@ -46,7 +47,7 @@ impl DeclarativeMacroExpander {
4647
});
4748
match self.mac.err() {
4849
Some(_) => ExpandResult::new(
49-
tt::Subtree::empty(tt::DelimSpan { open: span, close: span }),
50+
(tt::Subtree::empty(tt::DelimSpan { open: span, close: span }), None),
5051
ExpandError::MacroDefinition,
5152
),
5253
None => self
@@ -90,6 +91,7 @@ impl DeclarativeMacroExpander {
9091
None => self
9192
.mac
9293
.expand(&tt, |_| (), new_meta_vars, call_site, def_site_edition)
94+
.map(TupleExt::head)
9395
.map_err(Into::into),
9496
}
9597
}

crates/hir/src/semantics.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,17 @@ impl<'db> SemanticsImpl<'db> {
12461246
.map_or(false, |m| matches!(m.id, MacroId::ProcMacroId(..)))
12471247
}
12481248

1249+
pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
1250+
let sa = self.analyze(macro_call.syntax())?;
1251+
self.db
1252+
.parse_macro_expansion(
1253+
sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?,
1254+
)
1255+
.value
1256+
.1
1257+
.matched_arm
1258+
}
1259+
12491260
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
12501261
let sa = match self.analyze(macro_call.syntax()) {
12511262
Some(it) => it,

crates/ide/src/hover.rs

+35-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ide_db::{
1414
helpers::pick_best_token,
1515
FxIndexSet, RootDatabase,
1616
};
17-
use itertools::Itertools;
17+
use itertools::{multizip, Itertools};
1818
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
1919

2020
use crate::{
@@ -149,7 +149,7 @@ fn hover_simple(
149149
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
150150
cov_mark::hit!(no_highlight_on_comment_hover);
151151
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
152-
let res = hover_for_definition(sema, file_id, def, &node, config);
152+
let res = hover_for_definition(sema, file_id, def, &node, None, config);
153153
Some(RangeInfo::new(range, res))
154154
});
155155
}
@@ -162,6 +162,7 @@ fn hover_simple(
162162
file_id,
163163
Definition::from(resolution?),
164164
&original_token.parent()?,
165+
None,
165166
config,
166167
);
167168
return Some(RangeInfo::new(range, res));
@@ -196,6 +197,29 @@ fn hover_simple(
196197
descended()
197198
.filter_map(|token| {
198199
let node = token.parent()?;
200+
201+
// special case macro calls, we wanna render the invoked arm index
202+
if let Some(name) = ast::NameRef::cast(node.clone()) {
203+
if let Some(path_seg) =
204+
name.syntax().parent().and_then(ast::PathSegment::cast)
205+
{
206+
if let Some(macro_call) = path_seg
207+
.parent_path()
208+
.syntax()
209+
.parent()
210+
.and_then(ast::MacroCall::cast)
211+
{
212+
if let Some(macro_) = sema.resolve_macro_call(&macro_call) {
213+
return Some(vec![(
214+
Definition::Macro(macro_),
215+
sema.resolve_macro_call_arm(&macro_call),
216+
node,
217+
)]);
218+
}
219+
}
220+
}
221+
}
222+
199223
match IdentClass::classify_node(sema, &node)? {
200224
// It's better for us to fall back to the keyword hover here,
201225
// rendering poll is very confusing
@@ -204,20 +228,19 @@ fn hover_simple(
204228
IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
205229
decl,
206230
..
207-
}) => Some(vec![(Definition::ExternCrateDecl(decl), node)]),
231+
}) => Some(vec![(Definition::ExternCrateDecl(decl), None, node)]),
208232

209233
class => Some(
210-
class
211-
.definitions()
212-
.into_iter()
213-
.zip(iter::repeat(node))
234+
multizip((class.definitions(), iter::repeat(None), iter::repeat(node)))
214235
.collect::<Vec<_>>(),
215236
),
216237
}
217238
})
218239
.flatten()
219-
.unique_by(|&(def, _)| def)
220-
.map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
240+
.unique_by(|&(def, _, _)| def)
241+
.map(|(def, macro_arm, node)| {
242+
hover_for_definition(sema, file_id, def, &node, macro_arm, config)
243+
})
221244
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
222245
acc.actions.extend(actions);
223246
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
@@ -374,6 +397,7 @@ pub(crate) fn hover_for_definition(
374397
file_id: FileId,
375398
def: Definition,
376399
scope_node: &SyntaxNode,
400+
macro_arm: Option<u32>,
377401
config: &HoverConfig,
378402
) -> HoverResult {
379403
let famous_defs = match &def {
@@ -398,7 +422,8 @@ pub(crate) fn hover_for_definition(
398422
};
399423
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
400424

401-
let markup = render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config);
425+
let markup =
426+
render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, macro_arm, config);
402427
HoverResult {
403428
markup: render::process_markup(sema.db, def, &markup, config),
404429
actions: [

crates/ide/src/hover/render.rs

+8
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ pub(super) fn definition(
403403
def: Definition,
404404
famous_defs: Option<&FamousDefs<'_, '_>>,
405405
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
406+
macro_arm: Option<u32>,
406407
config: &HoverConfig,
407408
) -> Markup {
408409
let mod_path = definition_mod_path(db, &def);
@@ -413,6 +414,13 @@ pub(super) fn definition(
413414
Definition::Adt(Adt::Struct(struct_)) => {
414415
struct_.display_limited(db, config.max_struct_field_count).to_string()
415416
}
417+
Definition::Macro(it) => {
418+
let mut label = it.display(db).to_string();
419+
if let Some(macro_arm) = macro_arm {
420+
format_to!(label, " // matched arm #{}", macro_arm);
421+
}
422+
label
423+
}
416424
_ => def.label(db),
417425
};
418426
let docs = def.docs(db, famous_defs);

crates/ide/src/hover/tests.rs

+20-20
Original file line numberDiff line numberDiff line change
@@ -1560,21 +1560,21 @@ fn y() {
15601560
fn test_hover_macro_invocation() {
15611561
check(
15621562
r#"
1563-
macro_rules! foo { () => {} }
1563+
macro_rules! foo { (a) => {}; () => {} }
15641564
15651565
fn f() { fo$0o!(); }
15661566
"#,
15671567
expect![[r#"
1568-
*foo*
1568+
*foo*
15691569
1570-
```rust
1571-
test
1572-
```
1570+
```rust
1571+
test
1572+
```
15731573
1574-
```rust
1575-
macro_rules! foo
1576-
```
1577-
"#]],
1574+
```rust
1575+
macro_rules! foo // matched arm #1
1576+
```
1577+
"#]],
15781578
)
15791579
}
15801580

@@ -1590,22 +1590,22 @@ macro foo() {}
15901590
fn f() { fo$0o!(); }
15911591
"#,
15921592
expect![[r#"
1593-
*foo*
1593+
*foo*
15941594
1595-
```rust
1596-
test
1597-
```
1595+
```rust
1596+
test
1597+
```
15981598
1599-
```rust
1600-
macro foo
1601-
```
1599+
```rust
1600+
macro foo // matched arm #0
1601+
```
16021602
1603-
---
1603+
---
16041604
1605-
foo bar
1605+
foo bar
16061606
1607-
foo bar baz
1608-
"#]],
1607+
foo bar baz
1608+
"#]],
16091609
)
16101610
}
16111611

crates/ide/src/static_index.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,14 @@ impl StaticIndex<'_> {
188188
} else {
189189
let it = self.tokens.insert(TokenStaticData {
190190
documentation: documentation_for_definition(&sema, def, &node),
191-
hover: Some(hover_for_definition(&sema, file_id, def, &node, &hover_config)),
191+
hover: Some(hover_for_definition(
192+
&sema,
193+
file_id,
194+
def,
195+
&node,
196+
None,
197+
&hover_config,
198+
)),
192199
definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
193200
FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
194201
}),

crates/mbe/src/benchmark.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn benchmark_expand_macro_rules() {
4848
.map(|(id, tt)| {
4949
let res = rules[&id].expand(&tt, |_| (), true, DUMMY, Edition::CURRENT);
5050
assert!(res.err.is_none());
51-
res.value.token_trees.len()
51+
res.value.0.token_trees.len()
5252
})
5353
.sum()
5454
};

0 commit comments

Comments
 (0)