diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 3f940124cc5..37a0504150c 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -308,7 +308,11 @@ pub(crate) fn resolve_path( } } - resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) + if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { + resolve_hir_path_qualifier(db, &self.resolver, &hir_path) + } else { + resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) + } } pub(crate) fn record_literal_missing_fields( diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 61b6671044d..d2d0e4a98f3 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -2,7 +2,7 @@ use std::iter; -use syntax::SyntaxKind; +use syntax::{SyntaxKind, T}; use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; @@ -54,7 +54,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword(ctx, acc, "where", "where "); return; } - if ctx.unsafe_is_prev { + if ctx.previous_token_is(T![unsafe]) { if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { add_keyword(ctx, acc, "fn", "fn $0() {}") } @@ -92,7 +92,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword(ctx, acc, "for", "for $1 in $0 {}"); } - if ctx.if_is_prev || ctx.block_expr_parent { + if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || ctx.block_expr_parent { add_keyword(ctx, acc, "let", "let "); } diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 2f3fb17100f..85c7edabb63 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -1,25 +1,26 @@ //! See `CompletionContext` structure. use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; -use ide_db::base_db::{FilePosition, SourceDatabase}; -use ide_db::{call_info::ActiveParameter, RootDatabase}; +use ide_db::{ + base_db::{FilePosition, SourceDatabase}, + call_info::ActiveParameter, + RootDatabase, +}; use syntax::{ algo::find_node_at_offset, ast::{self, NameOrNameRef, NameOwner}, match_ast, AstNode, NodeOrToken, - SyntaxKind::*, - SyntaxNode, SyntaxToken, TextRange, TextSize, + SyntaxKind::{self, *}, + SyntaxNode, SyntaxToken, TextRange, TextSize, T, }; - use text_edit::Indel; use crate::{ patterns::{ - fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent, - has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent, - has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling, - has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm, - unsafe_is_prev, + for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent, + has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent, + has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, inside_impl_trait_block, + is_in_loop_body, is_match_arm, previous_token, }, CompletionConfig, }; @@ -81,25 +82,26 @@ pub(crate) struct CompletionContext<'a> { pub(super) is_path_type: bool, pub(super) has_type_args: bool, pub(super) attribute_under_caret: Option, + pub(super) locals: Vec<(String, Local)>, + pub(super) mod_declaration_under_caret: Option, - pub(super) unsafe_is_prev: bool, - pub(super) if_is_prev: bool, + pub(super) has_trait_parent: bool, + pub(super) has_impl_parent: bool, + + // keyword patterns + pub(super) previous_token: Option, pub(super) block_expr_parent: bool, pub(super) bind_pat_parent: bool, pub(super) ref_pat_parent: bool, pub(super) in_loop_body: bool, - pub(super) has_trait_parent: bool, - pub(super) has_impl_parent: bool, - pub(super) inside_impl_trait_block: bool, pub(super) has_field_list_parent: bool, pub(super) trait_as_prev_sibling: bool, pub(super) impl_as_prev_sibling: bool, pub(super) is_match_arm: bool, pub(super) has_item_list_or_source_file_parent: bool, - pub(super) for_is_prev2: bool, - pub(super) fn_is_prev: bool, pub(super) incomplete_let: bool, - pub(super) locals: Vec<(String, Local)>, + + no_completion_required: bool, } impl<'a> CompletionContext<'a> { @@ -175,22 +177,19 @@ pub(super) fn new( has_type_args: false, attribute_under_caret: None, mod_declaration_under_caret: None, - unsafe_is_prev: false, - if_is_prev: false, + previous_token: None, block_expr_parent: false, bind_pat_parent: false, ref_pat_parent: false, in_loop_body: false, has_trait_parent: false, has_impl_parent: false, - inside_impl_trait_block: false, has_field_list_parent: false, trait_as_prev_sibling: false, impl_as_prev_sibling: false, is_match_arm: false, has_item_list_or_source_file_parent: false, - for_is_prev2: false, - fn_is_prev: false, + no_completion_required: false, incomplete_let: false, locals, }; @@ -245,7 +244,7 @@ pub(super) fn new( /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. /// - `for _ i$0` -- obviously, it'll be "in" keyword. pub(crate) fn no_completion_required(&self) -> bool { - (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2 + self.no_completion_required } /// The range of the identifier that is being completed. @@ -264,33 +263,39 @@ pub(crate) fn source_range(&self) -> TextRange { } } + pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool { + self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) + } + fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); let syntax_element = NodeOrToken::Token(fake_ident_token); + self.previous_token = previous_token(syntax_element.clone()); self.block_expr_parent = has_block_expr_parent(syntax_element.clone()); - self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone()); - self.if_is_prev = if_is_prev(syntax_element.clone()); self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); self.ref_pat_parent = has_ref_parent(syntax_element.clone()); self.in_loop_body = is_in_loop_body(syntax_element.clone()); self.has_trait_parent = has_trait_parent(syntax_element.clone()); self.has_impl_parent = has_impl_parent(syntax_element.clone()); - self.inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); self.is_match_arm = is_match_arm(syntax_element.clone()); + self.has_item_list_or_source_file_parent = has_item_list_or_source_file_parent(syntax_element.clone()); self.mod_declaration_under_caret = find_node_at_offset::(&file_with_fake_ident, offset) .filter(|module| module.item_list().is_none()); - self.for_is_prev2 = for_is_prev2(syntax_element.clone()); - self.fn_is_prev = fn_is_prev(syntax_element.clone()); self.incomplete_let = syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { it.syntax().text_range().end() == syntax_element.text_range().end() }); + + let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); + let fn_is_prev = self.previous_token_is(T![fn]); + let for_is_prev2 = for_is_prev2(syntax_element.clone()); + self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2; } fn fill_impl_def(&mut self) { diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index d82564381d1..3d8a83ed872 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -115,36 +115,8 @@ fn test_is_match_arm() { check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); } -pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { - element - .into_token() - .and_then(|it| previous_non_trivia_token(it)) - .filter(|it| it.kind() == T![unsafe]) - .is_some() -} -#[test] -fn test_unsafe_is_prev() { - check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev); -} - -pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { - element - .into_token() - .and_then(|it| previous_non_trivia_token(it)) - .filter(|it| it.kind() == T![if]) - .is_some() -} - -pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool { - element - .into_token() - .and_then(|it| previous_non_trivia_token(it)) - .filter(|it| it.kind() == T![fn]) - .is_some() -} -#[test] -fn test_fn_is_prev() { - check_pattern_is_applicable(r"fn l$0", fn_is_prev); +pub(crate) fn previous_token(element: SyntaxElement) -> Option { + element.into_token().and_then(|it| previous_non_trivia_token(it)) } /// Check if the token previous to the previous one is `for`. @@ -162,11 +134,6 @@ fn test_for_is_prev2() { check_pattern_is_applicable(r"for i i$0", for_is_prev2); } -#[test] -fn test_if_is_prev() { - check_pattern_is_applicable(r"if l$0", if_is_prev); -} - pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some() }