aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-03-04 11:14:48 +0000
committerAleksey Kladov <[email protected]>2020-03-04 11:22:47 +0000
commitf79719b8ae4d1929acaa940802a1e293f7dd7a6b (patch)
treea793e25b0037d61df3470ec59f09ea823d56d593 /crates/ra_ide
parent2638bec66cb05ff51a0804181a47546a0f55afbf (diff)
Move find_refs_to_def
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/references.rs143
2 files changed, 5 insertions, 139 deletions
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index 7625fc8c8..adee7c493 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -19,6 +19,7 @@ join_to_string = "0.1.3"
19log = "0.4.8" 19log = "0.4.8"
20rustc-hash = "1.1.0" 20rustc-hash = "1.1.0"
21rand = { version = "0.7.3", features = ["small_rng"] } 21rand = { version = "0.7.3", features = ["small_rng"] }
22# TODO: check if can remove
22once_cell = "1.3.1" 23once_cell = "1.3.1"
23 24
24ra_syntax = { path = "../ra_syntax" } 25ra_syntax = { path = "../ra_syntax" }
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index ee065b6f9..abecca2bb 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -13,8 +13,6 @@ mod rename;
13mod search_scope; 13mod search_scope;
14 14
15use hir::Semantics; 15use hir::Semantics;
16use once_cell::unsync::Lazy;
17use ra_db::SourceDatabaseExt;
18use ra_ide_db::{ 16use ra_ide_db::{
19 defs::{classify_name, classify_name_ref, Definition}, 17 defs::{classify_name, classify_name_ref, Definition},
20 RootDatabase, 18 RootDatabase,
@@ -23,15 +21,16 @@ use ra_prof::profile;
23use ra_syntax::{ 21use ra_syntax::{
24 algo::find_node_at_offset, 22 algo::find_node_at_offset,
25 ast::{self, NameOwner}, 23 ast::{self, NameOwner},
26 match_ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextUnit, TokenAtOffset, 24 AstNode, SyntaxKind, SyntaxNode, TextRange, TokenAtOffset,
27}; 25};
28use test_utils::tested_by;
29 26
30use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; 27use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
31 28
32pub(crate) use self::rename::rename; 29pub(crate) use self::rename::rename;
33 30
34pub use ra_ide_db::search::{Reference, ReferenceAccess, ReferenceKind, SearchScope}; 31pub use ra_ide_db::search::{
32 find_refs_to_def, Reference, ReferenceAccess, ReferenceKind, SearchScope,
33};
35 34
36#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
37pub struct ReferenceSearchResult { 36pub struct ReferenceSearchResult {
@@ -122,84 +121,6 @@ pub(crate) fn find_all_refs(
122 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) 121 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }))
123} 122}
124 123
125pub(crate) fn find_refs_to_def(
126 db: &RootDatabase,
127 def: &Definition,
128 search_scope: Option<SearchScope>,
129) -> Vec<Reference> {
130 let _p = profile("find_refs_to_def");
131
132 let search_scope = {
133 let base = SearchScope::for_def(&def, db);
134 match search_scope {
135 None => base,
136 Some(scope) => base.intersection(&scope),
137 }
138 };
139
140 let name = match def.name(db) {
141 None => return Vec::new(),
142 Some(it) => it.to_string(),
143 };
144
145 let pat = name.as_str();
146 let mut refs = vec![];
147
148 for (file_id, search_range) in search_scope {
149 let text = db.file_text(file_id);
150 let search_range =
151 search_range.unwrap_or(TextRange::offset_len(0.into(), TextUnit::of_str(&text)));
152
153 let sema = Semantics::new(db);
154 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
155
156 for (idx, _) in text.match_indices(pat) {
157 let offset = TextUnit::from_usize(idx);
158 if !search_range.contains_inclusive(offset) {
159 tested_by!(search_filters_by_range);
160 continue;
161 }
162
163 let name_ref =
164 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&tree, offset) {
165 name_ref
166 } else {
167 // Handle macro token cases
168 let token = match tree.token_at_offset(offset) {
169 TokenAtOffset::None => continue,
170 TokenAtOffset::Single(t) => t,
171 TokenAtOffset::Between(_, t) => t,
172 };
173 let expanded = sema.descend_into_macros(token);
174 match ast::NameRef::cast(expanded.parent()) {
175 Some(name_ref) => name_ref,
176 _ => continue,
177 }
178 };
179
180 if let Some(d) = classify_name_ref(&sema, &name_ref) {
181 let d = d.definition();
182 if &d == def {
183 let kind =
184 if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) {
185 ReferenceKind::StructLiteral
186 } else {
187 ReferenceKind::Other
188 };
189
190 let file_range = sema.original_range(name_ref.syntax());
191 refs.push(Reference {
192 file_range,
193 kind,
194 access: reference_access(&d, &name_ref),
195 });
196 }
197 }
198 }
199 }
200 refs
201}
202
203fn find_name( 124fn find_name(
204 sema: &Semantics<RootDatabase>, 125 sema: &Semantics<RootDatabase>,
205 syntax: &SyntaxNode, 126 syntax: &SyntaxNode,
@@ -236,48 +157,6 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio
236 None 157 None
237} 158}
238 159
239fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> {
240 // Only Locals and Fields have accesses for now.
241 match def {
242 Definition::Local(_) | Definition::StructField(_) => {}
243 _ => return None,
244 };
245
246 let mode = name_ref.syntax().ancestors().find_map(|node| {
247 match_ast! {
248 match (node) {
249 ast::BinExpr(expr) => {
250 if expr.op_kind()?.is_assignment() {
251 // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals).
252 // FIXME: This is not terribly accurate.
253 if let Some(lhs) = expr.lhs() {
254 if lhs.syntax().text_range().end() == name_ref.syntax().text_range().end() {
255 return Some(ReferenceAccess::Write);
256 }
257 }
258 }
259 Some(ReferenceAccess::Read)
260 },
261 _ => {None}
262 }
263 }
264 });
265
266 // Default Locals and Fields to read
267 mode.or(Some(ReferenceAccess::Read))
268}
269
270fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool {
271 name_ref
272 .syntax()
273 .ancestors()
274 .find_map(ast::RecordLit::cast)
275 .and_then(|l| l.path())
276 .and_then(|p| p.segment())
277 .map(|p| p.name_ref().as_ref() == Some(name_ref))
278 .unwrap_or(false)
279}
280
281fn get_struct_def_name_for_struc_litetal_search( 160fn get_struct_def_name_for_struc_litetal_search(
282 syntax: &SyntaxNode, 161 syntax: &SyntaxNode,
283 position: FilePosition, 162 position: FilePosition,
@@ -296,20 +175,6 @@ fn get_struct_def_name_for_struc_litetal_search(
296 None 175 None
297} 176}
298 177
299fn is_call_expr_name_ref(name_ref: &ast::NameRef) -> bool {
300 name_ref
301 .syntax()
302 .ancestors()
303 .find_map(ast::CallExpr::cast)
304 .and_then(|c| match c.expr()? {
305 ast::Expr::PathExpr(p) => {
306 Some(p.path()?.segment()?.name_ref().as_ref() == Some(name_ref))
307 }
308 _ => None,
309 })
310 .unwrap_or(false)
311}
312
313#[cfg(test)] 178#[cfg(test)]
314mod tests { 179mod tests {
315 use test_utils::covers; 180 use test_utils::covers;