aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/completion/complete_keyword.rs29
-rw-r--r--crates/ide/src/completion/complete_qualified_path.rs4
-rw-r--r--crates/ide/src/completion/completion_context.rs91
3 files changed, 65 insertions, 59 deletions
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs
index a80708935..22ada3cf2 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/ide/src/completion/complete_keyword.rs
@@ -10,30 +10,21 @@ use crate::completion::{
10pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
11 // complete keyword "crate" in use stmt 11 // complete keyword "crate" in use stmt
12 let source_range = ctx.source_range(); 12 let source_range = ctx.source_range();
13 match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) { 13
14 (Some(_), None) => { 14 if ctx.use_item_syntax.is_some() {
15 if ctx.path_qual.is_none() {
15 CompletionItem::new(CompletionKind::Keyword, source_range, "crate::") 16 CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
16 .kind(CompletionItemKind::Keyword) 17 .kind(CompletionItemKind::Keyword)
17 .insert_text("crate::") 18 .insert_text("crate::")
18 .add_to(acc); 19 .add_to(acc);
19 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
20 .kind(CompletionItemKind::Keyword)
21 .add_to(acc);
22 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
23 .kind(CompletionItemKind::Keyword)
24 .insert_text("super::")
25 .add_to(acc);
26 }
27 (Some(_), Some(_)) => {
28 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
29 .kind(CompletionItemKind::Keyword)
30 .add_to(acc);
31 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
32 .kind(CompletionItemKind::Keyword)
33 .insert_text("super::")
34 .add_to(acc);
35 } 20 }
36 _ => {} 21 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
22 .kind(CompletionItemKind::Keyword)
23 .add_to(acc);
24 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
25 .kind(CompletionItemKind::Keyword)
26 .insert_text("super::")
27 .add_to(acc);
37 } 28 }
38 29
39 // Suggest .await syntax for types that implement Future trait 30 // Suggest .await syntax for types that implement Future trait
diff --git a/crates/ide/src/completion/complete_qualified_path.rs b/crates/ide/src/completion/complete_qualified_path.rs
index cb7dd23c1..74794dc88 100644
--- a/crates/ide/src/completion/complete_qualified_path.rs
+++ b/crates/ide/src/completion/complete_qualified_path.rs
@@ -8,7 +8,7 @@ use test_utils::mark;
8use crate::completion::{CompletionContext, Completions}; 8use crate::completion::{CompletionContext, Completions};
9 9
10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 let path = match &ctx.path_prefix { 11 let path = match &ctx.path_qual {
12 Some(path) => path.clone(), 12 Some(path) => path.clone(),
13 None => return, 13 None => return,
14 }; 14 };
@@ -19,7 +19,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
19 19
20 let context_module = ctx.scope.module(); 20 let context_module = ctx.scope.module();
21 21
22 let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) { 22 let resolution = match ctx.sema.resolve_path(&path) {
23 Some(res) => res, 23 Some(res) => res,
24 None => return, 24 None => return,
25 }; 25 };
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs
index 09440334d..3857dce67 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/ide/src/completion/completion_context.rs
@@ -56,7 +56,7 @@ pub(crate) struct CompletionContext<'a> {
56 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 56 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
57 pub(super) is_trivial_path: bool, 57 pub(super) is_trivial_path: bool,
58 /// If not a trivial path, the prefix (qualifier). 58 /// If not a trivial path, the prefix (qualifier).
59 pub(super) path_prefix: Option<hir::Path>, 59 pub(super) path_qual: Option<ast::Path>,
60 pub(super) after_if: bool, 60 pub(super) after_if: bool,
61 /// `true` if we are a statement or a last expr in the block. 61 /// `true` if we are a statement or a last expr in the block.
62 pub(super) can_be_stmt: bool, 62 pub(super) can_be_stmt: bool,
@@ -137,7 +137,7 @@ impl<'a> CompletionContext<'a> {
137 is_param: false, 137 is_param: false,
138 is_pat_binding_or_const: false, 138 is_pat_binding_or_const: false,
139 is_trivial_path: false, 139 is_trivial_path: false,
140 path_prefix: None, 140 path_qual: None,
141 after_if: false, 141 after_if: false,
142 can_be_stmt: false, 142 can_be_stmt: false,
143 is_expr: false, 143 is_expr: false,
@@ -385,48 +385,54 @@ impl<'a> CompletionContext<'a> {
385 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 385 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
386 self.has_type_args = segment.generic_arg_list().is_some(); 386 self.has_type_args = segment.generic_arg_list().is_some();
387 387
388 let hygiene = hir::Hygiene::new(self.db, self.position.file_id.into()); 388 if let Some(path) = path_or_use_tree_qualifier(&path) {
389 if let Some(path) = hir::Path::from_src(path.clone(), &hygiene) { 389 self.path_qual = path
390 if let Some(path_prefix) = path.qualifier() { 390 .segment()
391 self.path_prefix = Some(path_prefix); 391 .and_then(|it| {
392 find_node_with_range::<ast::PathSegment>(
393 original_file,
394 it.syntax().text_range(),
395 )
396 })
397 .map(|it| it.parent_path());
398 return;
399 }
400
401 if let Some(segment) = path.segment() {
402 if segment.coloncolon_token().is_some() {
392 return; 403 return;
393 } 404 }
394 } 405 }
395 406
396 if path.qualifier().is_none() { 407 self.is_trivial_path = true;
397 self.is_trivial_path = true;
398
399 // Find either enclosing expr statement (thing with `;`) or a
400 // block. If block, check that we are the last expr.
401 self.can_be_stmt = name_ref
402 .syntax()
403 .ancestors()
404 .find_map(|node| {
405 if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
406 return Some(
407 stmt.syntax().text_range() == name_ref.syntax().text_range(),
408 );
409 }
410 if let Some(block) = ast::BlockExpr::cast(node) {
411 return Some(
412 block.expr().map(|e| e.syntax().text_range())
413 == Some(name_ref.syntax().text_range()),
414 );
415 }
416 None
417 })
418 .unwrap_or(false);
419 self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
420 408
421 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { 409 // Find either enclosing expr statement (thing with `;`) or a
422 if let Some(if_expr) = 410 // block. If block, check that we are the last expr.
423 self.sema.find_node_at_offset_with_macros::<ast::IfExpr>(original_file, off) 411 self.can_be_stmt = name_ref
412 .syntax()
413 .ancestors()
414 .find_map(|node| {
415 if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
416 return Some(stmt.syntax().text_range() == name_ref.syntax().text_range());
417 }
418 if let Some(block) = ast::BlockExpr::cast(node) {
419 return Some(
420 block.expr().map(|e| e.syntax().text_range())
421 == Some(name_ref.syntax().text_range()),
422 );
423 }
424 None
425 })
426 .unwrap_or(false);
427 self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
428
429 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
430 if let Some(if_expr) =
431 self.sema.find_node_at_offset_with_macros::<ast::IfExpr>(original_file, off)
432 {
433 if if_expr.syntax().text_range().end() < name_ref.syntax().text_range().start()
424 { 434 {
425 if if_expr.syntax().text_range().end() 435 self.after_if = true;
426 < name_ref.syntax().text_range().start()
427 {
428 self.after_if = true;
429 }
430 } 436 }
431 } 437 }
432 } 438 }
@@ -469,3 +475,12 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
469 Some(n) => n.syntax().text_range() == node.text_range(), 475 Some(n) => n.syntax().text_range() == node.text_range(),
470 } 476 }
471} 477}
478
479fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> {
480 if let Some(qual) = path.qualifier() {
481 return Some(qual);
482 }
483 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
484 let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
485 use_tree.path()
486}