diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs index a80708935ea..22ada3cf293 100644 --- a/crates/ide/src/completion/complete_keyword.rs +++ b/crates/ide/src/completion/complete_keyword.rs @@ -10,30 +10,21 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { // complete keyword "crate" in use stmt let source_range = ctx.source_range(); - match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) { - (Some(_), None) => { + + if ctx.use_item_syntax.is_some() { + if ctx.path_qual.is_none() { CompletionItem::new(CompletionKind::Keyword, source_range, "crate::") .kind(CompletionItemKind::Keyword) .insert_text("crate::") .add_to(acc); - CompletionItem::new(CompletionKind::Keyword, source_range, "self") - .kind(CompletionItemKind::Keyword) - .add_to(acc); - CompletionItem::new(CompletionKind::Keyword, source_range, "super::") - .kind(CompletionItemKind::Keyword) - .insert_text("super::") - .add_to(acc); } - (Some(_), Some(_)) => { - CompletionItem::new(CompletionKind::Keyword, source_range, "self") - .kind(CompletionItemKind::Keyword) - .add_to(acc); - CompletionItem::new(CompletionKind::Keyword, source_range, "super::") - .kind(CompletionItemKind::Keyword) - .insert_text("super::") - .add_to(acc); - } - _ => {} + CompletionItem::new(CompletionKind::Keyword, source_range, "self") + .kind(CompletionItemKind::Keyword) + .add_to(acc); + CompletionItem::new(CompletionKind::Keyword, source_range, "super::") + .kind(CompletionItemKind::Keyword) + .insert_text("super::") + .add_to(acc); } // 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 cb7dd23c187..74794dc88bf 100644 --- a/crates/ide/src/completion/complete_qualified_path.rs +++ b/crates/ide/src/completion/complete_qualified_path.rs @@ -8,7 +8,7 @@ use crate::completion::{CompletionContext, Completions}; pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { - let path = match &ctx.path_prefix { + let path = match &ctx.path_qual { Some(path) => path.clone(), None => return, }; @@ -19,7 +19,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon let context_module = ctx.scope.module(); - let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) { + let resolution = match ctx.sema.resolve_path(&path) { Some(res) => res, None => return, }; diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs index 09440334d3f..3857dce6721 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> { /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. pub(super) is_trivial_path: bool, /// If not a trivial path, the prefix (qualifier). - pub(super) path_prefix: Option, + pub(super) path_qual: Option, pub(super) after_if: bool, /// `true` if we are a statement or a last expr in the block. pub(super) can_be_stmt: bool, @@ -137,7 +137,7 @@ pub(super) fn new( is_param: false, is_pat_binding_or_const: false, is_trivial_path: false, - path_prefix: None, + path_qual: None, after_if: false, can_be_stmt: false, is_expr: false, @@ -385,48 +385,54 @@ fn classify_name_ref( self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); self.has_type_args = segment.generic_arg_list().is_some(); - let hygiene = hir::Hygiene::new(self.db, self.position.file_id.into()); - if let Some(path) = hir::Path::from_src(path.clone(), &hygiene) { - if let Some(path_prefix) = path.qualifier() { - self.path_prefix = Some(path_prefix); + if let Some(path) = path_or_use_tree_qualifier(&path) { + self.path_qual = path + .segment() + .and_then(|it| { + find_node_with_range::( + original_file, + it.syntax().text_range(), + ) + }) + .map(|it| it.parent_path()); + return; + } + + if let Some(segment) = path.segment() { + if segment.coloncolon_token().is_some() { return; } } - if path.qualifier().is_none() { - self.is_trivial_path = true; + self.is_trivial_path = true; - // Find either enclosing expr statement (thing with `;`) or a - // block. If block, check that we are the last expr. - self.can_be_stmt = name_ref - .syntax() - .ancestors() - .find_map(|node| { - if let Some(stmt) = ast::ExprStmt::cast(node.clone()) { - return Some( - stmt.syntax().text_range() == name_ref.syntax().text_range(), - ); - } - if let Some(block) = ast::BlockExpr::cast(node) { - return Some( - block.expr().map(|e| e.syntax().text_range()) - == Some(name_ref.syntax().text_range()), - ); - } - None - }) - .unwrap_or(false); - self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); + // Find either enclosing expr statement (thing with `;`) or a + // block. If block, check that we are the last expr. + self.can_be_stmt = name_ref + .syntax() + .ancestors() + .find_map(|node| { + if let Some(stmt) = ast::ExprStmt::cast(node.clone()) { + return Some(stmt.syntax().text_range() == name_ref.syntax().text_range()); + } + if let Some(block) = ast::BlockExpr::cast(node) { + return Some( + block.expr().map(|e| e.syntax().text_range()) + == Some(name_ref.syntax().text_range()), + ); + } + None + }) + .unwrap_or(false); + self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some(); - if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { - if let Some(if_expr) = - self.sema.find_node_at_offset_with_macros::(original_file, off) + if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { + if let Some(if_expr) = + self.sema.find_node_at_offset_with_macros::(original_file, off) + { + if if_expr.syntax().text_range().end() < name_ref.syntax().text_range().start() { - if if_expr.syntax().text_range().end() - < name_ref.syntax().text_range().start() - { - self.after_if = true; - } + self.after_if = true; } } } @@ -469,3 +475,12 @@ fn is_node(node: &SyntaxNode) -> bool { Some(n) => n.syntax().text_range() == node.text_range(), } } + +fn path_or_use_tree_qualifier(path: &ast::Path) -> Option { + if let Some(qual) = path.qualifier() { + return Some(qual); + } + let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; + let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; + use_tree.path() +}