Skip to content

Commit d0768aa

Browse files
committed
Auto merge of rust-lang#14812 - Veykril:highlight-trait-assoc, r=HKalbasi
feat: Highlight used trait assoc items when cursor is on trait import or trait bound
2 parents 88d2125 + b87ee91 commit d0768aa

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,
@@ -130,7 +134,7 @@ fn highlight_references(
130134
token: SyntaxToken,
131135
file_id: FileId,
132136
) -> Option<Vec<HighlightedRange>> {
133-
let defs = find_defs(sema, token);
137+
let defs = find_defs(sema, token.clone());
134138
let usages = defs
135139
.iter()
136140
.filter_map(|&d| {
@@ -145,6 +149,59 @@ fn highlight_references(
145149
.map(|FileReference { category, range, .. }| HighlightedRange { range, category });
146150
let mut res = FxHashSet::default();
147151
for &def in &defs {
152+
// highlight trait usages
153+
if let Definition::Trait(t) = def {
154+
let trait_item_use_scope = (|| {
155+
let name_ref = token.parent().and_then(ast::NameRef::cast)?;
156+
let path = full_path_of_name_ref(&name_ref)?;
157+
let parent = path.syntax().parent()?;
158+
match_ast! {
159+
match parent {
160+
ast::UseTree(it) => it.syntax().ancestors().find(|it| {
161+
ast::SourceFile::can_cast(it.kind()) || ast::Module::can_cast(it.kind())
162+
}),
163+
ast::PathType(it) => it
164+
.syntax()
165+
.ancestors()
166+
.nth(2)
167+
.and_then(ast::TypeBoundList::cast)?
168+
.syntax()
169+
.parent()
170+
.filter(|it| ast::WhereClause::can_cast(it.kind()) || ast::TypeParam::can_cast(it.kind()))?
171+
.ancestors()
172+
.find(|it| {
173+
ast::Item::can_cast(it.kind())
174+
}),
175+
_ => None,
176+
}
177+
}
178+
})();
179+
if let Some(trait_item_use_scope) = trait_item_use_scope {
180+
res.extend(
181+
t.items_with_supertraits(sema.db)
182+
.into_iter()
183+
.filter_map(|item| {
184+
Definition::from(item)
185+
.usages(sema)
186+
.set_scope(Some(SearchScope::file_range(FileRange {
187+
file_id,
188+
range: trait_item_use_scope.text_range(),
189+
})))
190+
.include_self_refs()
191+
.all()
192+
.references
193+
.remove(&file_id)
194+
})
195+
.flatten()
196+
.map(|FileReference { category, range, .. }| HighlightedRange {
197+
range,
198+
category,
199+
}),
200+
);
201+
}
202+
}
203+
204+
// highlight the defs themselves
148205
match def {
149206
Definition::Local(local) => {
150207
let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write);
@@ -1477,6 +1534,47 @@ fn f() {
14771534
let c = move$0 |y| x + y;
14781535
// ^ read
14791536
}
1537+
"#,
1538+
);
1539+
}
1540+
1541+
#[test]
1542+
fn test_trait_highlights_assoc_item_uses() {
1543+
check(
1544+
r#"
1545+
trait Foo {
1546+
//^^^
1547+
type T;
1548+
const C: usize;
1549+
fn f() {}
1550+
fn m(&self) {}
1551+
}
1552+
impl Foo for i32 {
1553+
//^^^
1554+
type T = i32;
1555+
const C: usize = 0;
1556+
fn f() {}
1557+
fn m(&self) {}
1558+
}
1559+
fn f<T: Foo$0>(t: T) {
1560+
//^^^
1561+
let _: T::T;
1562+
//^
1563+
t.m();
1564+
//^
1565+
T::C;
1566+
//^
1567+
T::f();
1568+
//^
1569+
}
1570+
1571+
fn f2<T: Foo>(t: T) {
1572+
//^^^
1573+
let _: T::T;
1574+
t.m();
1575+
T::C;
1576+
T::f();
1577+
}
14801578
"#,
14811579
);
14821580
}

0 commit comments

Comments
 (0)