mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 17:28:09 +00:00
Auto merge of #14812 - Veykril:highlight-trait-assoc, r=HKalbasi
feat: Highlight used trait assoc items when cursor is on trait import or trait bound
This commit is contained in:
commit
d0768aad62
1 changed files with 101 additions and 3 deletions
|
@ -4,7 +4,9 @@ use ide_db::{
|
|||
defs::{Definition, IdentClass},
|
||||
helpers::pick_best_token,
|
||||
search::{FileReference, ReferenceCategory, SearchScope},
|
||||
syntax_helpers::node_ext::{for_each_break_and_continue_expr, for_each_tail_expr, walk_expr},
|
||||
syntax_helpers::node_ext::{
|
||||
for_each_break_and_continue_expr, for_each_tail_expr, full_path_of_name_ref, walk_expr,
|
||||
},
|
||||
FxHashSet, RootDatabase,
|
||||
};
|
||||
use syntax::{
|
||||
|
@ -39,11 +41,13 @@ pub struct HighlightRelatedConfig {
|
|||
// Highlights constructs related to the thing under the cursor:
|
||||
//
|
||||
// . if on an identifier, highlights all references to that identifier in the current file
|
||||
// .. 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
|
||||
// . if on an `async` or `await token, highlights all yield points for that async context
|
||||
// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
|
||||
// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
|
||||
// . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
|
||||
//
|
||||
// Note: `?` and `->` do not currently trigger this behavior in the VSCode editor.
|
||||
// Note: `?`, `|` and `->` do not currently trigger this behavior in the VSCode editor.
|
||||
pub(crate) fn highlight_related(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
config: HighlightRelatedConfig,
|
||||
|
@ -130,7 +134,7 @@ fn highlight_references(
|
|||
token: SyntaxToken,
|
||||
file_id: FileId,
|
||||
) -> Option<Vec<HighlightedRange>> {
|
||||
let defs = find_defs(sema, token);
|
||||
let defs = find_defs(sema, token.clone());
|
||||
let usages = defs
|
||||
.iter()
|
||||
.filter_map(|&d| {
|
||||
|
@ -145,6 +149,59 @@ fn highlight_references(
|
|||
.map(|FileReference { category, range, .. }| HighlightedRange { range, category });
|
||||
let mut res = FxHashSet::default();
|
||||
for &def in &defs {
|
||||
// highlight trait usages
|
||||
if let Definition::Trait(t) = def {
|
||||
let trait_item_use_scope = (|| {
|
||||
let name_ref = token.parent().and_then(ast::NameRef::cast)?;
|
||||
let path = full_path_of_name_ref(&name_ref)?;
|
||||
let parent = path.syntax().parent()?;
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::UseTree(it) => it.syntax().ancestors().find(|it| {
|
||||
ast::SourceFile::can_cast(it.kind()) || ast::Module::can_cast(it.kind())
|
||||
}),
|
||||
ast::PathType(it) => it
|
||||
.syntax()
|
||||
.ancestors()
|
||||
.nth(2)
|
||||
.and_then(ast::TypeBoundList::cast)?
|
||||
.syntax()
|
||||
.parent()
|
||||
.filter(|it| ast::WhereClause::can_cast(it.kind()) || ast::TypeParam::can_cast(it.kind()))?
|
||||
.ancestors()
|
||||
.find(|it| {
|
||||
ast::Item::can_cast(it.kind())
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
})();
|
||||
if let Some(trait_item_use_scope) = trait_item_use_scope {
|
||||
res.extend(
|
||||
t.items_with_supertraits(sema.db)
|
||||
.into_iter()
|
||||
.filter_map(|item| {
|
||||
Definition::from(item)
|
||||
.usages(sema)
|
||||
.set_scope(Some(SearchScope::file_range(FileRange {
|
||||
file_id,
|
||||
range: trait_item_use_scope.text_range(),
|
||||
})))
|
||||
.include_self_refs()
|
||||
.all()
|
||||
.references
|
||||
.remove(&file_id)
|
||||
})
|
||||
.flatten()
|
||||
.map(|FileReference { category, range, .. }| HighlightedRange {
|
||||
range,
|
||||
category,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// highlight the defs themselves
|
||||
match def {
|
||||
Definition::Local(local) => {
|
||||
let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write);
|
||||
|
@ -1477,6 +1534,47 @@ fn f() {
|
|||
let c = move$0 |y| x + y;
|
||||
// ^ read
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trait_highlights_assoc_item_uses() {
|
||||
check(
|
||||
r#"
|
||||
trait Foo {
|
||||
//^^^
|
||||
type T;
|
||||
const C: usize;
|
||||
fn f() {}
|
||||
fn m(&self) {}
|
||||
}
|
||||
impl Foo for i32 {
|
||||
//^^^
|
||||
type T = i32;
|
||||
const C: usize = 0;
|
||||
fn f() {}
|
||||
fn m(&self) {}
|
||||
}
|
||||
fn f<T: Foo$0>(t: T) {
|
||||
//^^^
|
||||
let _: T::T;
|
||||
//^
|
||||
t.m();
|
||||
//^
|
||||
T::C;
|
||||
//^
|
||||
T::f();
|
||||
//^
|
||||
}
|
||||
|
||||
fn f2<T: Foo>(t: T) {
|
||||
//^^^
|
||||
let _: T::T;
|
||||
t.m();
|
||||
T::C;
|
||||
T::f();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue