Skip to content

Commit b87ee91

Browse files
committed
feat: Highlight used trait assoc items when cursor is on trait import or trait bound
1 parent 2f8cd66 commit b87ee91

File tree

1 file changed

+101
-3
lines changed

1 file changed

+101
-3
lines changed

crates/ide/src/highlight_related.rs

+101-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use ide_db::{
44
defs::{Definition, IdentClass},
55
helpers::pick_best_token,
66
search::{FileReference, ReferenceCategory, SearchScope},
7-
syntax_helpers::node_ext::{for_each_break_and_continue_expr, for_each_tail_expr, walk_expr},
7+
syntax_helpers::node_ext::{
8+
for_each_break_and_continue_expr, for_each_tail_expr, full_path_of_name_ref, walk_expr,
9+
},
810
FxHashSet, RootDatabase,
911
};
1012
use syntax::{
@@ -39,11 +41,13 @@ pub struct HighlightRelatedConfig {
3941
// Highlights constructs related to the thing under the cursor:
4042
//
4143
// . if on an identifier, highlights all references to that identifier in the current file
44+
// .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
4245
// . if on an `async` or `await token, highlights all yield points for that async context
4346
// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
4447
// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
48+
// . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
4549
//
46-
// Note: `?` and `->` do not currently trigger this behavior in the VSCode editor.
50+
// Note: `?`, `|` and `->` do not currently trigger this behavior in the VSCode editor.
4751
pub(crate) fn highlight_related(
4852
sema: &Semantics<'_, RootDatabase>,
4953
config: HighlightRelatedConfig,
@@ -129,7 +133,7 @@ fn highlight_references(
129133
token: SyntaxToken,
130134
file_id: FileId,
131135
) -> Option<Vec<HighlightedRange>> {
132-
let defs = find_defs(sema, token);
136+
let defs = find_defs(sema, token.clone());
133137
let usages = defs
134138
.iter()
135139
.filter_map(|&d| {
@@ -144,6 +148,59 @@ fn highlight_references(
144148
.map(|FileReference { category, range, .. }| HighlightedRange { range, category });
145149
let mut res = FxHashSet::default();
146150
for &def in &defs {
151+
// highlight trait usages
152+
if let Definition::Trait(t) = def {
153+
let trait_item_use_scope = (|| {
154+
let name_ref = token.parent().and_then(ast::NameRef::cast)?;
155+
let path = full_path_of_name_ref(&name_ref)?;
156+
let parent = path.syntax().parent()?;
157+
match_ast! {
158+
match parent {
159+
ast::UseTree(it) => it.syntax().ancestors().find(|it| {
160+
ast::SourceFile::can_cast(it.kind()) || ast::Module::can_cast(it.kind())
161+
}),
162+
ast::PathType(it) => it
163+
.syntax()
164+
.ancestors()
165+
.nth(2)
166+
.and_then(ast::TypeBoundList::cast)?
167+
.syntax()
168+
.parent()
169+
.filter(|it| ast::WhereClause::can_cast(it.kind()) || ast::TypeParam::can_cast(it.kind()))?
170+
.ancestors()
171+
.find(|it| {
172+
ast::Item::can_cast(it.kind())
173+
}),
174+
_ => None,
175+
}
176+
}
177+
})();
178+
if let Some(trait_item_use_scope) = trait_item_use_scope {
179+
res.extend(
180+
t.items_with_supertraits(sema.db)
181+
.into_iter()
182+
.filter_map(|item| {
183+
Definition::from(item)
184+
.usages(sema)
185+
.set_scope(Some(SearchScope::file_range(FileRange {
186+
file_id,
187+
range: trait_item_use_scope.text_range(),
188+
})))
189+
.include_self_refs()
190+
.all()
191+
.references
192+
.remove(&file_id)
193+
})
194+
.flatten()
195+
.map(|FileReference { category, range, .. }| HighlightedRange {
196+
range,
197+
category,
198+
}),
199+
);
200+
}
201+
}
202+
203+
// highlight the defs themselves
147204
match def {
148205
Definition::Local(local) => {
149206
let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write);
@@ -1476,6 +1533,47 @@ fn f() {
14761533
let c = move$0 |y| x + y;
14771534
// ^ read
14781535
}
1536+
"#,
1537+
);
1538+
}
1539+
1540+
#[test]
1541+
fn test_trait_highlights_assoc_item_uses() {
1542+
check(
1543+
r#"
1544+
trait Foo {
1545+
//^^^
1546+
type T;
1547+
const C: usize;
1548+
fn f() {}
1549+
fn m(&self) {}
1550+
}
1551+
impl Foo for i32 {
1552+
//^^^
1553+
type T = i32;
1554+
const C: usize = 0;
1555+
fn f() {}
1556+
fn m(&self) {}
1557+
}
1558+
fn f<T: Foo$0>(t: T) {
1559+
//^^^
1560+
let _: T::T;
1561+
//^
1562+
t.m();
1563+
//^
1564+
T::C;
1565+
//^
1566+
T::f();
1567+
//^
1568+
}
1569+
1570+
fn f2<T: Foo>(t: T) {
1571+
//^^^
1572+
let _: T::T;
1573+
t.m();
1574+
T::C;
1575+
T::f();
1576+
}
14791577
"#,
14801578
);
14811579
}

0 commit comments

Comments
 (0)