diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 0ca97a0e44..ba13d3707b 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -5,8 +5,8 @@ use std::iter; use syntax::{SyntaxKind, T}; use crate::{ - patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, - CompletionKind, Completions, + context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem, + CompletionItemKind, CompletionKind, Completions, }; pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { @@ -128,8 +128,15 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword("mut", "mut "); } - if ctx.in_loop_body { - if ctx.can_be_stmt() { + let (can_be_stmt, in_loop_body) = match ctx.path_context { + Some(PathCompletionContext { + is_trivial_path: true, can_be_stmt, in_loop_body, .. + }) => (can_be_stmt, in_loop_body), + _ => return, + }; + + if in_loop_body { + if can_be_stmt { add_keyword("continue", "continue;"); add_keyword("break", "break;"); } else { @@ -138,9 +145,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte } } - if !ctx.is_trivial_path() { - return; - } let fn_def = match &ctx.function_def { Some(it) => it, None => return, @@ -148,7 +152,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword( "return", - match (ctx.can_be_stmt(), fn_def.ret_type().is_some()) { + match (can_be_stmt, fn_def.ret_type().is_some()) { (true, true) => "return $0;", (true, false) => "return;", (false, true) => "return $0", diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index 59a338e7bb..b9862de677 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs @@ -3,8 +3,8 @@ use ide_db::helpers::SnippetCap; use crate::{ - item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, - Completions, + context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, + CompletionItemKind, CompletionKind, Completions, }; fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { @@ -14,15 +14,21 @@ 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_def.is_some()) { + if ctx.function_def.is_none() { return; } + + let can_be_stmt = match ctx.path_context { + Some(PathCompletionContext { is_trivial_path: true, can_be_stmt, .. }) => can_be_stmt, + _ => return, + }; + let cap = match ctx.config.snippet_cap { Some(it) => it, None => return, }; - if ctx.can_be_stmt() { + if can_be_stmt { snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); } diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index 968c0254da..a60e5f43c1 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs @@ -34,20 +34,13 @@ use hir::{self, HasAttrs, HasSource}; use ide_db::{traits::get_missing_assoc_items, SymbolKind}; use syntax::{ - ast::{self, edit, Impl}, + ast::{self, edit}, display::function_declaration, - AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T, + AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, T, }; use text_edit::TextEdit; -use crate::{ - CompletionContext, - CompletionItem, - CompletionItemKind, - CompletionKind, - Completions, - // display::function_declaration, -}; +use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; #[derive(Debug, PartialEq, Eq)] enum ImplCompletionKind { @@ -58,7 +51,7 @@ enum ImplCompletionKind { } pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - if let Some((kind, trigger, impl_def)) = completion_match(ctx) { + if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { hir::AssocItem::Function(fn_item) if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => @@ -80,8 +73,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } } -fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { - let mut token = ctx.token.clone(); +fn completion_match(mut token: SyntaxToken) -> Option<(ImplCompletionKind, SyntaxNode, ast::Impl)> { // For keyword without name like `impl .. { fn $0 }`, the current position is inside // the whitespace token, which is outside `FN` syntax node. // We need to follow the previous token in this case. diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 7e4b149263..6177caa12b 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -43,6 +43,7 @@ pub(crate) struct PathCompletionContext { pub(super) can_be_stmt: bool, /// `true` if we expect an expression at the cursor position. pub(super) is_expr: bool, + pub(super) in_loop_body: bool, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -94,7 +95,6 @@ pub(crate) struct CompletionContext<'a> { pub(super) active_parameter: Option, pub(super) locals: Vec<(String, Local)>, - pub(super) in_loop_body: bool, pub(super) incomplete_let: bool, no_completion_required: bool, @@ -160,7 +160,6 @@ impl<'a> CompletionContext<'a> { path_context: None, active_parameter: ActiveParameter::at(db, position), locals, - in_loop_body: false, incomplete_let: false, no_completion_required: false, }; @@ -324,10 +323,6 @@ impl<'a> CompletionContext<'a> { self.path_context.as_ref().and_then(|it| it.path_qual.as_ref()) } - pub(crate) fn can_be_stmt(&self) -> bool { - self.path_context.as_ref().map_or(false, |it| it.can_be_stmt) - } - fn fill_impl_def(&mut self) { self.impl_def = self .sema @@ -453,7 +448,6 @@ impl<'a> CompletionContext<'a> { let for_is_prev2 = for_is_prev2(syntax_element.clone()); (fn_is_prev && !inside_impl_trait_block) || for_is_prev2 }; - self.in_loop_body = is_in_loop_body(syntax_element.clone()); self.incomplete_let = syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { @@ -584,7 +578,9 @@ impl<'a> CompletionContext<'a> { is_path_type: false, can_be_stmt: false, is_expr: false, + in_loop_body: false, }); + path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); let path = segment.parent_path(); if let Some(p) = path.syntax().parent() { diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 251d76fe9a..ee87bf4614 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -272,9 +272,8 @@ fn test_for_is_prev2() { check_pattern_is_applicable(r"for i i$0", for_is_prev2); } -pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { - element - .ancestors() +pub(crate) fn is_in_loop_body(node: &SyntaxNode) -> bool { + node.ancestors() .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR) .find_map(|it| { let loop_body = match_ast! { @@ -285,7 +284,7 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { _ => None, } }; - loop_body.filter(|it| it.syntax().text_range().contains_range(element.text_range())) + loop_body.filter(|it| it.syntax().text_range().contains_range(node.text_range())) }) .is_some() }