From 210456aeaa44bb970bf4ce28eba3e8c6890bc38d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 9 Oct 2020 19:55:30 +0200 Subject: [PATCH] Treat `ast::Name` in field patterns as use --- crates/ide/src/references.rs | 46 ++++++++++++++ crates/ide_db/src/search.rs | 116 ++++++++++++++++++++++------------- 2 files changed, 119 insertions(+), 43 deletions(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index ae68b4392e..571dd5452c 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -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) } diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index edab1d644d..8e3dcd99c4 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs @@ -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,54 +252,83 @@ 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, - }; - - 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) { + match sema.find_node_at_offset_with_descend(&tree, offset) { + Some(name_ref) => { + if self.found_name_ref(&name_ref, sink) { return; } } - 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), - }, - _ => continue, // not a usage - }; - if sink(reference) { - return; + None => match sema.find_node_at_offset_with_descend(&tree, offset) { + Some(name) => { + if self.found_name(&name, sink) { + return; + } } - } - _ => {} // not a usage + None => {} + }, } } } } + + 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 {