diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/completion/complete_keyword.rs | 29 | ||||
-rw-r--r-- | crates/ide/src/completion/complete_qualified_path.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/completion/completion_context.rs | 91 |
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::{ | |||
10 | pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(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; | |||
8 | use crate::completion::{CompletionContext, Completions}; | 8 | use crate::completion::{CompletionContext, Completions}; |
9 | 9 | ||
10 | pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(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 | |||
479 | fn 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 | } | ||