diff options
Diffstat (limited to 'crates/ide_completion/src/patterns.rs')
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 29 |
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)] |
16 | pub(crate) enum ImmediateLocation { | 16 | pub(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 | ||
26 | pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation> { | 27 | pub(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] |
107 | fn test_has_use_parent() { | ||
108 | check_location(r"use f$0", ImmediateLocation::Use); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
91 | fn test_has_impl_parent() { | 112 | fn 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 | } |