Skip to content

Commit

Permalink
Auto merge of rust-lang#16057 - Veykril:macro-arm, r=Veykril
Browse files Browse the repository at this point in the history
Render matched macro arm on hover of macro calls

Fixes rust-lang/rust-analyzer#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?)
  • Loading branch information
bors committed Apr 18, 2024
2 parents e8296d2 + 1b5453b commit 30d6e02
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 67 deletions.
41 changes: 24 additions & 17 deletions src/tools/rust-analyzer/crates/hir-expand/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use base_db::{salsa, CrateId, FileId, SourceDatabase};
use either::Either;
use limit::Limit;
use mbe::syntax_node_to_token_tree;
use mbe::{syntax_node_to_token_tree, MatchedArmIndex};
use rustc_hash::FxHashSet;
use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
Expand Down Expand Up @@ -313,16 +313,18 @@ fn parse_macro_expansion(
let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
let edition = loc.def.edition;
let expand_to = loc.expand_to();
let mbe::ValueResult { value: tt, err } = macro_expand(db, macro_file.macro_call_id, loc);
let mbe::ValueResult { value: (tt, matched_arm), err } =
macro_expand(db, macro_file.macro_call_id, loc);

let (parse, rev_token_map) = token_tree_to_syntax_node(
let (parse, mut rev_token_map) = token_tree_to_syntax_node(
match &tt {
CowArc::Arc(it) => it,
CowArc::Owned(it) => it,
},
expand_to,
edition,
);
rev_token_map.matched_arm = matched_arm;

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

let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
MacroDefKind::ProcMacro(..) => {
return db.expand_proc_macro(macro_call_id).map(CowArc::Arc).zip_val(None)
}
_ => {
let (macro_arg, undo_info, span) =
db.macro_arg_considering_derives(macro_call_id, &loc.kind);
Expand All @@ -560,10 +564,10 @@ fn macro_expand(
.decl_macro_expander(loc.def.krate, id)
.expand(db, arg.clone(), macro_call_id, span),
MacroDefKind::BuiltIn(it, _) => {
it.expand(db, macro_call_id, arg, span).map_err(Into::into)
it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
}
MacroDefKind::BuiltInDerive(it, _) => {
it.expand(db, macro_call_id, arg, span).map_err(Into::into)
it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
}
MacroDefKind::BuiltInEager(it, _) => {
// This might look a bit odd, but we do not expand the inputs to eager macros here.
Expand All @@ -574,7 +578,8 @@ fn macro_expand(
// As such we just return the input subtree here.
let eager = match &loc.kind {
MacroCallKind::FnLike { eager: None, .. } => {
return ExpandResult::ok(CowArc::Arc(macro_arg.clone()));
return ExpandResult::ok(CowArc::Arc(macro_arg.clone()))
.zip_val(None);
}
MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
_ => None,
Expand All @@ -586,12 +591,12 @@ fn macro_expand(
// FIXME: We should report both errors!
res.err = error.clone().or(res.err);
}
res
res.zip_val(None)
}
MacroDefKind::BuiltInAttr(it, _) => {
let mut res = it.expand(db, macro_call_id, arg, span);
fixup::reverse_fixups(&mut res.value, &undo_info);
res
res.zip_val(None)
}
_ => unreachable!(),
};
Expand All @@ -603,16 +608,18 @@ fn macro_expand(
if !loc.def.is_include() {
// Set a hard limit for the expanded tt
if let Err(value) = check_tt_count(&tt) {
return value.map(|()| {
CowArc::Owned(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(span),
token_trees: Box::new([]),
return value
.map(|()| {
CowArc::Owned(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(span),
token_trees: Box::new([]),
})
})
});
.zip_val(matched_arm);
}
}

ExpandResult { value: CowArc::Owned(tt), err }
ExpandResult { value: (CowArc::Owned(tt), matched_arm), err }
}

fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
Expand Down
6 changes: 4 additions & 2 deletions src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::OnceLock;

use base_db::{CrateId, VersionReq};
use span::{Edition, MacroCallId, Span, SyntaxContextId};
use stdx::TupleExt;
use syntax::{ast, AstNode};
use triomphe::Arc;

Expand Down Expand Up @@ -30,7 +31,7 @@ impl DeclarativeMacroExpander {
tt: tt::Subtree,
call_id: MacroCallId,
span: Span,
) -> ExpandResult<tt::Subtree> {
) -> ExpandResult<(tt::Subtree, Option<u32>)> {
let loc = db.lookup_intern_macro_call(call_id);
let toolchain = db.toolchain(loc.def.krate);
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
Expand All @@ -46,7 +47,7 @@ impl DeclarativeMacroExpander {
});
match self.mac.err() {
Some(_) => ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: span, close: span }),
(tt::Subtree::empty(tt::DelimSpan { open: span, close: span }), None),
ExpandError::MacroDefinition,
),
None => self
Expand Down Expand Up @@ -90,6 +91,7 @@ impl DeclarativeMacroExpander {
None => self
.mac
.expand(&tt, |_| (), new_meta_vars, call_site, def_site_edition)
.map(TupleExt::head)
.map_err(Into::into),
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/tools/rust-analyzer/crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,17 @@ impl<'db> SemanticsImpl<'db> {
.map_or(false, |m| matches!(m.id, MacroId::ProcMacroId(..)))
}

pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
let sa = self.analyze(macro_call.syntax())?;
self.db
.parse_macro_expansion(
sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?,
)
.value
.1
.matched_arm
}

pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
let sa = match self.analyze(macro_call.syntax()) {
Some(it) => it,
Expand Down
45 changes: 35 additions & 10 deletions src/tools/rust-analyzer/crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ide_db::{
helpers::pick_best_token,
FxIndexSet, RootDatabase,
};
use itertools::Itertools;
use itertools::{multizip, Itertools};
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};

use crate::{
Expand Down Expand Up @@ -149,7 +149,7 @@ fn hover_simple(
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
cov_mark::hit!(no_highlight_on_comment_hover);
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
let res = hover_for_definition(sema, file_id, def, &node, config);
let res = hover_for_definition(sema, file_id, def, &node, None, config);
Some(RangeInfo::new(range, res))
});
}
Expand All @@ -162,6 +162,7 @@ fn hover_simple(
file_id,
Definition::from(resolution?),
&original_token.parent()?,
None,
config,
);
return Some(RangeInfo::new(range, res));
Expand Down Expand Up @@ -196,6 +197,29 @@ fn hover_simple(
descended()
.filter_map(|token| {
let node = token.parent()?;

// special case macro calls, we wanna render the invoked arm index
if let Some(name) = ast::NameRef::cast(node.clone()) {
if let Some(path_seg) =
name.syntax().parent().and_then(ast::PathSegment::cast)
{
if let Some(macro_call) = path_seg
.parent_path()
.syntax()
.parent()
.and_then(ast::MacroCall::cast)
{
if let Some(macro_) = sema.resolve_macro_call(&macro_call) {
return Some(vec![(
Definition::Macro(macro_),
sema.resolve_macro_call_arm(&macro_call),
node,
)]);
}
}
}
}

match IdentClass::classify_node(sema, &node)? {
// It's better for us to fall back to the keyword hover here,
// rendering poll is very confusing
Expand All @@ -204,20 +228,19 @@ fn hover_simple(
IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
decl,
..
}) => Some(vec![(Definition::ExternCrateDecl(decl), node)]),
}) => Some(vec![(Definition::ExternCrateDecl(decl), None, node)]),

class => Some(
class
.definitions()
.into_iter()
.zip(iter::repeat(node))
multizip((class.definitions(), iter::repeat(None), iter::repeat(node)))
.collect::<Vec<_>>(),
),
}
})
.flatten()
.unique_by(|&(def, _)| def)
.map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
.unique_by(|&(def, _, _)| def)
.map(|(def, macro_arm, node)| {
hover_for_definition(sema, file_id, def, &node, macro_arm, config)
})
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
acc.actions.extend(actions);
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
Expand Down Expand Up @@ -374,6 +397,7 @@ pub(crate) fn hover_for_definition(
file_id: FileId,
def: Definition,
scope_node: &SyntaxNode,
macro_arm: Option<u32>,
config: &HoverConfig,
) -> HoverResult {
let famous_defs = match &def {
Expand All @@ -398,7 +422,8 @@ pub(crate) fn hover_for_definition(
};
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();

let markup = render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config);
let markup =
render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, macro_arm, config);
HoverResult {
markup: render::process_markup(sema.db, def, &markup, config),
actions: [
Expand Down
8 changes: 8 additions & 0 deletions src/tools/rust-analyzer/crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ pub(super) fn definition(
def: Definition,
famous_defs: Option<&FamousDefs<'_, '_>>,
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
macro_arm: Option<u32>,
config: &HoverConfig,
) -> Markup {
let mod_path = definition_mod_path(db, &def);
Expand All @@ -413,6 +414,13 @@ pub(super) fn definition(
Definition::Adt(Adt::Struct(struct_)) => {
struct_.display_limited(db, config.max_struct_field_count).to_string()
}
Definition::Macro(it) => {
let mut label = it.display(db).to_string();
if let Some(macro_arm) = macro_arm {
format_to!(label, " // matched arm #{}", macro_arm);
}
label
}
_ => def.label(db),
};
let docs = def.docs(db, famous_defs);
Expand Down
40 changes: 20 additions & 20 deletions src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1560,21 +1560,21 @@ fn y() {
fn test_hover_macro_invocation() {
check(
r#"
macro_rules! foo { () => {} }
macro_rules! foo { (a) => {}; () => {} }
fn f() { fo$0o!(); }
"#,
expect![[r#"
*foo*
*foo*
```rust
test
```
```rust
test
```
```rust
macro_rules! foo
```
"#]],
```rust
macro_rules! foo // matched arm #1
```
"#]],
)
}

Expand All @@ -1590,22 +1590,22 @@ macro foo() {}
fn f() { fo$0o!(); }
"#,
expect![[r#"
*foo*
*foo*
```rust
test
```
```rust
test
```
```rust
macro foo
```
```rust
macro foo // matched arm #0
```
---
---
foo bar
foo bar
foo bar baz
"#]],
foo bar baz
"#]],
)
}

Expand Down
9 changes: 8 additions & 1 deletion src/tools/rust-analyzer/crates/ide/src/static_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,14 @@ impl StaticIndex<'_> {
} else {
let it = self.tokens.insert(TokenStaticData {
documentation: documentation_for_definition(&sema, def, &node),
hover: Some(hover_for_definition(&sema, file_id, def, &node, &hover_config)),
hover: Some(hover_for_definition(
&sema,
file_id,
def,
&node,
None,
&hover_config,
)),
definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
}),
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn benchmark_expand_macro_rules() {
.map(|(id, tt)| {
let res = rules[&id].expand(&tt, |_| (), true, DUMMY, Edition::CURRENT);
assert!(res.err.is_none());
res.value.token_trees.len()
res.value.0.token_trees.len()
})
.sum()
};
Expand Down
Loading

0 comments on commit 30d6e02

Please sign in to comment.