Skip to content

Commit 5121359

Browse files
committed
Highlight all related tokens in macro inputs
1 parent c5059e0 commit 5121359

File tree

3 files changed

+99
-27
lines changed

3 files changed

+99
-27
lines changed

crates/hir/src/semantics.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,12 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
166166
self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map)
167167
}
168168

169+
// FIXME: Rename to descend_into_macros_single
169170
pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
170171
self.imp.descend_into_macros(token).pop().unwrap()
171172
}
172173

174+
// FIXME: Rename to descend_into_macros
173175
pub fn descend_into_macros_many(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
174176
self.imp.descend_into_macros(token)
175177
}
@@ -236,6 +238,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
236238
self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
237239
}
238240

241+
/// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
242+
/// descend it and find again
243+
pub fn find_nodes_at_offset_with_descend<'slf, N: AstNode + 'slf>(
244+
&'slf self,
245+
node: &SyntaxNode,
246+
offset: TextSize,
247+
) -> impl Iterator<Item = N> + 'slf {
248+
self.imp.descend_node_at_offset(node, offset).flat_map(N::cast)
249+
}
250+
239251
pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
240252
self.imp.resolve_lifetime_param(lifetime)
241253
}
@@ -482,12 +494,13 @@ impl<'db> SemanticsImpl<'db> {
482494
.as_ref()?
483495
.map_token_down(self.db.upcast(), None, token.as_ref())?;
484496

497+
let len = queue.len();
485498
queue.extend(tokens.inspect(|token| {
486499
if let Some(parent) = token.value.parent() {
487500
self.cache(find_root(&parent), token.file_id);
488501
}
489502
}));
490-
return Some(());
503+
return (queue.len() != len).then(|| ());
491504
},
492505
ast::Item(item) => {
493506
match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) {
@@ -500,12 +513,13 @@ impl<'db> SemanticsImpl<'db> {
500513
.as_ref()?
501514
.map_token_down(self.db.upcast(), None, token.as_ref())?;
502515

516+
let len = queue.len();
503517
queue.extend(tokens.inspect(|token| {
504518
if let Some(parent) = token.value.parent() {
505519
self.cache(find_root(&parent), token.file_id);
506520
}
507521
}));
508-
return Some(());
522+
return (queue.len() != len).then(|| ());
509523
}
510524
None => {}
511525
}

crates/ide/src/highlight_related.rs

Lines changed: 82 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use ide_db::{
66
search::{FileReference, ReferenceAccess, SearchScope},
77
RootDatabase,
88
};
9+
use itertools::Itertools;
910
use syntax::{
1011
ast::{self, LoopBodyOwner},
1112
match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, T,
@@ -70,7 +71,7 @@ fn highlight_references(
7071
syntax: &SyntaxNode,
7172
FilePosition { offset, file_id }: FilePosition,
7273
) -> Option<Vec<HighlightedRange>> {
73-
let defs = find_defs(sema, syntax, offset)?;
74+
let defs = find_defs(sema, syntax, offset);
7475
let usages = defs
7576
.iter()
7677
.flat_map(|&d| {
@@ -99,7 +100,12 @@ fn highlight_references(
99100
})
100101
});
101102

102-
Some(declarations.chain(usages).collect())
103+
let res: Vec<_> = declarations.chain(usages).collect();
104+
if res.is_empty() {
105+
None
106+
} else {
107+
Some(res)
108+
}
103109
}
104110

105111
fn highlight_exit_points(
@@ -270,29 +276,41 @@ fn find_defs(
270276
sema: &Semantics<RootDatabase>,
271277
syntax: &SyntaxNode,
272278
offset: TextSize,
273-
) -> Option<Vec<Definition>> {
274-
let defs = match sema.find_node_at_offset_with_descend(syntax, offset)? {
275-
ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
276-
NameRefClass::Definition(def) => vec![def],
277-
NameRefClass::FieldShorthand { local_ref, field_ref } => {
278-
vec![Definition::Local(local_ref), Definition::Field(field_ref)]
279-
}
280-
},
281-
ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
282-
NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
283-
NameClass::PatFieldShorthand { local_def, field_ref } => {
284-
vec![Definition::Local(local_def), Definition::Field(field_ref)]
285-
}
286-
},
287-
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
288-
.and_then(|class| match class {
289-
NameRefClass::Definition(it) => Some(it),
290-
_ => None,
279+
) -> Vec<Definition> {
280+
sema.find_nodes_at_offset_with_descend(syntax, offset)
281+
.flat_map(|name_like| {
282+
Some(match name_like {
283+
ast::NameLike::NameRef(name_ref) => {
284+
match NameRefClass::classify(sema, &name_ref)? {
285+
NameRefClass::Definition(def) => vec![def],
286+
NameRefClass::FieldShorthand { local_ref, field_ref } => {
287+
vec![Definition::Local(local_ref), Definition::Field(field_ref)]
288+
}
289+
}
290+
}
291+
ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
292+
NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
293+
NameClass::PatFieldShorthand { local_def, field_ref } => {
294+
vec![Definition::Local(local_def), Definition::Field(field_ref)]
295+
}
296+
},
297+
ast::NameLike::Lifetime(lifetime) => {
298+
NameRefClass::classify_lifetime(sema, &lifetime)
299+
.and_then(|class| match class {
300+
NameRefClass::Definition(it) => Some(it),
301+
_ => None,
302+
})
303+
.or_else(|| {
304+
NameClass::classify_lifetime(sema, &lifetime)
305+
.and_then(NameClass::defined)
306+
})
307+
.map(|it| vec![it])?
308+
}
291309
})
292-
.or_else(|| NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined))
293-
.map(|it| vec![it])?,
294-
};
295-
Some(defs)
310+
})
311+
.flatten()
312+
.unique()
313+
.collect()
296314
}
297315

298316
#[cfg(test)]
@@ -392,6 +410,46 @@ fn foo() {
392410
);
393411
}
394412

413+
#[test]
414+
fn test_multi_macro_usage() {
415+
check(
416+
r#"
417+
macro_rules! foo {
418+
($ident:ident) => {
419+
fn $ident() -> $ident { loop {} }
420+
struct $ident;
421+
}
422+
}
423+
424+
foo!(bar$0);
425+
// ^^^
426+
// ^^^
427+
fn foo() {
428+
let bar: bar = bar();
429+
// ^^^
430+
// ^^^
431+
}
432+
"#,
433+
);
434+
check(
435+
r#"
436+
macro_rules! foo {
437+
($ident:ident) => {
438+
fn $ident() -> $ident { loop {} }
439+
struct $ident;
440+
}
441+
}
442+
443+
foo!(bar);
444+
// ^^^
445+
fn foo() {
446+
let bar: bar$0 = bar();
447+
// ^^^
448+
}
449+
"#,
450+
);
451+
}
452+
395453
#[test]
396454
fn test_hl_yield_points() {
397455
check(

crates/ide_db/src/defs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use syntax::{
1717
use crate::RootDatabase;
1818

1919
// FIXME: a more precise name would probably be `Symbol`?
20-
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
20+
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
2121
pub enum Definition {
2222
Macro(MacroDef),
2323
Field(Field),

0 commit comments

Comments
 (0)