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) {
|
fn check(ra_fixture: &str, expect: Expect) {
|
||||||
check_with_scope(ra_fixture, None, expect)
|
check_with_scope(ra_fixture, None, expect)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,9 @@ use once_cell::unsync::Lazy;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
||||||
|
|
||||||
|
use crate::defs::NameClass;
|
||||||
use crate::{
|
use crate::{
|
||||||
defs::{classify_name_ref, Definition, NameRefClass},
|
defs::{classify_name, classify_name_ref, Definition, NameRefClass},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -226,9 +227,9 @@ impl<'a> FindUsages<'a> {
|
||||||
|
|
||||||
let search_scope = {
|
let search_scope = {
|
||||||
let base = self.def.search_scope(sema.db);
|
let base = self.def.search_scope(sema.db);
|
||||||
match self.scope {
|
match &self.scope {
|
||||||
None => base,
|
None => base,
|
||||||
Some(scope) => base.intersection(&scope),
|
Some(scope) => base.intersection(scope),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -251,54 +252,83 @@ impl<'a> FindUsages<'a> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_ref: ast::NameRef =
|
match sema.find_node_at_offset_with_descend(&tree, offset) {
|
||||||
match sema.find_node_at_offset_with_descend(&tree, offset) {
|
Some(name_ref) => {
|
||||||
Some(it) => it,
|
if self.found_name_ref(&name_ref, sink) {
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
match classify_name_ref(&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)
|
|
||||||
{
|
|
||||||
ReferenceKind::StructLiteral
|
|
||||||
} else {
|
|
||||||
ReferenceKind::Other
|
|
||||||
};
|
|
||||||
|
|
||||||
let reference = Reference {
|
|
||||||
file_range: sema.original_range(name_ref.syntax()),
|
|
||||||
kind,
|
|
||||||
access: reference_access(&def, &name_ref),
|
|
||||||
};
|
|
||||||
if sink(reference) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(NameRefClass::FieldShorthand { local, field }) => {
|
None => match sema.find_node_at_offset_with_descend(&tree, offset) {
|
||||||
let reference = match self.def {
|
Some(name) => {
|
||||||
Definition::Field(_) if &field == self.def => Reference {
|
if self.found_name(&name, sink) {
|
||||||
file_range: self.sema.original_range(name_ref.syntax()),
|
return;
|
||||||
kind: ReferenceKind::FieldShorthandForField,
|
}
|
||||||
access: reference_access(&field, &name_ref),
|
|
||||||
},
|
|
||||||
Definition::Local(l) if &local == l => Reference {
|
|
||||||
file_range: self.sema.original_range(name_ref.syntax()),
|
|
||||||
kind: ReferenceKind::FieldShorthandForLocal,
|
|
||||||
access: reference_access(&Definition::Local(local), &name_ref),
|
|
||||||
},
|
|
||||||
_ => continue, // not a usage
|
|
||||||
};
|
|
||||||
if sink(reference) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
None => {}
|
||||||
_ => {} // not a usage
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ReferenceKind::StructLiteral
|
||||||
|
} else {
|
||||||
|
ReferenceKind::Other
|
||||||
|
};
|
||||||
|
|
||||||
|
let reference = Reference {
|
||||||
|
file_range: self.sema.original_range(name_ref.syntax()),
|
||||||
|
kind,
|
||||||
|
access: reference_access(&def, &name_ref),
|
||||||
|
};
|
||||||
|
sink(reference)
|
||||||
|
}
|
||||||
|
Some(NameRefClass::FieldShorthand { local, field }) => {
|
||||||
|
let reference = match self.def {
|
||||||
|
Definition::Field(_) if &field == self.def => Reference {
|
||||||
|
file_range: self.sema.original_range(name_ref.syntax()),
|
||||||
|
kind: ReferenceKind::FieldShorthandForField,
|
||||||
|
access: reference_access(&field, &name_ref),
|
||||||
|
},
|
||||||
|
Definition::Local(l) if &local == l => Reference {
|
||||||
|
file_range: self.sema.original_range(name_ref.syntax()),
|
||||||
|
kind: ReferenceKind::FieldShorthandForLocal,
|
||||||
|
access: reference_access(&Definition::Local(local), &name_ref),
|
||||||
|
},
|
||||||
|
_ => return false, // not a usage
|
||||||
|
};
|
||||||
|
sink(reference)
|
||||||
|
}
|
||||||
|
_ => false, // 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> {
|
fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> {
|
||||||
|
|
Loading…
Reference in a new issue