aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/patterns.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/patterns.rs')
-rw-r--r--crates/ide_completion/src/patterns.rs29
1 files changed, 25 insertions, 4 deletions
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 19e42ba43..c8a88367d 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -14,6 +14,7 @@ use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applic
14/// Direct parent container of the cursor position 14/// Direct parent container of the cursor position
15#[derive(Copy, Clone, Debug, PartialEq, Eq)] 15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub(crate) enum ImmediateLocation { 16pub(crate) enum ImmediateLocation {
17 Use,
17 Impl, 18 Impl,
18 Trait, 19 Trait,
19 RecordField, 20 RecordField,
@@ -24,9 +25,10 @@ pub(crate) enum ImmediateLocation {
24} 25}
25 26
26pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation> { 27pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation> {
27 // First "expand" the element we are completing to its maximum so that we can check in what 28 // First walk the element we are completing up to its highest node that has the same text range
28 // context it immediately lies. This for example means if the token is a NameRef at the end of 29 // as the element so that we can check in what context it immediately lies. We only do this for
29 // a path, we want to look at where the path is in the tree. 30 // NameRef -> Path as that's the only thing that makes sense to being "expanded" semantically.
31 // We only wanna do this if the NameRef is the last segment of the path.
30 let node = match tok.parent().and_then(ast::NameLike::cast)? { 32 let node = match tok.parent().and_then(ast::NameLike::cast)? {
31 ast::NameLike::NameRef(name_ref) => { 33 ast::NameLike::NameRef(name_ref) => {
32 if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) { 34 if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) {
@@ -46,7 +48,20 @@ pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation>
46 it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(), 48 it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(),
47 }; 49 };
48 let parent = match node.parent() { 50 let parent = match node.parent() {
49 Some(parent) => parent, 51 Some(parent) => match ast::MacroCall::cast(parent.clone()) {
52 // When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call.
53 // This is usually fine as the node expansion code above already accounts for that with
54 // the ancestors call, but there is one exception to this which is that when an attribute
55 // precedes it the code above will not walk the Path to the parent MacroCall as their ranges differ.
56 Some(call)
57 if call.excl_token().is_none()
58 && call.token_tree().is_none()
59 && call.semicolon_token().is_none() =>
60 {
61 call.syntax().parent()?
62 }
63 _ => parent,
64 },
50 // SourceFile 65 // SourceFile
51 None => { 66 None => {
52 return match node.kind() { 67 return match node.kind() {
@@ -58,6 +73,7 @@ pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation>
58 let res = match_ast! { 73 let res = match_ast! {
59 match parent { 74 match parent {
60 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 75 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
76 ast::Use(_it) => ImmediateLocation::Use,
61 ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, 77 ast::BlockExpr(_it) => ImmediateLocation::BlockExpr,
62 ast::SourceFile(_it) => ImmediateLocation::ItemList, 78 ast::SourceFile(_it) => ImmediateLocation::ItemList,
63 ast::ItemList(_it) => ImmediateLocation::ItemList, 79 ast::ItemList(_it) => ImmediateLocation::ItemList,
@@ -88,6 +104,11 @@ fn test_has_trait_parent() {
88} 104}
89 105
90#[test] 106#[test]
107fn test_has_use_parent() {
108 check_location(r"use f$0", ImmediateLocation::Use);
109}
110
111#[test]
91fn test_has_impl_parent() { 112fn test_has_impl_parent() {
92 check_location(r"impl A { f$0 }", ImmediateLocation::Impl); 113 check_location(r"impl A { f$0 }", ImmediateLocation::Impl);
93} 114}