diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/references.rs | 143 |
1 files changed, 4 insertions, 139 deletions
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; | |||
13 | mod search_scope; | 13 | mod search_scope; |
14 | 14 | ||
15 | use hir::Semantics; | 15 | use hir::Semantics; |
16 | use once_cell::unsync::Lazy; | ||
17 | use ra_db::SourceDatabaseExt; | ||
18 | use ra_ide_db::{ | 16 | use 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; | |||
23 | use ra_syntax::{ | 21 | use 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 | }; |
28 | use test_utils::tested_by; | ||
29 | 26 | ||
30 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; | 27 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; |
31 | 28 | ||
32 | pub(crate) use self::rename::rename; | 29 | pub(crate) use self::rename::rename; |
33 | 30 | ||
34 | pub use ra_ide_db::search::{Reference, ReferenceAccess, ReferenceKind, SearchScope}; | 31 | pub 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)] |
37 | pub struct ReferenceSearchResult { | 36 | pub 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 | ||
125 | pub(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 | |||
203 | fn find_name( | 124 | fn 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 | ||
239 | fn 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 | |||
270 | fn 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 | |||
281 | fn get_struct_def_name_for_struc_litetal_search( | 160 | fn 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 | ||
299 | fn 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)] |
314 | mod tests { | 179 | mod tests { |
315 | use test_utils::covers; | 180 | use test_utils::covers; |