diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-01-08 14:33:05 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-01-08 14:33:05 +0000 |
commit | 928ecd069a508845ef4dbfd1bc1b9bf975d76e5b (patch) | |
tree | ec7d616010741522ac4718ff472e8fc6307b2d24 /crates/ra_ide | |
parent | 5d8f2bd822c1e9384ef547c781ccc26a6dec63e2 (diff) | |
parent | fb25c919793cc9aafbe57f61cd74d18146163ada (diff) |
Merge #2738
2738: [Draft] Adds a way to limits reference search by StructLiteral r=matklad a=mikhail-m1
first draft for #2549
Co-authored-by: Mikhail Modin <[email protected]>
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/references.rs | 95 | ||||
-rw-r--r-- | crates/ra_ide/src/references/rename.rs | 8 |
2 files changed, 91 insertions, 12 deletions
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index e3ecde50d..a0226b1bc 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -18,7 +18,10 @@ use hir::InFile; | |||
18 | use once_cell::unsync::Lazy; | 18 | use once_cell::unsync::Lazy; |
19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; |
20 | use ra_prof::profile; | 20 | use ra_prof::profile; |
21 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; | 21 | use ra_syntax::{ |
22 | algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextUnit, | ||
23 | TokenAtOffset, | ||
24 | }; | ||
22 | 25 | ||
23 | use crate::{ | 26 | use crate::{ |
24 | db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, | 27 | db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, |
@@ -35,7 +38,20 @@ pub use self::search_scope::SearchScope; | |||
35 | #[derive(Debug, Clone)] | 38 | #[derive(Debug, Clone)] |
36 | pub struct ReferenceSearchResult { | 39 | pub struct ReferenceSearchResult { |
37 | declaration: NavigationTarget, | 40 | declaration: NavigationTarget, |
38 | references: Vec<FileRange>, | 41 | declaration_kind: ReferenceKind, |
42 | references: Vec<Reference>, | ||
43 | } | ||
44 | |||
45 | #[derive(Debug, Clone)] | ||
46 | pub struct Reference { | ||
47 | pub file_range: FileRange, | ||
48 | pub kind: ReferenceKind, | ||
49 | } | ||
50 | |||
51 | #[derive(Debug, Clone, PartialEq)] | ||
52 | pub enum ReferenceKind { | ||
53 | StructLiteral, | ||
54 | Other, | ||
39 | } | 55 | } |
40 | 56 | ||
41 | impl ReferenceSearchResult { | 57 | impl ReferenceSearchResult { |
@@ -43,7 +59,7 @@ impl ReferenceSearchResult { | |||
43 | &self.declaration | 59 | &self.declaration |
44 | } | 60 | } |
45 | 61 | ||
46 | pub fn references(&self) -> &[FileRange] { | 62 | pub fn references(&self) -> &[Reference] { |
47 | &self.references | 63 | &self.references |
48 | } | 64 | } |
49 | 65 | ||
@@ -58,12 +74,18 @@ impl ReferenceSearchResult { | |||
58 | // allow turning ReferenceSearchResult into an iterator | 74 | // allow turning ReferenceSearchResult into an iterator |
59 | // over FileRanges | 75 | // over FileRanges |
60 | impl IntoIterator for ReferenceSearchResult { | 76 | impl IntoIterator for ReferenceSearchResult { |
61 | type Item = FileRange; | 77 | type Item = Reference; |
62 | type IntoIter = std::vec::IntoIter<FileRange>; | 78 | type IntoIter = std::vec::IntoIter<Reference>; |
63 | 79 | ||
64 | fn into_iter(mut self) -> Self::IntoIter { | 80 | fn into_iter(mut self) -> Self::IntoIter { |
65 | let mut v = Vec::with_capacity(self.len()); | 81 | let mut v = Vec::with_capacity(self.len()); |
66 | v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() }); | 82 | v.push(Reference { |
83 | file_range: FileRange { | ||
84 | file_id: self.declaration.file_id(), | ||
85 | range: self.declaration.range(), | ||
86 | }, | ||
87 | kind: self.declaration_kind, | ||
88 | }); | ||
67 | v.append(&mut self.references); | 89 | v.append(&mut self.references); |
68 | v.into_iter() | 90 | v.into_iter() |
69 | } | 91 | } |
@@ -71,11 +93,24 @@ impl IntoIterator for ReferenceSearchResult { | |||
71 | 93 | ||
72 | pub(crate) fn find_all_refs( | 94 | pub(crate) fn find_all_refs( |
73 | db: &RootDatabase, | 95 | db: &RootDatabase, |
74 | position: FilePosition, | 96 | mut position: FilePosition, |
75 | search_scope: Option<SearchScope>, | 97 | search_scope: Option<SearchScope>, |
76 | ) -> Option<RangeInfo<ReferenceSearchResult>> { | 98 | ) -> Option<RangeInfo<ReferenceSearchResult>> { |
77 | let parse = db.parse(position.file_id); | 99 | let parse = db.parse(position.file_id); |
78 | let syntax = parse.tree().syntax().clone(); | 100 | let syntax = parse.tree().syntax().clone(); |
101 | |||
102 | let token = syntax.token_at_offset(position.offset); | ||
103 | let mut search_kind = ReferenceKind::Other; | ||
104 | |||
105 | if let TokenAtOffset::Between(ref left, ref right) = token { | ||
106 | if (right.kind() == SyntaxKind::L_CURLY || right.kind() == SyntaxKind::L_PAREN) | ||
107 | && left.kind() != SyntaxKind::IDENT | ||
108 | { | ||
109 | position = FilePosition { offset: left.text_range().start(), ..position }; | ||
110 | search_kind = ReferenceKind::StructLiteral; | ||
111 | } | ||
112 | } | ||
113 | |||
79 | let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; | 114 | let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; |
80 | 115 | ||
81 | let declaration = match def.kind { | 116 | let declaration = match def.kind { |
@@ -96,9 +131,15 @@ pub(crate) fn find_all_refs( | |||
96 | } | 131 | } |
97 | }; | 132 | }; |
98 | 133 | ||
99 | let references = process_definition(db, def, name, search_scope); | 134 | let references = process_definition(db, def, name, search_scope) |
135 | .into_iter() | ||
136 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) | ||
137 | .collect(); | ||
100 | 138 | ||
101 | Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) | 139 | Some(RangeInfo::new( |
140 | range, | ||
141 | ReferenceSearchResult { declaration, references, declaration_kind: ReferenceKind::Other }, | ||
142 | )) | ||
102 | } | 143 | } |
103 | 144 | ||
104 | fn find_name<'a>( | 145 | fn find_name<'a>( |
@@ -122,7 +163,7 @@ fn process_definition( | |||
122 | def: NameDefinition, | 163 | def: NameDefinition, |
123 | name: String, | 164 | name: String, |
124 | scope: SearchScope, | 165 | scope: SearchScope, |
125 | ) -> Vec<FileRange> { | 166 | ) -> Vec<Reference> { |
126 | let _p = profile("process_definition"); | 167 | let _p = profile("process_definition"); |
127 | 168 | ||
128 | let pat = name.as_str(); | 169 | let pat = name.as_str(); |
@@ -146,7 +187,21 @@ fn process_definition( | |||
146 | } | 187 | } |
147 | if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) { | 188 | if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) { |
148 | if d == def { | 189 | if d == def { |
149 | refs.push(FileRange { file_id, range }); | 190 | let kind = if name_ref |
191 | .syntax() | ||
192 | .ancestors() | ||
193 | .find_map(ast::RecordLit::cast) | ||
194 | .and_then(|l| l.path()) | ||
195 | .and_then(|p| p.segment()) | ||
196 | .and_then(|p| p.name_ref()) | ||
197 | .map(|n| n == name_ref) | ||
198 | .unwrap_or(false) | ||
199 | { | ||
200 | ReferenceKind::StructLiteral | ||
201 | } else { | ||
202 | ReferenceKind::Other | ||
203 | }; | ||
204 | refs.push(Reference { file_range: FileRange { file_id, range }, kind }); | ||
150 | } | 205 | } |
151 | } | 206 | } |
152 | } | 207 | } |
@@ -163,6 +218,24 @@ mod tests { | |||
163 | }; | 218 | }; |
164 | 219 | ||
165 | #[test] | 220 | #[test] |
221 | fn test_struct_literal() { | ||
222 | let code = r#" | ||
223 | struct Foo <|>{ | ||
224 | a: i32, | ||
225 | } | ||
226 | impl Foo { | ||
227 | fn f() -> i32 { 42 } | ||
228 | } | ||
229 | fn main() { | ||
230 | let f: Foo; | ||
231 | f = Foo {a: Foo::f()}; | ||
232 | }"#; | ||
233 | |||
234 | let refs = get_all_refs(code); | ||
235 | assert_eq!(refs.len(), 2); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
166 | fn test_find_all_refs_for_local() { | 239 | fn test_find_all_refs_for_local() { |
167 | let code = r#" | 240 | let code = r#" |
168 | fn main() { | 241 | fn main() { |
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index b804d5f6d..e02985dcd 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -110,7 +110,13 @@ fn rename_reference( | |||
110 | 110 | ||
111 | let edit = refs | 111 | let edit = refs |
112 | .into_iter() | 112 | .into_iter() |
113 | .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name)) | 113 | .map(|reference| { |
114 | source_edit_from_file_id_range( | ||
115 | reference.file_range.file_id, | ||
116 | reference.file_range.range, | ||
117 | new_name, | ||
118 | ) | ||
119 | }) | ||
114 | .collect::<Vec<_>>(); | 120 | .collect::<Vec<_>>(); |
115 | 121 | ||
116 | if edit.is_empty() { | 122 | if edit.is_empty() { |