diff options
author | Lukas Wirth <[email protected]> | 2021-06-06 19:02:26 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-06-06 19:02:26 +0100 |
commit | e475bcdcc671161cf97d86d116a834c540f75f7c (patch) | |
tree | a5449ac31b140b65264645d6c074c6787f0eca08 /crates/ide_completion | |
parent | ad9234fef2a90105448214255669fb46a382c3a5 (diff) |
Simplify CompletionContext by introducing a path CallKind enum
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 55 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/render/builder_ext.rs | 12 | ||||
-rw-r--r-- | crates/ide_completion/src/render/macro_.rs | 4 |
6 files changed, 49 insertions, 32 deletions
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index e0a7021fd..22844c2ae 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -4,7 +4,7 @@ use either::Either; | |||
4 | use hir::{HasVisibility, ScopeDef}; | 4 | use hir::{HasVisibility, ScopeDef}; |
5 | use rustc_hash::FxHashSet; | 5 | use rustc_hash::FxHashSet; |
6 | 6 | ||
7 | use crate::{context::CompletionContext, Completions}; | 7 | use crate::{context::CompletionContext, patterns::ImmediateLocation, Completions}; |
8 | 8 | ||
9 | /// Complete dot accesses, i.e. fields or methods. | 9 | /// Complete dot accesses, i.e. fields or methods. |
10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -18,7 +18,7 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
18 | _ => return, | 18 | _ => return, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.is_call { | 21 | if matches!(ctx.completion_location, Some(ImmediateLocation::MethodCall { .. })) { |
22 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); | 22 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); |
23 | } else { | 23 | } else { |
24 | complete_fields(ctx, &receiver_ty, |field, ty| match field { | 24 | complete_fields(ctx, &receiver_ty, |field, ty| match field { |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 86bbb58e2..86eb21714 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -24,7 +24,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
24 | } | 24 | } |
25 | 25 | ||
26 | let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { | 26 | let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { |
27 | Some(ImmediateLocation::MethodCall { receiver: Some(it) }) => (it, false), | 27 | Some(ImmediateLocation::MethodCall { receiver: Some(it), .. }) => (it, false), |
28 | Some(ImmediateLocation::FieldAccess { | 28 | Some(ImmediateLocation::FieldAccess { |
29 | receiver: Some(it), | 29 | receiver: Some(it), |
30 | receiver_is_ambiguous_float_literal, | 30 | receiver_is_ambiguous_float_literal, |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index cb4f08e53..6bd67c123 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -29,6 +29,18 @@ pub(crate) enum PatternRefutability { | |||
29 | Irrefutable, | 29 | Irrefutable, |
30 | } | 30 | } |
31 | 31 | ||
32 | #[derive(Debug)] | ||
33 | pub(crate) struct PathCompletionContext { | ||
34 | /// If this is a call with () already there | ||
35 | call_kind: Option<CallKind>, | ||
36 | } | ||
37 | |||
38 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
39 | pub(crate) enum CallKind { | ||
40 | Pat, | ||
41 | Mac, | ||
42 | Expr, | ||
43 | } | ||
32 | /// `CompletionContext` is created early during completion to figure out, where | 44 | /// `CompletionContext` is created early during completion to figure out, where |
33 | /// exactly is the cursor, syntax-wise. | 45 | /// exactly is the cursor, syntax-wise. |
34 | #[derive(Debug)] | 46 | #[derive(Debug)] |
@@ -68,6 +80,7 @@ pub(crate) struct CompletionContext<'a> { | |||
68 | pub(super) prev_sibling: Option<ImmediatePrevSibling>, | 80 | pub(super) prev_sibling: Option<ImmediatePrevSibling>, |
69 | pub(super) attribute_under_caret: Option<ast::Attr>, | 81 | pub(super) attribute_under_caret: Option<ast::Attr>, |
70 | 82 | ||
83 | pub(super) path_context: Option<PathCompletionContext>, | ||
71 | /// FIXME: `ActiveParameter` is string-based, which is very very wrong | 84 | /// FIXME: `ActiveParameter` is string-based, which is very very wrong |
72 | pub(super) active_parameter: Option<ActiveParameter>, | 85 | pub(super) active_parameter: Option<ActiveParameter>, |
73 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 86 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
@@ -78,12 +91,6 @@ pub(crate) struct CompletionContext<'a> { | |||
78 | pub(super) can_be_stmt: bool, | 91 | pub(super) can_be_stmt: bool, |
79 | /// `true` if we expect an expression at the cursor position. | 92 | /// `true` if we expect an expression at the cursor position. |
80 | pub(super) is_expr: bool, | 93 | pub(super) is_expr: bool, |
81 | /// If this is a call (method or function) in particular, i.e. the () are already there. | ||
82 | pub(super) is_call: bool, | ||
83 | /// Like `is_call`, but for tuple patterns. | ||
84 | pub(super) is_pattern_call: bool, | ||
85 | /// If this is a macro call, i.e. the () are already there. | ||
86 | pub(super) is_macro_call: bool, | ||
87 | pub(super) is_path_type: bool, | 94 | pub(super) is_path_type: bool, |
88 | pub(super) has_type_args: bool, | 95 | pub(super) has_type_args: bool, |
89 | pub(super) locals: Vec<(String, Local)>, | 96 | pub(super) locals: Vec<(String, Local)>, |
@@ -153,9 +160,7 @@ impl<'a> CompletionContext<'a> { | |||
153 | path_qual: None, | 160 | path_qual: None, |
154 | can_be_stmt: false, | 161 | can_be_stmt: false, |
155 | is_expr: false, | 162 | is_expr: false, |
156 | is_call: false, | 163 | path_context: None, |
157 | is_pattern_call: false, | ||
158 | is_macro_call: false, | ||
159 | is_path_type: false, | 164 | is_path_type: false, |
160 | has_type_args: false, | 165 | has_type_args: false, |
161 | previous_token: None, | 166 | previous_token: None, |
@@ -250,14 +255,14 @@ impl<'a> CompletionContext<'a> { | |||
250 | pub(crate) fn has_dot_receiver(&self) -> bool { | 255 | pub(crate) fn has_dot_receiver(&self) -> bool { |
251 | matches!( | 256 | matches!( |
252 | &self.completion_location, | 257 | &self.completion_location, |
253 | Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver }) | 258 | Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver,.. }) |
254 | if receiver.is_some() | 259 | if receiver.is_some() |
255 | ) | 260 | ) |
256 | } | 261 | } |
257 | 262 | ||
258 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { | 263 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { |
259 | match &self.completion_location { | 264 | match &self.completion_location { |
260 | Some(ImmediateLocation::MethodCall { receiver }) | 265 | Some(ImmediateLocation::MethodCall { receiver, .. }) |
261 | | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), | 266 | | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), |
262 | _ => None, | 267 | _ => None, |
263 | } | 268 | } |
@@ -316,6 +321,10 @@ impl<'a> CompletionContext<'a> { | |||
316 | ) || self.attribute_under_caret.is_some() | 321 | ) || self.attribute_under_caret.is_some() |
317 | } | 322 | } |
318 | 323 | ||
324 | pub(crate) fn path_call_kind(&self) -> Option<CallKind> { | ||
325 | self.path_context.as_ref().and_then(|it| it.call_kind) | ||
326 | } | ||
327 | |||
319 | fn fill_impl_def(&mut self) { | 328 | fn fill_impl_def(&mut self) { |
320 | self.impl_def = self | 329 | self.impl_def = self |
321 | .sema | 330 | .sema |
@@ -568,17 +577,21 @@ impl<'a> CompletionContext<'a> { | |||
568 | }; | 577 | }; |
569 | 578 | ||
570 | if let Some(segment) = ast::PathSegment::cast(parent) { | 579 | if let Some(segment) = ast::PathSegment::cast(parent) { |
580 | let mut path_ctx = PathCompletionContext { call_kind: None }; | ||
571 | let path = segment.parent_path(); | 581 | let path = segment.parent_path(); |
572 | self.is_call = path | ||
573 | .syntax() | ||
574 | .parent() | ||
575 | .and_then(ast::PathExpr::cast) | ||
576 | .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) | ||
577 | .is_some(); | ||
578 | self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); | ||
579 | self.is_pattern_call = | ||
580 | path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some(); | ||
581 | 582 | ||
583 | if let Some(p) = path.syntax().parent() { | ||
584 | path_ctx.call_kind = match_ast! { | ||
585 | match p { | ||
586 | ast::PathExpr(it) => it.syntax().parent().and_then(ast::CallExpr::cast).map(|_| CallKind::Expr), | ||
587 | ast::MacroCall(_it) => Some(CallKind::Mac), | ||
588 | ast::TupleStructPat(_it) => Some(CallKind::Pat), | ||
589 | _ => None | ||
590 | } | ||
591 | }; | ||
592 | } | ||
593 | self.path_context = Some(path_ctx); | ||
594 | dbg!(&self.path_context); | ||
582 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); | 595 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); |
583 | self.has_type_args = segment.generic_arg_list().is_some(); | 596 | self.has_type_args = segment.generic_arg_list().is_some(); |
584 | 597 | ||
@@ -623,8 +636,6 @@ impl<'a> CompletionContext<'a> { | |||
623 | .unwrap_or(false); | 636 | .unwrap_or(false); |
624 | self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); | 637 | self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); |
625 | } | 638 | } |
626 | self.is_call |= | ||
627 | matches!(self.completion_location, Some(ImmediateLocation::MethodCall { .. })); | ||
628 | } | 639 | } |
629 | } | 640 | } |
630 | 641 | ||
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 080898aef..251d76fe9 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -4,7 +4,7 @@ use hir::Semantics; | |||
4 | use ide_db::RootDatabase; | 4 | use ide_db::RootDatabase; |
5 | use syntax::{ | 5 | use syntax::{ |
6 | algo::non_trivia_sibling, | 6 | algo::non_trivia_sibling, |
7 | ast::{self, LoopBodyOwner}, | 7 | ast::{self, ArgListOwner, LoopBodyOwner}, |
8 | match_ast, AstNode, Direction, SyntaxElement, | 8 | match_ast, AstNode, Direction, SyntaxElement, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, | 10 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, |
@@ -39,6 +39,7 @@ pub(crate) enum ImmediateLocation { | |||
39 | // Original file ast node | 39 | // Original file ast node |
40 | MethodCall { | 40 | MethodCall { |
41 | receiver: Option<ast::Expr>, | 41 | receiver: Option<ast::Expr>, |
42 | has_parens: bool, | ||
42 | }, | 43 | }, |
43 | // Original file ast node | 44 | // Original file ast node |
44 | FieldAccess { | 45 | FieldAccess { |
@@ -204,6 +205,7 @@ pub(crate) fn determine_location( | |||
204 | .receiver() | 205 | .receiver() |
205 | .map(|e| e.syntax().text_range()) | 206 | .map(|e| e.syntax().text_range()) |
206 | .and_then(|r| find_node_with_range(original_file, r)), | 207 | .and_then(|r| find_node_with_range(original_file, r)), |
208 | has_parens: it.arg_list().map_or(false, |it| it.l_paren_token().is_some()) | ||
207 | }, | 209 | }, |
208 | _ => return None, | 210 | _ => return None, |
209 | } | 211 | } |
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs index 6d062b3b9..c54752d30 100644 --- a/crates/ide_completion/src/render/builder_ext.rs +++ b/crates/ide_completion/src/render/builder_ext.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | 4 | ||
5 | use crate::{item::Builder, CompletionContext}; | 5 | use crate::{context::CallKind, item::Builder, patterns::ImmediateLocation, CompletionContext}; |
6 | 6 | ||
7 | #[derive(Debug)] | 7 | #[derive(Debug)] |
8 | pub(super) enum Params { | 8 | pub(super) enum Params { |
@@ -32,10 +32,12 @@ impl Builder { | |||
32 | cov_mark::hit!(no_parens_in_use_item); | 32 | cov_mark::hit!(no_parens_in_use_item); |
33 | return false; | 33 | return false; |
34 | } | 34 | } |
35 | if ctx.is_pattern_call { | 35 | if matches!(ctx.path_call_kind(), Some(CallKind::Expr) | Some(CallKind::Pat)) |
36 | return false; | 36 | | matches!( |
37 | } | 37 | ctx.completion_location, |
38 | if ctx.is_call { | 38 | Some(ImmediateLocation::MethodCall { has_parens: true, .. }) |
39 | ) | ||
40 | { | ||
39 | return false; | 41 | return false; |
40 | } | 42 | } |
41 | 43 | ||
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 0dfba8acc..429d937c8 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -5,6 +5,7 @@ use ide_db::SymbolKind; | |||
5 | use syntax::display::macro_label; | 5 | use syntax::display::macro_label; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | context::CallKind, | ||
8 | item::{CompletionItem, CompletionKind, ImportEdit}, | 9 | item::{CompletionItem, CompletionKind, ImportEdit}, |
9 | render::RenderContext, | 10 | render::RenderContext, |
10 | }; | 11 | }; |
@@ -68,7 +69,8 @@ impl<'a> MacroRender<'a> { | |||
68 | } | 69 | } |
69 | 70 | ||
70 | fn needs_bang(&self) -> bool { | 71 | fn needs_bang(&self) -> bool { |
71 | self.ctx.completion.use_item_syntax.is_none() && !self.ctx.completion.is_macro_call | 72 | self.ctx.completion.use_item_syntax.is_none() |
73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) | ||
72 | } | 74 | } |
73 | 75 | ||
74 | fn label(&self) -> String { | 76 | fn label(&self) -> String { |