Highlight declarations and references for both defs in field shorthands

This commit is contained in:
Lukas Wirth 2021-08-24 03:14:03 +02:00
parent ced65f77c4
commit 631bca786f
2 changed files with 74 additions and 31 deletions

View file

@ -1,14 +1,14 @@
use hir::Semantics; use hir::Semantics;
use ide_db::{ use ide_db::{
base_db::FilePosition, base_db::FilePosition,
defs::Definition, defs::{Definition, NameClass, NameRefClass},
helpers::{for_each_break_expr, for_each_tail_expr, pick_best_token}, helpers::{for_each_break_expr, for_each_tail_expr, pick_best_token},
search::{FileReference, ReferenceAccess, SearchScope}, search::{FileReference, ReferenceAccess, SearchScope},
RootDatabase, RootDatabase,
}; };
use syntax::{ use syntax::{
ast::{self, LoopBodyOwner}, ast::{self, LoopBodyOwner},
match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, T, match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, T,
}; };
use crate::{display::TryToNav, references, NavigationTarget}; use crate::{display::TryToNav, references, NavigationTarget};
@ -70,35 +70,36 @@ fn highlight_references(
syntax: &SyntaxNode, syntax: &SyntaxNode,
FilePosition { offset, file_id }: FilePosition, FilePosition { offset, file_id }: FilePosition,
) -> Option<Vec<HighlightedRange>> { ) -> Option<Vec<HighlightedRange>> {
let def = references::find_def(sema, syntax, offset)?; let defs = find_defs(sema, syntax, offset)?;
let usages = def let usages = defs
.usages(sema) .iter()
.set_scope(Some(SearchScope::single_file(file_id))) .flat_map(|&d| {
.include_self_refs() d.usages(sema)
.all(); .set_scope(Some(SearchScope::single_file(file_id)))
.include_self_refs()
.all()
.references
.remove(&file_id)
})
.flatten()
.map(|FileReference { access, range, .. }| HighlightedRange { range, access });
let declaration = match def { let declarations = defs.iter().flat_map(|def| {
Definition::ModuleDef(hir::ModuleDef::Module(module)) => { match def {
Some(NavigationTarget::from_module_to_decl(sema.db, module)) &Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
Some(NavigationTarget::from_module_to_decl(sema.db, module))
}
def => def.try_to_nav(sema.db),
} }
def => def.try_to_nav(sema.db), .filter(|decl| decl.file_id == file_id)
} .and_then(|decl| {
.filter(|decl| decl.file_id == file_id) let range = decl.focus_range?;
.and_then(|decl| { let access = references::decl_access(&def, syntax, range);
let range = decl.focus_range?; Some(HighlightedRange { range, access })
let access = references::decl_access(&def, syntax, range); })
Some(HighlightedRange { range, access })
}); });
let file_refs = usages.references.get(&file_id).map_or(&[][..], Vec::as_slice); Some(declarations.chain(usages).collect())
let mut res = Vec::with_capacity(file_refs.len() + 1);
res.extend(declaration);
res.extend(
file_refs
.iter()
.map(|&FileReference { access, range, .. }| HighlightedRange { range, access }),
);
Some(res)
} }
fn highlight_exit_points( fn highlight_exit_points(
@ -265,6 +266,35 @@ fn cover_range(r0: Option<TextRange>, r1: Option<TextRange>) -> Option<TextRange
} }
} }
fn find_defs(
sema: &Semantics<RootDatabase>,
syntax: &SyntaxNode,
offset: TextSize,
) -> Option<Vec<Definition>> {
let defs = match sema.find_node_at_offset_with_descend(syntax, offset)? {
ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
NameRefClass::Definition(def) => vec![def],
NameRefClass::FieldShorthand { local_ref, field_ref } => {
vec![Definition::Local(local_ref), Definition::Field(field_ref)]
}
},
ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
NameClass::PatFieldShorthand { local_def, field_ref } => {
vec![Definition::Local(local_def), Definition::Field(field_ref)]
}
},
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
.and_then(|class| match class {
NameRefClass::Definition(it) => Some(it),
_ => None,
})
.or_else(|| NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined))
.map(|it| vec![it])?,
};
Some(defs)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::fixture; use crate::fixture;
@ -773,6 +803,22 @@ fn foo() {
); );
} }
#[test]
fn test_hl_field_shorthand() {
check(
r#"
struct Struct { field: u32 }
//^^^^^
fn function(field: u32) {
//^^^^^
Struct { field$0 }
//^^^^^ read
//^^^^^ read
}
"#,
);
}
#[test] #[test]
fn test_hl_disabled_ref_local() { fn test_hl_disabled_ref_local() {
let config = HighlightRelatedConfig { let config = HighlightRelatedConfig {

View file

@ -118,10 +118,7 @@ pub(crate) fn find_def(
_ => None, _ => None,
}) })
.or_else(|| { .or_else(|| {
NameClass::classify_lifetime(sema, &lifetime).and_then(|class| match class { NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined)
NameClass::Definition(it) => Some(it),
_ => None,
})
})?, })?,
}; };
Some(def) Some(def)