aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/references.rs101
1 files changed, 53 insertions, 48 deletions
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 7d31ef6bd..5b8ed370c 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -55,7 +55,7 @@ pub enum ReferenceKind {
55 Other, 55 Other,
56} 56}
57 57
58#[derive(Debug, Clone, PartialEq)] 58#[derive(Debug, Copy, Clone, PartialEq)]
59pub enum ReferenceAccess { 59pub enum ReferenceAccess {
60 Read, 60 Read,
61 Write, 61 Write,
@@ -225,49 +225,41 @@ fn process_definition(
225} 225}
226 226
227fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option<ReferenceAccess> { 227fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option<ReferenceAccess> {
228 // Only Locals and Fields have accesses for now.
228 match kind { 229 match kind {
229 NameKind::Local(_) | NameKind::Field(_) => { 230 NameKind::Local(_) | NameKind::Field(_) => {}
230 //LetExpr or BinExpr 231 _ => return None,
231 name_ref.syntax().ancestors().find_map(|node| { 232 };
232 match_ast! {
233 match (node) {
234 ast::BinExpr(expr) => {
235 if expr.op_kind()?.is_assignment() {
236 // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals).
237 // FIXME: This is not terribly accurate.
238 if let Some(lhs) = expr.lhs() {
239 if lhs.syntax().text_range().end() == name_ref.syntax().text_range().end() {
240 return Some(ReferenceAccess::Write);
241 } else if name_ref.syntax().text_range().is_subrange(&lhs.syntax().text_range()) {
242 return Some(ReferenceAccess::Read);
243 }
244 }
245
246 // If the variable is on the RHS then it's a Read.
247 if let Some(rhs) = expr.rhs() {
248 if name_ref.syntax().text_range().is_subrange(&rhs.syntax().text_range()) {
249 return Some(ReferenceAccess::Read);
250 }
251 }
252 }
253 233
254 // Cannot determine access 234 let mode = name_ref.syntax().ancestors().find_map(|node| {
255 None 235 match_ast! {
256 }, 236 match (node) {
257 _ => {None} 237 ast::BinExpr(expr) => {
238 if expr.op_kind()?.is_assignment() {
239 // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals).
240 // FIXME: This is not terribly accurate.
241 if let Some(lhs) = expr.lhs() {
242 if lhs.syntax().text_range().end() == name_ref.syntax().text_range().end() {
243 return Some(ReferenceAccess::Write);
244 }
245 }
258 } 246 }
259 } 247 return Some(ReferenceAccess::Read);
260 }) 248 },
249 _ => {None}
250 }
261 } 251 }
262 _ => None, 252 });
263 } 253
254 // Default Locals and Fields to read
255 mode.or(Some(ReferenceAccess::Read))
264} 256}
265 257
266#[cfg(test)] 258#[cfg(test)]
267mod tests { 259mod tests {
268 use crate::{ 260 use crate::{
269 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, 261 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis},
270 Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, 262 Reference, ReferenceKind, ReferenceSearchResult, SearchScope,
271 }; 263 };
272 264
273 #[test] 265 #[test]
@@ -314,10 +306,10 @@ mod tests {
314 "i BIND_PAT FileId(1) [33; 34)", 306 "i BIND_PAT FileId(1) [33; 34)",
315 ReferenceKind::Other, 307 ReferenceKind::Other,
316 &[ 308 &[
317 "FileId(1) [67; 68) Other", 309 "FileId(1) [67; 68) Other Write",
318 "FileId(1) [71; 72) Other", 310 "FileId(1) [71; 72) Other Read",
319 "FileId(1) [101; 102) Other", 311 "FileId(1) [101; 102) Other Write",
320 "FileId(1) [127; 128) Other", 312 "FileId(1) [127; 128) Other Write",
321 ], 313 ],
322 ); 314 );
323 } 315 }
@@ -334,7 +326,7 @@ mod tests {
334 refs, 326 refs,
335 "i BIND_PAT FileId(1) [12; 13)", 327 "i BIND_PAT FileId(1) [12; 13)",
336 ReferenceKind::Other, 328 ReferenceKind::Other,
337 &["FileId(1) [38; 39) Other"], 329 &["FileId(1) [38; 39) Other Read"],
338 ); 330 );
339 } 331 }
340 332
@@ -350,7 +342,7 @@ mod tests {
350 refs, 342 refs,
351 "i BIND_PAT FileId(1) [12; 13)", 343 "i BIND_PAT FileId(1) [12; 13)",
352 ReferenceKind::Other, 344 ReferenceKind::Other,
353 &["FileId(1) [38; 39) Other"], 345 &["FileId(1) [38; 39) Other Read"],
354 ); 346 );
355 } 347 }
356 348
@@ -372,7 +364,7 @@ mod tests {
372 refs, 364 refs,
373 "spam RECORD_FIELD_DEF FileId(1) [66; 79) [70; 74)", 365 "spam RECORD_FIELD_DEF FileId(1) [66; 79) [70; 74)",
374 ReferenceKind::Other, 366 ReferenceKind::Other,
375 &["FileId(1) [152; 156) Other"], 367 &["FileId(1) [152; 156) Other Read"],
376 ); 368 );
377 } 369 }
378 370
@@ -577,9 +569,12 @@ mod tests {
577 }"#; 569 }"#;
578 570
579 let refs = get_all_refs(code); 571 let refs = get_all_refs(code);
580 assert_eq!(refs.len(), 3); 572 check_result(
581 assert_eq!(refs.references[0].access, Some(ReferenceAccess::Write)); 573 refs,
582 assert_eq!(refs.references[1].access, Some(ReferenceAccess::Read)); 574 "i BIND_PAT FileId(1) [36; 37)",
575 ReferenceKind::Other,
576 &["FileId(1) [55; 56) Other Write", "FileId(1) [59; 60) Other Read"],
577 );
583 } 578 }
584 579
585 #[test] 580 #[test]
@@ -595,9 +590,12 @@ mod tests {
595 }"#; 590 }"#;
596 591
597 let refs = get_all_refs(code); 592 let refs = get_all_refs(code);
598 assert_eq!(refs.len(), 3); 593 check_result(
599 //assert_eq!(refs.references[0].access, Some(ReferenceAccess::Write)); 594 refs,
600 assert_eq!(refs.references[1].access, Some(ReferenceAccess::Write)); 595 "f RECORD_FIELD_DEF FileId(1) [32; 38) [32; 33)",
596 ReferenceKind::Other,
597 &["FileId(1) [96; 97) Other Read", "FileId(1) [117; 118) Other Write"],
598 );
601 } 599 }
602 600
603 fn get_all_refs(text: &str) -> ReferenceSearchResult { 601 fn get_all_refs(text: &str) -> ReferenceSearchResult {
@@ -620,7 +618,14 @@ mod tests {
620 618
621 impl Reference { 619 impl Reference {
622 fn debug_render(&self) -> String { 620 fn debug_render(&self) -> String {
623 format!("{:?} {:?} {:?}", self.file_range.file_id, self.file_range.range, self.kind) 621 let mut s = format!(
622 "{:?} {:?} {:?}",
623 self.file_range.file_id, self.file_range.range, self.kind
624 );
625 if let Some(access) = self.access {
626 s.push_str(&format!(" {:?}", access));
627 }
628 s
624 } 629 }
625 630
626 fn assert_match(&self, expected: &str) { 631 fn assert_match(&self, expected: &str) {