mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Treat ast::Name
in field patterns as use
This commit is contained in:
parent
95c498d913
commit
210456aeaa
2 changed files with 119 additions and 43 deletions
|
@ -686,6 +686,52 @@ fn g() { f(); }
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_all_refs_struct_pat() {
|
||||
check(
|
||||
r#"
|
||||
struct S {
|
||||
field<|>: u8,
|
||||
}
|
||||
|
||||
fn f(s: S) {
|
||||
match s {
|
||||
S { field } => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
field RECORD_FIELD FileId(0) 15..24 15..20 Other
|
||||
|
||||
FileId(0) 68..73 FieldShorthandForField Read
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_all_refs_enum_var_pat() {
|
||||
check(
|
||||
r#"
|
||||
enum En {
|
||||
Variant {
|
||||
field<|>: u8,
|
||||
}
|
||||
}
|
||||
|
||||
fn f(e: En) {
|
||||
match e {
|
||||
En::Variant { field } => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
field RECORD_FIELD FileId(0) 32..41 32..37 Other
|
||||
|
||||
FileId(0) 102..107 FieldShorthandForField Read
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
check_with_scope(ra_fixture, None, expect)
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ use once_cell::unsync::Lazy;
|
|||
use rustc_hash::FxHashMap;
|
||||
use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
||||
|
||||
use crate::defs::NameClass;
|
||||
use crate::{
|
||||
defs::{classify_name_ref, Definition, NameRefClass},
|
||||
defs::{classify_name, classify_name_ref, Definition, NameRefClass},
|
||||
RootDatabase,
|
||||
};
|
||||
|
||||
|
@ -226,9 +227,9 @@ impl<'a> FindUsages<'a> {
|
|||
|
||||
let search_scope = {
|
||||
let base = self.def.search_scope(sema.db);
|
||||
match self.scope {
|
||||
match &self.scope {
|
||||
None => base,
|
||||
Some(scope) => base.intersection(&scope),
|
||||
Some(scope) => base.intersection(scope),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -251,16 +252,33 @@ impl<'a> FindUsages<'a> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let name_ref: ast::NameRef =
|
||||
match sema.find_node_at_offset_with_descend(&tree, offset) {
|
||||
Some(it) => it,
|
||||
None => continue,
|
||||
};
|
||||
Some(name_ref) => {
|
||||
if self.found_name_ref(&name_ref, sink) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
None => match sema.find_node_at_offset_with_descend(&tree, offset) {
|
||||
Some(name) => {
|
||||
if self.found_name(&name, sink) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match classify_name_ref(&sema, &name_ref) {
|
||||
fn found_name_ref(
|
||||
&self,
|
||||
name_ref: &ast::NameRef,
|
||||
sink: &mut dyn FnMut(Reference) -> bool,
|
||||
) -> bool {
|
||||
match classify_name_ref(self.sema, &name_ref) {
|
||||
Some(NameRefClass::Definition(def)) if &def == self.def => {
|
||||
let kind = if is_record_lit_name_ref(&name_ref)
|
||||
|| is_call_expr_name_ref(&name_ref)
|
||||
let kind = if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref)
|
||||
{
|
||||
ReferenceKind::StructLiteral
|
||||
} else {
|
||||
|
@ -268,13 +286,11 @@ impl<'a> FindUsages<'a> {
|
|||
};
|
||||
|
||||
let reference = Reference {
|
||||
file_range: sema.original_range(name_ref.syntax()),
|
||||
file_range: self.sema.original_range(name_ref.syntax()),
|
||||
kind,
|
||||
access: reference_access(&def, &name_ref),
|
||||
};
|
||||
if sink(reference) {
|
||||
return;
|
||||
}
|
||||
sink(reference)
|
||||
}
|
||||
Some(NameRefClass::FieldShorthand { local, field }) => {
|
||||
let reference = match self.def {
|
||||
|
@ -288,15 +304,29 @@ impl<'a> FindUsages<'a> {
|
|||
kind: ReferenceKind::FieldShorthandForLocal,
|
||||
access: reference_access(&Definition::Local(local), &name_ref),
|
||||
},
|
||||
_ => continue, // not a usage
|
||||
_ => return false, // not a usage
|
||||
};
|
||||
if sink(reference) {
|
||||
return;
|
||||
sink(reference)
|
||||
}
|
||||
_ => false, // not a usage
|
||||
}
|
||||
}
|
||||
_ => {} // not a usage
|
||||
}
|
||||
|
||||
fn found_name(&self, name: &ast::Name, sink: &mut dyn FnMut(Reference) -> bool) -> bool {
|
||||
match classify_name(self.sema, name) {
|
||||
Some(NameClass::FieldShorthand { local: _, field }) => {
|
||||
let reference = match self.def {
|
||||
Definition::Field(_) if &field == self.def => Reference {
|
||||
file_range: self.sema.original_range(name.syntax()),
|
||||
kind: ReferenceKind::FieldShorthandForField,
|
||||
// FIXME: mutable patterns should have `Write` access
|
||||
access: Some(ReferenceAccess::Read),
|
||||
},
|
||||
_ => return false, // not a usage
|
||||
};
|
||||
sink(reference)
|
||||
}
|
||||
_ => false, // not a usage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue