mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Highlight declarations and references for both defs in field shorthands
This commit is contained in:
parent
ced65f77c4
commit
631bca786f
2 changed files with 74 additions and 31 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue