]> git.lizzy.rs Git - rust.git/commitdiff
Collapse more CompletionContext booleans into enums
authorLukas Wirth <lukastw97@gmail.com>
Thu, 27 May 2021 00:54:49 +0000 (02:54 +0200)
committerLukas Wirth <lukastw97@gmail.com>
Thu, 27 May 2021 00:54:49 +0000 (02:54 +0200)
crates/ide_completion/src/completions/flyimport.rs
crates/ide_completion/src/completions/keyword.rs
crates/ide_completion/src/completions/snippet.rs
crates/ide_completion/src/completions/unqualified_path.rs
crates/ide_completion/src/context.rs
crates/ide_completion/src/patterns.rs

index 9d5b61562a083618523b8147eb88bec8a758963a..b7d3ee8ce7bb05a780e7967460b5eb89004dfefb 100644 (file)
@@ -114,8 +114,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
         || ctx.attribute_under_caret.is_some()
         || ctx.mod_declaration_under_caret.is_some()
         || ctx.record_lit_syntax.is_some()
-        || ctx.has_trait_parent
-        || ctx.has_impl_parent
+        || ctx.has_impl_or_trait_parent()
     {
         return None;
     }
index fa6bcc955501b2ee7a9ab6fe0b74b19ad33fbdd3..58e35bad9b24ae687c49caede155845e48803410 100644 (file)
@@ -49,34 +49,35 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         return;
     }
 
-    let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
-    if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
+    let has_trait_or_impl_parent = ctx.has_impl_or_trait_parent();
+    let has_block_expr_parent = ctx.has_block_expr_parent();
+    let has_item_list_parent = ctx.has_item_list_parent();
+    if ctx.has_impl_or_trait_prev_sibling() {
         add_keyword(ctx, acc, "where", "where ");
         return;
     }
     if ctx.previous_token_is(T![unsafe]) {
-        if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
+        if has_item_list_parent || has_block_expr_parent {
             add_keyword(ctx, acc, "fn", "fn $1($2) {\n    $0\n}")
         }
 
-        if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
+        if has_item_list_parent || has_block_expr_parent {
             add_keyword(ctx, acc, "trait", "trait $1 {\n    $0\n}");
             add_keyword(ctx, acc, "impl", "impl $1 {\n    $0\n}");
         }
 
         return;
     }
-    if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
-    {
+    if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent {
         add_keyword(ctx, acc, "fn", "fn $1($2) {\n    $0\n}");
     }
-    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
+    if has_item_list_parent || has_block_expr_parent {
         add_keyword(ctx, acc, "use", "use ");
         add_keyword(ctx, acc, "impl", "impl $1 {\n    $0\n}");
         add_keyword(ctx, acc, "trait", "trait $1 {\n    $0\n}");
     }
 
-    if ctx.has_item_list_or_source_file_parent {
+    if has_item_list_parent {
         add_keyword(ctx, acc, "enum", "enum $1 {\n    $0\n}");
         add_keyword(ctx, acc, "struct", "struct $0");
         add_keyword(ctx, acc, "union", "union $1 {\n    $0\n}");
@@ -92,7 +93,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         add_keyword(ctx, acc, "for", "for $1 in $2 {\n    $0\n}");
     }
 
-    if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || ctx.block_expr_parent {
+    if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
         add_keyword(ctx, acc, "let", "let ");
     }
 
@@ -100,27 +101,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         add_keyword(ctx, acc, "else", "else {\n    $0\n}");
         add_keyword(ctx, acc, "else if", "else if $1 {\n    $0\n}");
     }
-    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
+    if has_item_list_parent || has_block_expr_parent {
         add_keyword(ctx, acc, "mod", "mod $0");
     }
-    if ctx.bind_pat_parent || ctx.ref_pat_parent {
+    if ctx.has_ident_or_ref_pat_parent() {
         add_keyword(ctx, acc, "mut", "mut ");
     }
-    if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
-    {
+    if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent {
         add_keyword(ctx, acc, "const", "const ");
         add_keyword(ctx, acc, "type", "type ");
     }
-    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
+    if has_item_list_parent || has_block_expr_parent {
         add_keyword(ctx, acc, "static", "static ");
     };
-    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
+    if has_item_list_parent || has_block_expr_parent {
         add_keyword(ctx, acc, "extern", "extern ");
     }
-    if ctx.has_item_list_or_source_file_parent
-        || has_trait_or_impl_parent
-        || ctx.block_expr_parent
-        || ctx.is_match_arm
+    if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent || ctx.is_match_arm
     {
         add_keyword(ctx, acc, "unsafe", "unsafe ");
     }
@@ -133,7 +130,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
             add_keyword(ctx, acc, "break", "break");
         }
     }
-    if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent {
+    if has_item_list_parent || ctx.has_impl_parent() || ctx.has_field_list_parent() {
         add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
         add_keyword(ctx, acc, "pub", "pub ");
     }
@@ -141,7 +138,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     if !ctx.is_trivial_path {
         return;
     }
-    let fn_def = match &ctx.function_syntax {
+    let fn_def = match &ctx.function_def {
         Some(it) => it,
         None => return,
     };
index 14cfb61deef8f0f343c6c7d28b6d08c30b5de54b..defc25b00892b039407a650f832efac72ca9e901 100644 (file)
@@ -14,7 +14,7 @@ fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str)
 }
 
 pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
-    if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) {
+    if !(ctx.is_trivial_path && ctx.function_def.is_some()) {
         return;
     }
     let cap = match ctx.config.snippet_cap {
index b8f8ef25f9a29843611059281ecb31ebadf36f90..7496d26c4db89b709c6e118863d39b3d9214a388 100644 (file)
@@ -13,8 +13,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
         || ctx.record_pat_syntax.is_some()
         || ctx.attribute_under_caret.is_some()
         || ctx.mod_declaration_under_caret.is_some()
-        || ctx.has_impl_parent
-        || ctx.has_trait_parent
+        || ctx.has_impl_or_trait_parent()
     {
         return;
     }
index 6dc6769df9a0a545f5b3ab855e8483d332cab314..dfac8f29f49c19cf1402f1ead5d56ecf66cc06f8 100644 (file)
@@ -31,6 +31,24 @@ pub(crate) enum PatternRefutability {
     Irrefutable,
 }
 
+/// Direct parent container of the cursor position
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum ImmediateLocation {
+    Impl,
+    Trait,
+    RecordFieldList,
+    RefPatOrExpr,
+    IdentPat,
+    BlockExpr,
+    ItemList,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum PrevSibling {
+    Trait,
+    Impl,
+}
+
 /// `CompletionContext` is created early during completion to figure out, where
 /// exactly is the cursor, syntax-wise.
 #[derive(Debug)]
@@ -48,14 +66,19 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) expected_name: Option<NameOrNameRef>,
     pub(super) expected_type: Option<Type>,
     pub(super) name_ref_syntax: Option<ast::NameRef>,
-    pub(super) function_syntax: Option<ast::Fn>,
+
     pub(super) use_item_syntax: Option<ast::Use>,
-    pub(super) record_lit_syntax: Option<ast::RecordExpr>,
-    pub(super) record_pat_syntax: Option<ast::RecordPat>,
-    pub(super) record_field_syntax: Option<ast::RecordExprField>,
+
+    /// The parent function of the cursor position if it exists.
+    pub(super) function_def: Option<ast::Fn>,
     /// The parent impl of the cursor position if it exists.
     pub(super) impl_def: Option<ast::Impl>,
 
+    /// RecordExpr the token is a field of
+    pub(super) record_lit_syntax: Option<ast::RecordExpr>,
+    /// RecordPat the token is a field of
+    pub(super) record_pat_syntax: Option<ast::RecordPat>,
+
     // potentially set if we are completing a lifetime
     pub(super) lifetime_syntax: Option<ast::Lifetime>,
     pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -66,6 +89,8 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) is_pat_or_const: Option<PatternRefutability>,
     pub(super) is_param: bool,
 
+    pub(super) completion_location: Option<ImmediateLocation>,
+
     /// FIXME: `ActiveParameter` is string-based, which is very very wrong
     pub(super) active_parameter: Option<ActiveParameter>,
     /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
@@ -94,20 +119,12 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) locals: Vec<(String, Local)>,
 
     pub(super) mod_declaration_under_caret: Option<ast::Module>,
-    pub(super) has_trait_parent: bool,
-    pub(super) has_impl_parent: bool,
 
     // keyword patterns
     pub(super) previous_token: Option<SyntaxToken>,
-    pub(super) block_expr_parent: bool,
-    pub(super) bind_pat_parent: bool,
-    pub(super) ref_pat_parent: bool,
     pub(super) in_loop_body: bool,
-    pub(super) has_field_list_parent: bool,
-    pub(super) trait_as_prev_sibling: bool,
-    pub(super) impl_as_prev_sibling: bool,
+    pub(super) prev_sibling: Option<PrevSibling>,
     pub(super) is_match_arm: bool,
-    pub(super) has_item_list_or_source_file_parent: bool,
     pub(super) incomplete_let: bool,
 
     no_completion_required: bool,
@@ -159,11 +176,10 @@ pub(super) fn new(
             name_ref_syntax: None,
             lifetime_syntax: None,
             lifetime_param_syntax: None,
-            function_syntax: None,
+            function_def: None,
             use_item_syntax: None,
             record_lit_syntax: None,
             record_pat_syntax: None,
-            record_field_syntax: None,
             impl_def: None,
             active_parameter: ActiveParameter::at(db, position),
             is_label_ref: false,
@@ -185,17 +201,10 @@ pub(super) fn new(
             attribute_under_caret: None,
             mod_declaration_under_caret: None,
             previous_token: None,
-            block_expr_parent: false,
-            bind_pat_parent: false,
-            ref_pat_parent: false,
             in_loop_body: false,
-            has_trait_parent: false,
-            has_impl_parent: false,
-            has_field_list_parent: false,
-            trait_as_prev_sibling: false,
-            impl_as_prev_sibling: false,
+            completion_location: None,
+            prev_sibling: None,
             is_match_arm: false,
-            has_item_list_or_source_file_parent: false,
             no_completion_required: false,
             incomplete_let: false,
             locals,
@@ -274,23 +283,68 @@ pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool {
         self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind)
     }
 
+    pub(crate) fn has_impl_or_trait_parent(&self) -> bool {
+        matches!(
+            self.completion_location,
+            Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl)
+        )
+    }
+
+    pub(crate) fn has_block_expr_parent(&self) -> bool {
+        matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
+    }
+
+    pub(crate) fn has_item_list_parent(&self) -> bool {
+        matches!(self.completion_location, Some(ImmediateLocation::ItemList))
+    }
+
+    pub(crate) fn has_ident_or_ref_pat_parent(&self) -> bool {
+        matches!(
+            self.completion_location,
+            Some(ImmediateLocation::IdentPat) | Some(ImmediateLocation::RefPatOrExpr)
+        )
+    }
+
+    pub(crate) fn has_impl_parent(&self) -> bool {
+        matches!(self.completion_location, Some(ImmediateLocation::Impl))
+    }
+
+    pub(crate) fn has_field_list_parent(&self) -> bool {
+        matches!(self.completion_location, Some(ImmediateLocation::RecordFieldList))
+    }
+
+    pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
+        self.prev_sibling.is_some()
+    }
+
     fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
         let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
         let syntax_element = NodeOrToken::Token(fake_ident_token);
         self.previous_token = previous_token(syntax_element.clone());
-        self.block_expr_parent = has_block_expr_parent(syntax_element.clone());
-        self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone());
-        self.ref_pat_parent = has_ref_parent(syntax_element.clone());
         self.in_loop_body = is_in_loop_body(syntax_element.clone());
-        self.has_trait_parent = has_trait_parent(syntax_element.clone());
-        self.has_impl_parent = has_impl_parent(syntax_element.clone());
-        self.has_field_list_parent = has_field_list_parent(syntax_element.clone());
-        self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
-        self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
         self.is_match_arm = is_match_arm(syntax_element.clone());
+        if has_impl_as_prev_sibling(syntax_element.clone()) {
+            self.prev_sibling = Some(PrevSibling::Impl)
+        } else if has_trait_as_prev_sibling(syntax_element.clone()) {
+            self.prev_sibling = Some(PrevSibling::Trait)
+        }
+
+        if has_block_expr_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::BlockExpr);
+        } else if has_bind_pat_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::IdentPat);
+        } else if has_ref_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::RefPatOrExpr);
+        } else if has_impl_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::Impl);
+        } else if has_field_list_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::RecordFieldList);
+        } else if has_trait_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::Trait);
+        } else if has_item_list_or_source_file_parent(syntax_element.clone()) {
+            self.completion_location = Some(ImmediateLocation::ItemList);
+        }
 
-        self.has_item_list_or_source_file_parent =
-            has_item_list_or_source_file_parent(syntax_element.clone());
         self.mod_declaration_under_caret =
             find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
                 .filter(|module| module.item_list().is_none());
@@ -542,31 +596,20 @@ fn classify_name_ref(
             .last()
             .unwrap();
 
-        match top_node.parent().map(|it| it.kind()) {
-            Some(SOURCE_FILE) | Some(ITEM_LIST) => {
-                self.is_new_item = true;
-                return;
-            }
-            _ => (),
+        if matches!(top_node.parent().map(|it| it.kind()), Some(SOURCE_FILE) | Some(ITEM_LIST)) {
+            self.is_new_item = true;
+            return;
         }
 
         self.use_item_syntax =
             self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
 
-        self.function_syntax = self
+        self.function_def = self
             .sema
             .token_ancestors_with_macros(self.token.clone())
             .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
             .find_map(ast::Fn::cast);
 
-        self.record_field_syntax = self
-            .sema
-            .token_ancestors_with_macros(self.token.clone())
-            .take_while(|it| {
-                it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR
-            })
-            .find_map(ast::RecordExprField::cast);
-
         let parent = match name_ref.syntax().parent() {
             Some(it) => it,
             None => return,
@@ -639,6 +682,7 @@ fn classify_name_ref(
                 }
             }
         }
+
         if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
             // The receiver comes before the point of insertion of the fake
             // ident, so it should have the same range in the non-modified file
@@ -656,6 +700,7 @@ fn classify_name_ref(
                     false
                 };
         }
+
         if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
             // As above
             self.dot_receiver = method_call_expr
index 3d8a83ed872019c4ca2349f4f12c3c56b8af95cb..8f0d76661678e54a7a50b34a3f6d6cd4ecc8f3d2 100644 (file)
@@ -91,11 +91,10 @@ fn test_has_ref_parent() {
 }
 
 pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
-    let ancestor = not_same_range_ancestor(element);
-    if !ancestor.is_some() {
-        return true;
+    match not_same_range_ancestor(element) {
+        Some(it) => it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST,
+        None => true,
     }
-    ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
 }
 #[test]
 fn test_has_item_list_or_source_file_parent() {
@@ -151,25 +150,21 @@ fn test_has_impl_as_prev_sibling() {
 }
 
 pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
-    for node in element.ancestors() {
-        if node.kind() == FN || node.kind() == CLOSURE_EXPR {
-            break;
-        }
-        let loop_body = match_ast! {
-            match node {
-                ast::ForExpr(it) => it.loop_body(),
-                ast::WhileExpr(it) => it.loop_body(),
-                ast::LoopExpr(it) => it.loop_body(),
-                _ => None,
-            }
-        };
-        if let Some(body) = loop_body {
-            if body.syntax().text_range().contains_range(element.text_range()) {
-                return true;
-            }
-        }
-    }
-    false
+    element
+        .ancestors()
+        .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR)
+        .find_map(|it| {
+            let loop_body = match_ast! {
+                match it {
+                    ast::ForExpr(it) => it.loop_body(),
+                    ast::WhileExpr(it) => it.loop_body(),
+                    ast::LoopExpr(it) => it.loop_body(),
+                    _ => None,
+                }
+            };
+            loop_body.filter(|it| it.syntax().text_range().contains_range(element.text_range()))
+        })
+        .is_some()
 }
 
 fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {