Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-expand/src/db.rs39
-rw-r--r--crates/hir-expand/src/declarative.rs6
-rw-r--r--crates/hir/src/semantics.rs11
-rw-r--r--crates/ide/src/hover.rs45
-rw-r--r--crates/ide/src/hover/render.rs8
-rw-r--r--crates/ide/src/hover/tests.rs40
-rw-r--r--crates/ide/src/static_index.rs9
-rw-r--r--crates/mbe/src/benchmark.rs2
-rw-r--r--crates/mbe/src/expander.rs29
-rw-r--r--crates/mbe/src/lib.rs6
-rw-r--r--crates/span/src/map.rs3
11 files changed, 133 insertions, 65 deletions
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 97fa9cf2cc..33c0373e48 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -313,9 +313,10 @@ 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,
@@ -323,6 +324,7 @@ fn parse_macro_expansion(
expand_to,
edition,
);
+ rev_token_map.matched_arm = matched_arm;
ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
}
@@ -544,11 +546,13 @@ fn macro_expand(
db: &dyn ExpandDatabase,
macro_call_id: MacroCallId,
loc: MacroCallLoc,
-) -> ExpandResult<CowArc<tt::Subtree>> {
+) -> ExpandResult<(CowArc<tt::Subtree>, Option<u32>)> {
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);
@@ -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.
@@ -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,
@@ -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!(),
};
@@ -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 {
diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs
index f9ea8e2ea5..66465ce600 100644
--- a/crates/hir-expand/src/declarative.rs
+++ b/crates/hir-expand/src/declarative.rs
@@ -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;
@@ -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| {
@@ -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
@@ -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),
}
}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index e1516fcdcb..e792e159ac 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -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,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 822751c0e4..95de3c88c8 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -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::{
@@ -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))
});
}
@@ -162,6 +162,7 @@ fn hover_simple(
file_id,
Definition::from(resolution?),
&original_token.parent()?,
+ None,
config,
);
return Some(RangeInfo::new(range, res));
@@ -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
@@ -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));
@@ -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 {
@@ -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: [
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 7579d4d6d8..3f0fc85134 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -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);
@@ -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);
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 67f10f0374..6bbc8b380d 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -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
+ ```
+ "#]],
)
}
@@ -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
+ "#]],
)
}
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 3fef16df25..ca013da709 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -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() }
}),
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index 1dca288017..f4bbaef7af 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -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()
};
diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs
index 2d495da0db..b1468e5bef 100644
--- a/crates/mbe/src/expander.rs
+++ b/crates/mbe/src/expander.rs
@@ -18,9 +18,9 @@ pub(crate) fn expand_rules(
new_meta_vars: bool,
call_site: Span,
def_site_edition: Edition,
-) -> ExpandResult<tt::Subtree<Span>> {
- let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
- for rule in rules {
+) -> ExpandResult<(tt::Subtree<Span>, Option<u32>)> {
+ let mut match_: Option<(matcher::Match, &crate::Rule, usize)> = None;
+ for (idx, rule) in rules.iter().enumerate() {
let new_match = matcher::match_(&rule.lhs, input, def_site_edition);
if new_match.err.is_none() {
@@ -35,31 +35,34 @@ pub(crate) fn expand_rules(
call_site,
);
if transcribe_err.is_none() {
- return ExpandResult::ok(value);
+ return ExpandResult::ok((value, Some(idx as u32)));
}
}
// Use the rule if we matched more tokens, or bound variables count
- if let Some((prev_match, _)) = &match_ {
+ if let Some((prev_match, _, _)) = &match_ {
if (new_match.unmatched_tts, -(new_match.bound_count as i32))
< (prev_match.unmatched_tts, -(prev_match.bound_count as i32))
{
- match_ = Some((new_match, rule));
+ match_ = Some((new_match, rule, idx));
}
} else {
- match_ = Some((new_match, rule));
+ match_ = Some((new_match, rule, idx));
}
}
- if let Some((match_, rule)) = match_ {
+ if let Some((match_, rule, idx)) = match_ {
// if we got here, there was no match without errors
let ExpandResult { value, err: transcribe_err } =
transcriber::transcribe(&rule.rhs, &match_.bindings, marker, new_meta_vars, call_site);
- ExpandResult { value, err: match_.err.or(transcribe_err) }
+ ExpandResult { value: (value, Some(idx as u32)), err: match_.err.or(transcribe_err) }
} else {
ExpandResult::new(
- tt::Subtree {
- delimiter: tt::Delimiter::invisible_spanned(call_site),
- token_trees: Box::new([]),
- },
+ (
+ tt::Subtree {
+ delimiter: tt::Delimiter::invisible_spanned(call_site),
+ token_trees: Box::default(),
+ },
+ None,
+ ),
ExpandError::NoMatchingRule,
)
}
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 5445f8790f..77e6490317 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -251,7 +251,7 @@ impl DeclarativeMacro {
new_meta_vars: bool,
call_site: Span,
def_site_edition: Edition,
- ) -> ExpandResult<tt::Subtree<Span>> {
+ ) -> ExpandResult<(tt::Subtree<Span>, Option<u32>)> {
expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site, def_site_edition)
}
}
@@ -330,6 +330,10 @@ impl<T, E> ValueResult<T, E> {
Self { value: Default::default(), err: Some(err) }
}
+ pub fn zip_val<U>(self, other: U) -> ValueResult<(T, U), E> {
+ ValueResult { value: (self.value, other), err: self.err }
+ }
+
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ValueResult<U, E> {
ValueResult { value: f(self.value), err: self.err }
}
diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs
index 6d8c9c30fb..e769b6420e 100644
--- a/crates/span/src/map.rs
+++ b/crates/span/src/map.rs
@@ -15,6 +15,7 @@ use crate::{
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct SpanMap<S> {
spans: Vec<(TextSize, SpanData<S>)>,
+ pub matched_arm: Option<u32>,
}
impl<S> SpanMap<S>
@@ -23,7 +24,7 @@ where
{
/// Creates a new empty [`SpanMap`].
pub fn empty() -> Self {
- Self { spans: Vec::new() }
+ Self { spans: Vec::new(), matched_arm: None }
}
/// Finalizes the [`SpanMap`], shrinking its backing storage and validating that the offsets are