Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context/analysis.rs')
| -rw-r--r-- | crates/ide-completion/src/context/analysis.rs | 94 |
1 files changed, 47 insertions, 47 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 77a94403ab..873eceff5f 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1,7 +1,6 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use base_db::salsa; use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; use ide_db::{RootDatabase, active_parameter::ActiveParameter}; use itertools::Either; @@ -20,12 +19,15 @@ use syntax::{ match_ast, }; -use crate::context::{ - AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx, - DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, - NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, PathKind, - PatternContext, PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget, - TypeLocation, +use crate::{ + completions::postfix::is_in_condition, + context::{ + AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx, + DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, + NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, + PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx, + TypeAscriptionTarget, TypeLocation, + }, }; #[derive(Debug)] @@ -86,7 +88,7 @@ pub(super) fn expand_and_analyze<'db>( let original_offset = expansion.original_offset + relative_offset; let token = expansion.original_file.token_at_offset(original_offset).left_biased()?; - salsa::attach(sema.db, || analyze(sema, expansion, original_token, &token)).map( + hir::attach_db(sema.db, || analyze(sema, expansion, original_token, &token)).map( |(analysis, expected, qualifier_ctx)| AnalysisResult { analysis, expected, @@ -563,10 +565,10 @@ fn analyze<'db>( /// Calculate the expected type and name of the cursor position. fn expected_type_and_name<'db>( sema: &Semantics<'db, RootDatabase>, - token: &SyntaxToken, + self_token: &SyntaxToken, name_like: &ast::NameLike, ) -> (Option<Type<'db>>, Option<NameOrNameRef>) { - let token = prev_special_biased_token_at_trivia(token.clone()); + let token = prev_special_biased_token_at_trivia(self_token.clone()); let mut node = match token.parent() { Some(it) => it, None => return (None, None), @@ -756,7 +758,15 @@ fn expected_type_and_name<'db>( .map(|c| (Some(c.return_type()), None)) .unwrap_or((None, None)) }, - ast::ParamList(_) => (None, None), + ast::ParamList(it) => { + let closure = it.syntax().parent().and_then(ast::ClosureExpr::cast); + let ty = closure + .filter(|_| it.syntax().text_range().end() <= self_token.text_range().start()) + .and_then(|it| sema.type_of_expr(&it.into())); + ty.and_then(|ty| ty.original.as_callable(sema.db)) + .map(|c| (Some(c.return_type()), None)) + .unwrap_or((None, None)) + }, ast::Stmt(_) => (None, None), ast::Item(_) => (None, None), _ => { @@ -916,7 +926,7 @@ fn classify_name_ref<'db>( receiver_ty, kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) } + ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()).unzip().0 } }); return Some(make_res(kind)); }, @@ -931,7 +941,7 @@ fn classify_name_ref<'db>( receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), kind: DotAccessKind::Method { has_parens }, receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) } + ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()).unzip().0 } }); return Some(make_res(kind)); }, @@ -1216,28 +1226,10 @@ fn classify_name_ref<'db>( Some(res) }; - fn is_in_condition(it: &ast::Expr) -> bool { - (|| { - let parent = it.syntax().parent()?; - if let Some(expr) = ast::WhileExpr::cast(parent.clone()) { - Some(expr.condition()? == *it) - } else if let Some(expr) = ast::IfExpr::cast(parent.clone()) { - Some(expr.condition()? == *it) - } else if let Some(expr) = ast::BinExpr::cast(parent) - && expr.op_token()?.kind() == T![&&] - { - Some(is_in_condition(&expr.into())) - } else { - None - } - })() - .unwrap_or(false) - } - let make_path_kind_expr = |expr: ast::Expr| { let it = expr.syntax(); let in_block_expr = is_in_block(it); - let in_loop_body = is_in_breakable(it); + let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip(); let after_if_expr = after_if_expr(it.clone()); let ref_expr_parent = path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); @@ -1291,6 +1283,11 @@ fn classify_name_ref<'db>( None => (None, None), } }; + let innermost_breakable_ty = innermost_breakable + .and_then(ast::Expr::cast) + .and_then(|expr| find_node_in_file_compensated(sema, original_file, &expr)) + .and_then(|expr| sema.type_of_expr(&expr)) + .map(|ty| if ty.original.is_never() { ty.adjusted() } else { ty.original() }); let is_func_update = func_update_record(it); let in_condition = is_in_condition(&expr); let after_incomplete_let = after_incomplete_let(it.clone()).is_some(); @@ -1303,7 +1300,8 @@ fn classify_name_ref<'db>( .is_some_and(|it| it.semicolon_token().is_none()) || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw; let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some(); - let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); + let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax()) + .and_then(Either::left); let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) { Some(arm) => arm @@ -1323,6 +1321,7 @@ fn classify_name_ref<'db>( after_amp, is_func_update, innermost_ret_ty, + innermost_breakable_ty, self_param, in_value, incomplete_let, @@ -1756,27 +1755,29 @@ fn pattern_context_for( mut_token, ref_token, record_pat: None, - impl_: fetch_immediate_impl(sema, original_file, pat.syntax()), + impl_or_trait: fetch_immediate_impl_or_trait(sema, original_file, pat.syntax()), missing_variants, } } -fn fetch_immediate_impl( +fn fetch_immediate_impl_or_trait( sema: &Semantics<'_, RootDatabase>, original_file: &SyntaxNode, node: &SyntaxNode, -) -> Option<ast::Impl> { +) -> Option<Either<ast::Impl, ast::Trait>> { let mut ancestors = ancestors_in_file_compensated(sema, original_file, node)? .filter_map(ast::Item::cast) .filter(|it| !matches!(it, ast::Item::MacroCall(_))); match ancestors.next()? { ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (), - ast::Item::Impl(it) => return Some(it), + ast::Item::Impl(it) => return Some(Either::Left(it)), + ast::Item::Trait(it) => return Some(Either::Right(it)), _ => return None, } match ancestors.next()? { - ast::Item::Impl(it) => Some(it), + ast::Item::Impl(it) => Some(Either::Left(it)), + ast::Item::Trait(it) => Some(Either::Right(it)), _ => None, } } @@ -1870,24 +1871,22 @@ fn is_in_token_of_for_loop(path: &ast::Path) -> bool { .unwrap_or(false) } -fn is_in_breakable(node: &SyntaxNode) -> BreakableKind { +fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> { node.ancestors() .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR) .find_map(|it| { let (breakable, loop_body) = match_ast! { match it { - ast::ForExpr(it) => (BreakableKind::For, it.loop_body()), - ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()), - ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()), - ast::BlockExpr(it) => return it.label().map(|_| BreakableKind::Block), + ast::ForExpr(it) => (BreakableKind::For, it.loop_body()?), + ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()?), + ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()?), + ast::BlockExpr(it) => return it.label().map(|_| (BreakableKind::Block, it.syntax().clone())), _ => return None, } }; - loop_body - .filter(|it| it.syntax().text_range().contains_range(node.text_range())) - .map(|_| breakable) + loop_body.syntax().text_range().contains_range(node.text_range()) + .then_some((breakable, it)) }) - .unwrap_or(BreakableKind::None) } fn is_in_block(node: &SyntaxNode) -> bool { @@ -1938,6 +1937,7 @@ fn prev_special_biased_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken { | T![|=] | T![&=] | T![^=] + | T![|] | T![return] | T![break] | T![continue] = prev.kind() |