aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_db/src')
-rw-r--r--crates/ide_db/src/search.rs119
1 files changed, 38 insertions, 81 deletions
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index b9ba0aed5..38b20f2dc 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -53,24 +53,36 @@ impl IntoIterator for UsageSearchResult {
53} 53}
54 54
55#[derive(Debug, Clone)] 55#[derive(Debug, Clone)]
56pub enum NameLike {
57 NameRef(ast::NameRef),
58 Name(ast::Name),
59 Lifetime(ast::Lifetime),
60}
61
62impl NameLike {
63 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
64 match self {
65 NameLike::NameRef(name_ref) => Some(name_ref),
66 _ => None,
67 }
68 }
69}
70
71mod __ {
72 use super::{
73 ast::{Lifetime, Name, NameRef},
74 NameLike,
75 };
76 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
77}
78
79#[derive(Debug, Clone)]
56pub struct FileReference { 80pub struct FileReference {
57 pub range: TextRange, 81 pub range: TextRange,
58 pub kind: ReferenceKind, 82 pub name: NameLike,
59 pub access: Option<ReferenceAccess>, 83 pub access: Option<ReferenceAccess>,
60} 84}
61 85
62#[derive(Debug, Clone, PartialEq)]
63pub enum ReferenceKind {
64 FieldShorthandForField,
65 FieldShorthandForLocal,
66 StructLiteral,
67 RecordFieldExprOrPat,
68 SelfParam,
69 EnumLiteral,
70 Lifetime,
71 Other,
72}
73
74#[derive(Debug, Copy, Clone, PartialEq)] 86#[derive(Debug, Copy, Clone, PartialEq)]
75pub enum ReferenceAccess { 87pub enum ReferenceAccess {
76 Read, 88 Read,
@@ -369,8 +381,11 @@ impl<'a> FindUsages<'a> {
369 match NameRefClass::classify_lifetime(self.sema, lifetime) { 381 match NameRefClass::classify_lifetime(self.sema, lifetime) {
370 Some(NameRefClass::Definition(def)) if &def == self.def => { 382 Some(NameRefClass::Definition(def)) if &def == self.def => {
371 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); 383 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
372 let reference = 384 let reference = FileReference {
373 FileReference { range, kind: ReferenceKind::Lifetime, access: None }; 385 range,
386 name: NameLike::Lifetime(lifetime.clone()),
387 access: None,
388 };
374 sink(file_id, reference) 389 sink(file_id, reference)
375 } 390 }
376 _ => false, // not a usage 391 _ => false, // not a usage
@@ -384,19 +399,12 @@ impl<'a> FindUsages<'a> {
384 ) -> bool { 399 ) -> bool {
385 match NameRefClass::classify(self.sema, &name_ref) { 400 match NameRefClass::classify(self.sema, &name_ref) {
386 Some(NameRefClass::Definition(def)) if &def == self.def => { 401 Some(NameRefClass::Definition(def)) if &def == self.def => {
387 let kind = if is_record_field_expr_or_pat(&name_ref) {
388 ReferenceKind::RecordFieldExprOrPat
389 } else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) {
390 ReferenceKind::StructLiteral
391 } else if is_enum_lit_name_ref(&name_ref) {
392 ReferenceKind::EnumLiteral
393 } else {
394 ReferenceKind::Other
395 };
396
397 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); 402 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
398 let reference = 403 let reference = FileReference {
399 FileReference { range, kind, access: reference_access(&def, &name_ref) }; 404 range,
405 name: NameLike::NameRef(name_ref.clone()),
406 access: reference_access(&def, &name_ref),
407 };
400 sink(file_id, reference) 408 sink(file_id, reference)
401 } 409 }
402 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { 410 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
@@ -404,12 +412,12 @@ impl<'a> FindUsages<'a> {
404 let reference = match self.def { 412 let reference = match self.def {
405 Definition::Field(_) if &field == self.def => FileReference { 413 Definition::Field(_) if &field == self.def => FileReference {
406 range, 414 range,
407 kind: ReferenceKind::FieldShorthandForField, 415 name: NameLike::NameRef(name_ref.clone()),
408 access: reference_access(&field, &name_ref), 416 access: reference_access(&field, &name_ref),
409 }, 417 },
410 Definition::Local(l) if &local == l => FileReference { 418 Definition::Local(l) if &local == l => FileReference {
411 range, 419 range,
412 kind: ReferenceKind::FieldShorthandForLocal, 420 name: NameLike::NameRef(name_ref.clone()),
413 access: reference_access(&Definition::Local(local), &name_ref), 421 access: reference_access(&Definition::Local(local), &name_ref),
414 }, 422 },
415 _ => return false, // not a usage 423 _ => return false, // not a usage
@@ -433,7 +441,7 @@ impl<'a> FindUsages<'a> {
433 let FileRange { file_id, range } = self.sema.original_range(name.syntax()); 441 let FileRange { file_id, range } = self.sema.original_range(name.syntax());
434 let reference = FileReference { 442 let reference = FileReference {
435 range, 443 range,
436 kind: ReferenceKind::FieldShorthandForField, 444 name: NameLike::Name(name.clone()),
437 // FIXME: mutable patterns should have `Write` access 445 // FIXME: mutable patterns should have `Write` access
438 access: Some(ReferenceAccess::Read), 446 access: Some(ReferenceAccess::Read),
439 }; 447 };
@@ -473,54 +481,3 @@ fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<Referen
473 // Default Locals and Fields to read 481 // Default Locals and Fields to read
474 mode.or(Some(ReferenceAccess::Read)) 482 mode.or(Some(ReferenceAccess::Read))
475} 483}
476
477fn is_call_expr_name_ref(name_ref: &ast::NameRef) -> bool {
478 name_ref
479 .syntax()
480 .ancestors()
481 .find_map(ast::CallExpr::cast)
482 .and_then(|c| match c.expr()? {
483 ast::Expr::PathExpr(p) => {
484 Some(p.path()?.segment()?.name_ref().as_ref() == Some(name_ref))
485 }
486 _ => None,
487 })
488 .unwrap_or(false)
489}
490
491fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool {
492 name_ref
493 .syntax()
494 .ancestors()
495 .find_map(ast::RecordExpr::cast)
496 .and_then(|l| l.path())
497 .and_then(|p| p.segment())
498 .map(|p| p.name_ref().as_ref() == Some(name_ref))
499 .unwrap_or(false)
500}
501
502fn is_record_field_expr_or_pat(name_ref: &ast::NameRef) -> bool {
503 if let Some(parent) = name_ref.syntax().parent() {
504 match_ast! {
505 match parent {
506 ast::RecordExprField(it) => true,
507 ast::RecordPatField(_it) => true,
508 _ => false,
509 }
510 }
511 } else {
512 false
513 }
514}
515
516fn is_enum_lit_name_ref(name_ref: &ast::NameRef) -> bool {
517 name_ref
518 .syntax()
519 .ancestors()
520 .find_map(ast::PathExpr::cast)
521 .and_then(|p| p.path())
522 .and_then(|p| p.qualifier())
523 .and_then(|p| p.segment())
524 .map(|p| p.name_ref().as_ref() == Some(name_ref))
525 .unwrap_or(false)
526}