diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 0ca97a0e44d..ba13d3707b8 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 59a338e7bb1..b9862de677f 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 968c0254da7..a60e5f43c1c 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 7e4b1492631..6177caa12bb 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<ActiveParameter>,
     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 251d76fe9a9..ee87bf46144 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()
 }