1use std::iter;
3
4use hir::{EnumVariant, ExpandResult, InFile, Semantics, Type, TypeInfo};
5use ide_db::{
6 RootDatabase, active_parameter::ActiveParameter, syntax_helpers::node_ext::find_loops,
7};
8use itertools::{Either, Itertools};
9use stdx::always;
10use syntax::{
11 AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
12 T, TextRange, TextSize,
13 algo::{
14 self, ancestors_at_offset, find_node_at_offset, non_trivia_sibling,
15 previous_non_trivia_token,
16 },
17 ast::{
18 self, AttrKind, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
19 NameOrNameRef,
20 },
21 match_ast,
22};
23
24use crate::{
25 completions::postfix::{is_in_condition, is_in_value},
26 context::{
27 AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx,
28 DotAccessKind, ExpectedInfo, ItemListKind, LifetimeContext, LifetimeKind, NameContext,
29 NameKind, NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx,
30 PathExprCtx, PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
31 TypeAscriptionTarget, TypeLocation,
32 },
33};
34
35#[derive(Debug)]
36struct ExpansionResult {
37 original_file: SyntaxNode,
38 speculative_file: SyntaxNode,
39 original_offset: TextSize,
41 speculative_offset: TextSize,
43 fake_ident_token: SyntaxToken,
44 derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
45}
46
47pub(super) struct AnalysisResult<'db> {
48 pub(super) analysis: CompletionAnalysis<'db>,
49 pub(super) expected: ExpectedInfo<'db>,
50 pub(super) qualifier_ctx: QualifierCtx,
51 pub(super) token: SyntaxToken,
53 pub(super) original_offset: TextSize,
55}
56
57pub(super) fn expand_and_analyze<'db>(
58 sema: &Semantics<'db, RootDatabase>,
59 original_file: InFile<SyntaxNode>,
60 speculative_file: SyntaxNode,
61 offset: TextSize,
62 original_token: &SyntaxToken,
63) -> Option<AnalysisResult<'db>> {
64 let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?;
67 let relative_offset = offset - fake_ident_token.text_range().start();
69 let offset = offset - relative_offset;
72 let expansion = expand_maybe_stop(
73 sema,
74 original_file.clone(),
75 speculative_file.clone(),
76 offset,
77 fake_ident_token.clone(),
78 relative_offset,
79 )
80 .unwrap_or(ExpansionResult {
81 original_file: original_file.value,
82 speculative_file,
83 original_offset: offset,
84 speculative_offset: fake_ident_token.text_range().start(),
85 fake_ident_token,
86 derive_ctx: None,
87 });
88
89 let original_offset = expansion.original_offset + relative_offset;
91 let token = expansion.original_file.token_at_offset(original_offset).left_biased()?;
92
93 analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
94 AnalysisResult { analysis, expected, qualifier_ctx, token, original_offset }
95 })
96}
97
98fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> {
99 let token = file.token_at_offset(offset).left_biased()?;
100 algo::skip_whitespace_token(token, Direction::Prev)
101}
102
103fn expand_maybe_stop(
133 sema: &Semantics<'_, RootDatabase>,
134 original_file: InFile<SyntaxNode>,
135 speculative_file: SyntaxNode,
136 original_offset: TextSize,
137 fake_ident_token: SyntaxToken,
138 relative_offset: TextSize,
139) -> Option<ExpansionResult> {
140 if let result @ Some(_) = expand(
141 sema,
142 original_file.clone(),
143 speculative_file.clone(),
144 original_offset,
145 fake_ident_token.clone(),
146 relative_offset,
147 ) {
148 return result;
149 }
150
151 if token_at_offset_ignore_whitespace(&original_file.value, original_offset + relative_offset)
154 .is_some_and(|original_token| {
155 !sema.is_inside_macro_call(original_file.with_value(&original_token))
156 })
157 {
158 Some(ExpansionResult {
160 original_file: original_file.value,
161 speculative_file,
162 original_offset,
163 speculative_offset: fake_ident_token.text_range().start(),
164 fake_ident_token,
165 derive_ctx: None,
166 })
167 } else {
168 None
169 }
170}
171
172fn expand(
173 sema: &Semantics<'_, RootDatabase>,
174 original_file: InFile<SyntaxNode>,
175 speculative_file: SyntaxNode,
176 original_offset: TextSize,
177 fake_ident_token: SyntaxToken,
178 relative_offset: TextSize,
179) -> Option<ExpansionResult> {
180 let _p = tracing::info_span!("CompletionContext::expand").entered();
181
182 let parent_item =
183 |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
184 let original_node = token_at_offset_ignore_whitespace(&original_file.value, original_offset)
185 .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast));
186 let ancestor_items = iter::successors(
187 Option::zip(
188 original_node,
189 find_node_at_offset::<ast::Item>(
190 &speculative_file,
191 fake_ident_token.text_range().start(),
192 ),
193 ),
194 |(a, b)| parent_item(a).zip(parent_item(b)),
195 );
196
197 'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
199 match (
200 sema.expand_attr_macro(&actual_item),
201 sema.speculative_expand_attr_macro(
202 &actual_item,
203 &item_with_fake_ident,
204 fake_ident_token.clone(),
205 ),
206 ) {
207 (None, None) => continue 'ancestors,
209 (
211 Some(ExpandResult { value: actual_expansion, err: _ }),
212 Some((fake_expansion, fake_mapped_tokens)),
213 ) => {
214 let mut accumulated_offset_from_fake_tokens = 0;
215 let actual_range = actual_expansion.text_range().end();
216 let result = fake_mapped_tokens
217 .into_iter()
218 .filter_map(|(fake_mapped_token, rank)| {
219 let accumulated_offset = accumulated_offset_from_fake_tokens;
220 if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
221 return None;
225 }
226 accumulated_offset_from_fake_tokens += COMPLETION_MARKER.len();
227
228 let new_offset = fake_mapped_token.text_range().start()
229 - TextSize::new(accumulated_offset as u32);
230 if new_offset + relative_offset > actual_range {
231 return None;
234 }
235 let result = expand_maybe_stop(
236 sema,
237 actual_expansion.clone(),
238 fake_expansion.clone(),
239 new_offset,
240 fake_mapped_token,
241 relative_offset,
242 )?;
243 Some((result, rank))
244 })
245 .min_by_key(|(_, rank)| *rank)
246 .map(|(result, _)| result);
247 if result.is_some() {
248 return result;
249 }
250 }
251 _ => break 'ancestors,
253 }
254 }
255
256 let orig_tt = ancestors_at_offset(&original_file.value, original_offset)
258 .map_while(Either::<ast::TokenTree, ast::Meta>::cast)
259 .last()?;
260 let spec_tt = ancestors_at_offset(&speculative_file, fake_ident_token.text_range().start())
261 .map_while(Either::<ast::TokenTree, ast::Meta>::cast)
262 .last()?;
263
264 let (tts, attrs) = match (orig_tt, spec_tt) {
265 (Either::Left(orig_tt), Either::Left(spec_tt)) => {
266 let attrs = orig_tt
267 .syntax()
268 .parent()
269 .and_then(ast::Meta::cast)
270 .and_then(|it| it.parent_attr())
271 .zip(
272 spec_tt
273 .syntax()
274 .parent()
275 .and_then(ast::Meta::cast)
276 .and_then(|it| it.parent_attr()),
277 );
278 (Some((orig_tt, spec_tt)), attrs)
279 }
280 (Either::Right(orig_path), Either::Right(spec_path)) => {
281 (None, orig_path.parent_attr().zip(spec_path.parent_attr()))
282 }
283 _ => return None,
284 };
285
286 if let Some((orig_attr, spec_attr)) = attrs
288 && let Some(orig_meta) = orig_attr.meta()
289 {
290 if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_tokens))) = (
292 sema.expand_derive_as_pseudo_attr_macro(&orig_meta),
293 sema.speculative_expand_derive_as_pseudo_attr_macro(
294 &orig_attr,
295 &spec_attr,
296 fake_ident_token.clone(),
297 ),
298 ) && let Some((fake_mapped_token, _)) =
299 fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank)
300 {
301 return Some(ExpansionResult {
302 original_file: original_file.value,
303 speculative_file,
304 original_offset,
305 speculative_offset: fake_ident_token.text_range().start(),
306 fake_ident_token,
307 derive_ctx: Some((
308 actual_expansion,
309 fake_expansion,
310 fake_mapped_token.text_range().start(),
311 orig_attr,
312 )),
313 });
314 }
315
316 if let Some(spec_adt) =
317 spec_attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
318 ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
319 ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
320 ast::Item::Union(it) => Some(ast::Adt::Union(it)),
321 _ => None,
322 })
323 {
324 if let Some(helpers) = sema.derive_helper(&orig_attr) {
326 for (_mac, file) in helpers {
327 if let Some((fake_expansion, fake_mapped_tokens)) = sema.speculative_expand_raw(
328 file,
329 spec_adt.syntax(),
330 fake_ident_token.clone(),
331 ) {
332 let actual_expansion = sema.parse_or_expand(file.into());
335 let mut accumulated_offset_from_fake_tokens = 0;
336 let actual_range = actual_expansion.text_range().end();
337 let result = fake_mapped_tokens
338 .into_iter()
339 .filter_map(|(fake_mapped_token, rank)| {
340 let accumulated_offset = accumulated_offset_from_fake_tokens;
341 if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
342 return None;
346 }
347 accumulated_offset_from_fake_tokens += COMPLETION_MARKER.len();
348
349 let new_offset = fake_mapped_token.text_range().start()
350 - TextSize::new(accumulated_offset as u32);
351 if new_offset + relative_offset > actual_range {
352 return None;
355 }
356 let result = expand_maybe_stop(
357 sema,
358 InFile::new(file.into(), actual_expansion.clone()),
359 fake_expansion.clone(),
360 new_offset,
361 fake_mapped_token,
362 relative_offset,
363 )?;
364 Some((result, rank))
365 })
366 .min_by_key(|(_, rank)| *rank)
367 .map(|(result, _)| result);
368 if result.is_some() {
369 return result;
370 }
371 }
372 }
373 }
374 }
375 return None;
377 }
378
379 let (orig_tt, spec_tt) = tts?;
381 let (actual_macro_call, macro_call_with_fake_ident) = (
382 orig_tt.syntax().parent().and_then(ast::MacroCall::cast)?,
383 spec_tt.syntax().parent().and_then(ast::MacroCall::cast)?,
384 );
385 let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
386 let mac_call_path1 = macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
387
388 if mac_call_path0 != mac_call_path1 {
390 return None;
391 }
392 let speculative_args = macro_call_with_fake_ident.token_tree()?;
393
394 match (
395 sema.expand_macro_call(&actual_macro_call),
396 sema.speculative_expand_macro_call(&actual_macro_call, &speculative_args, fake_ident_token),
397 ) {
398 (Some(actual_expansion), Some((fake_expansion, fake_mapped_tokens))) => {
400 let mut accumulated_offset_from_fake_tokens = 0;
401 let actual_range = actual_expansion.text_range().end();
402 fake_mapped_tokens
403 .into_iter()
404 .filter_map(|(fake_mapped_token, rank)| {
405 let accumulated_offset = accumulated_offset_from_fake_tokens;
406 if !fake_mapped_token.text().contains(COMPLETION_MARKER) {
407 return None;
411 }
412 accumulated_offset_from_fake_tokens += COMPLETION_MARKER.len();
413
414 let new_offset = fake_mapped_token.text_range().start()
415 - TextSize::new(accumulated_offset as u32);
416 if new_offset + relative_offset > actual_range {
417 return None;
420 }
421 let result = expand_maybe_stop(
422 sema,
423 actual_expansion.clone(),
424 fake_expansion.clone(),
425 new_offset,
426 fake_mapped_token,
427 relative_offset,
428 )?;
429 Some((result, rank))
430 })
431 .min_by_key(|(_, rank)| *rank)
432 .map(|(result, _)| result)
433 }
434 _ => None,
437 }
438}
439
440fn analyze<'db>(
443 sema: &Semantics<'db, RootDatabase>,
444 expansion_result: ExpansionResult,
445 original_token: &SyntaxToken,
446 self_token: &SyntaxToken,
447) -> Option<(CompletionAnalysis<'db>, ExpectedInfo<'db>, QualifierCtx)> {
448 let _p = tracing::info_span!("CompletionContext::analyze").entered();
449 let ExpansionResult {
450 original_file,
451 speculative_file,
452 original_offset: _,
453 speculative_offset,
454 fake_ident_token,
455 derive_ctx,
456 } = expansion_result;
457
458 if original_token.kind() != self_token.kind()
459 && !(original_token.kind().is_punct() || original_token.kind().is_trivia())
461 && !(SyntaxKind::is_any_identifier(original_token.kind())
462 && SyntaxKind::is_any_identifier(self_token.kind()))
463 {
464 return None;
465 }
466
467 if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx
469 && let Some(origin_meta) = origin_attr.meta()
470 {
471 if let Some(ast::NameLike::NameRef(name_ref)) =
472 find_node_at_offset(&file_with_fake_ident, offset)
473 {
474 let parent = name_ref.syntax().parent()?;
475 let (mut nameref_ctx, _) =
476 classify_name_ref(sema, &original_file, name_ref, offset, parent)?;
477 if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
478 path_ctx.kind = PathKind::Derive {
479 existing_derives: sema
480 .resolve_derive_macro(&origin_meta)
481 .into_iter()
482 .flatten()
483 .flatten()
484 .collect(),
485 };
486 }
487 return Some((
488 CompletionAnalysis::NameRef(nameref_ctx),
489 ExpectedInfo::default(),
490 QualifierCtx::default(),
491 ));
492 }
493 return None;
494 }
495
496 let Some(name_like) = find_node_at_offset(&speculative_file, speculative_offset) else {
497 let analysis = if let Some(original) = ast::String::cast(original_token.clone())
498 && self_token.parent().is_none_or(|it| !ast::CfgAtom::can_cast(it.kind()))
499 {
500 CompletionAnalysis::String { original, expanded: ast::String::cast(self_token.clone()) }
501 } else {
502 let token = syntax::algo::skip_trivia_token(self_token.clone(), Direction::Prev)?;
505 let p = token.parent()?;
506 if p.kind() == SyntaxKind::TOKEN_TREE
507 && p.ancestors().any(|it| it.kind() == SyntaxKind::TOKEN_TREE_META)
508 {
509 let colon_prefix = previous_non_trivia_token(self_token.clone())
510 .is_some_and(|it| T![:] == it.kind());
511
512 CompletionAnalysis::UnexpandedAttrTT {
513 fake_attribute_under_caret: fake_ident_token
514 .parent_ancestors()
515 .find_map(ast::TokenTreeMeta::cast),
516 colon_prefix,
517 extern_crate: p.ancestors().find_map(ast::ExternCrate::cast),
518 }
519 } else if p.kind() == SyntaxKind::TOKEN_TREE
520 && p.ancestors().any(|it| ast::Macro::can_cast(it.kind()))
521 {
522 if let Some([_ident, colon, _name, dollar]) = fake_ident_token
523 .siblings_with_tokens(Direction::Prev)
524 .filter(|it| !it.kind().is_trivia())
525 .take(4)
526 .collect_array()
527 && dollar.kind() == T![$]
528 && colon.kind() == T![:]
529 {
530 CompletionAnalysis::MacroSegment
531 } else {
532 return None;
533 }
534 } else if find_node_at_offset::<ast::CfgPredicate>(
535 &speculative_file,
536 speculative_offset,
537 )
538 .is_some()
539 {
540 CompletionAnalysis::CfgPredicate
541 } else {
542 return None;
543 }
544 };
545 return Some((analysis, ExpectedInfo::default(), QualifierCtx::default()));
546 };
547
548 let expected = expected_type_and_name(sema, self_token, &name_like);
549 let mut qual_ctx = QualifierCtx::default();
550 let analysis = match name_like {
551 ast::NameLike::Lifetime(lifetime) => {
552 CompletionAnalysis::Lifetime(classify_lifetime(sema, &original_file, lifetime)?)
553 }
554 ast::NameLike::NameRef(name_ref) => {
555 let parent = name_ref.syntax().parent()?;
556 let (nameref_ctx, qualifier_ctx) = classify_name_ref(
557 sema,
558 &original_file,
559 name_ref,
560 expansion_result.original_offset,
561 parent,
562 )?;
563
564 if let NameRefContext {
565 kind:
566 NameRefKind::Path(PathCompletionCtx { kind: PathKind::Expr { .. }, path, .. }, ..),
567 ..
568 } = &nameref_ctx
569 && is_in_token_of_for_loop(path)
570 {
571 return None;
576 }
577
578 qual_ctx = qualifier_ctx;
579 CompletionAnalysis::NameRef(nameref_ctx)
580 }
581 ast::NameLike::Name(name) => {
582 let name_ctx = classify_name(sema, &original_file, name)?;
583 CompletionAnalysis::Name(name_ctx)
584 }
585 };
586 Some((analysis, expected, qual_ctx))
587}
588
589fn expected_type_and_name<'db>(
591 sema: &Semantics<'db, RootDatabase>,
592 self_token: &SyntaxToken,
593 name_like: &ast::NameLike,
594) -> ExpectedInfo<'db> {
595 let token = prev_special_biased_token_at_trivia(self_token.clone());
596 let mut node = match token.parent() {
597 Some(it) => it,
598 None => return ExpectedInfo::default(),
599 };
600
601 let strip_refs = |mut ty: Type<'db>| match name_like {
602 ast::NameLike::NameRef(n) => {
603 let p = match n.syntax().parent() {
604 Some(it) => it,
605 None => return ty,
606 };
607 let top_syn = match_ast! {
608 match p {
609 ast::FieldExpr(e) => e
610 .syntax()
611 .ancestors()
612 .take_while(|it| ast::FieldExpr::can_cast(it.kind()))
613 .last(),
614 ast::PathSegment(e) => e
615 .syntax()
616 .ancestors()
617 .skip(1)
618 .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
619 .find(|it| ast::PathExpr::can_cast(it.kind())),
620 _ => None
621 }
622 };
623 let top_syn = match top_syn {
624 Some(it) => it,
625 None => return ty,
626 };
627 let refs_level = top_syn
628 .ancestors()
629 .skip(1)
630 .map_while(Either::<ast::RefExpr, ast::PrefixExpr>::cast)
631 .take_while(|it| match it {
632 Either::Left(_) => true,
633 Either::Right(prefix) => prefix.op_kind() == Some(ast::UnaryOp::Deref),
634 })
635 .fold(0i32, |level, expr| match expr {
636 Either::Left(_) => level + 1,
637 Either::Right(_) => level - 1,
638 });
639 for _ in 0..refs_level {
640 cov_mark::hit!(expected_type_fn_param_ref);
641 ty = ty.strip_reference();
642 }
643 for _ in refs_level..0 {
644 cov_mark::hit!(expected_type_fn_param_deref);
645 ty = ty.add_reference(sema.db, hir::Mutability::Shared);
646 }
647 ty
648 }
649 _ => ty,
650 };
651
652 let mut generic_def = None;
653 let mut original_ty = None;
654 let mut rebase_ty = {
655 let node = node.clone();
656 move |ty: hir::Type<'db>| {
657 let def = *generic_def
658 .get_or_insert_with(|| sema.scope(&node).and_then(|scope| scope.generic_def()));
659 def.and_then(|def| ty.try_rebase_into_owner(sema.db, def))
660 .unwrap_or_else(|| ty.instantiate_with_errors())
661 }
662 };
663 let (ty, name) = loop {
664 break match_ast! {
665 match node {
666 ast::LetStmt(it) => {
667 cov_mark::hit!(expected_type_let_with_leading_char);
668 cov_mark::hit!(expected_type_let_without_leading_char);
669 let ty = it.pat()
670 .and_then(|pat| sema.type_of_pat(&pat))
671 .or_else(|| it.initializer().and_then(|it| sema.type_of_expr(&it)))
672 .map(TypeInfo::original)
673 .filter(|ty| {
674 it.ty().is_some() || !ty.is_fn()
677 });
678 let name = match it.pat() {
679 Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
680 Some(_) | None => None,
681 };
682
683 (ty, name)
684 },
685 ast::LetExpr(it) => {
686 cov_mark::hit!(expected_type_if_let_without_leading_char);
687 let ty = it.pat()
688 .and_then(|pat| sema.type_of_pat(&pat))
689 .or_else(|| it.expr().and_then(|it| sema.type_of_expr(&it)))
690 .map(TypeInfo::original);
691 (ty, None)
692 },
693 ast::BinExpr(it) => {
694 if let Some(ast::BinaryOp::Assignment { op: None }) = it.op_kind() {
695 let ty = it.lhs()
696 .and_then(|lhs| sema.type_of_expr(&lhs))
697 .or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs)))
698 .map(TypeInfo::original);
699 (ty, None)
700 } else if let Some(ast::BinaryOp::LogicOp(_)) = it.op_kind() {
701 let ty = sema.type_of_expr(&it.clone().into()).map(TypeInfo::original);
702 (ty, None)
703 } else {
704 (None, None)
705 }
706 },
707 ast::ArgList(_) => {
708 cov_mark::hit!(expected_type_fn_param);
709 ActiveParameter::at_token(
710 sema,
711 token.clone(),
712 ).map(|ap| {
713 let name = ap.ident().map(NameOrNameRef::Name);
714 original_ty.get_or_insert(ap.original.map(|it| it.ty().clone()));
715 (Some(ap.ty), name)
716 })
717 .unwrap_or((None, None))
718 },
719 ast::RecordExprFieldList(it) => {
720 (|| {
722 if token.kind() == T![..]
723 ||token.prev_token().map(|t| t.kind()) == Some(T![..])
724 {
725 cov_mark::hit!(expected_type_struct_func_update);
726 let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?;
727 let ty = sema.type_of_expr(&record_expr.into())?;
728 Some((
729 Some(ty.original),
730 None
731 ))
732 } else {
733 cov_mark::hit!(expected_type_struct_field_without_leading_char);
734 cov_mark::hit!(expected_type_struct_field_followed_by_comma);
735 let expr_field = previous_non_trivia_token(token.clone())?.parent().and_then(ast::RecordExprField::cast)?;
736 let (_, _, ty) = sema.resolve_record_field(&expr_field)?;
737 Some((
738 Some(ty),
739 expr_field.field_name().map(NameOrNameRef::NameRef),
740 ))
741 }
742 })().unwrap_or((None, None))
743 },
744 ast::RecordExprField(it) => {
745 let field_ty = sema.resolve_record_field(&it).map(|(_, _, ty)| ty);
746 let field_name = it.field_name().map(NameOrNameRef::NameRef);
747 if let Some(expr) = it.expr() {
748 cov_mark::hit!(expected_type_struct_field_with_leading_char);
749 let ty = field_ty
750 .or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original));
751 (ty, field_name)
752 } else {
753 (field_ty, field_name)
754 }
755 },
756 ast::MatchExpr(it) => {
759 let on_arrow = previous_non_trivia_token(token.clone()).is_some_and(|it| T![=>] == it.kind());
760
761 let ty = if on_arrow {
762 cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
764 cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
765 sema.type_of_expr(&it.into())
766 } else {
767 cov_mark::hit!(expected_type_match_arm_without_leading_char);
769 it.expr().and_then(|e| sema.type_of_expr(&e))
770 }.map(TypeInfo::original);
771 (ty, None)
772 },
773 ast::MatchArm(it) => {
774 let on_arrow = previous_non_trivia_token(token.clone()).is_some_and(|it| T![=>] == it.kind());
775 let in_body = it.expr().is_some_and(|it| it.syntax().text_range().contains_range(token.text_range()));
776 let match_expr = it.parent_match();
777
778 let ty = if on_arrow || in_body {
779 cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
781 cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
782 sema.type_of_expr(&match_expr.into())
783 } else {
784 cov_mark::hit!(expected_type_match_arm_without_leading_char);
786 match_expr.expr().and_then(|e| sema.type_of_expr(&e))
787 }.map(TypeInfo::original);
788 (ty, None)
789 },
790 ast::IfExpr(it) => {
791 let ty = if let Some(body) = it.then_branch()
792 && token.text_range().end() > body.syntax().text_range().start()
793 {
794 sema.type_of_expr(&body.into())
795 } else {
796 it.condition().and_then(|e| sema.type_of_expr(&e))
797 }.map(TypeInfo::original);
798 (ty, None)
799 },
800 ast::MatchGuard(it) => {
801 let ty = it.condition().and_then(|e| sema.type_of_expr(&e)).map(TypeInfo::original);
802 (ty, None)
803 },
804 ast::IdentPat(it) => {
805 cov_mark::hit!(expected_type_if_let_with_leading_char);
806 cov_mark::hit!(expected_type_match_arm_with_leading_char);
807 let ty = sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original);
808 (ty, None)
809 },
810 ast::TupleStructPat(it) => {
811 let fields = sema.resolve_tuple_struct_pat_fields(&it);
812 let nr = it.fields().take_while(|it| it.syntax().text_range().end() <= token.text_range().start()).count();
813 let ty = fields.and_then(|fields| Some(rebase_ty(fields.get(nr)?.1.clone())));
814 (ty, None)
815 },
816 ast::Fn(it) => {
817 cov_mark::hit!(expected_type_fn_ret_with_leading_char);
818 cov_mark::hit!(expected_type_fn_ret_without_leading_char);
819 let def = sema.to_def(&it);
820 (def.map(|def| rebase_ty(def.ret_type(sema.db))), None)
821 },
822 ast::ReturnExpr(it) => {
823 let fn_ = sema.ancestors_with_macros(it.syntax().clone())
824 .find_map(Either::<ast::Fn, ast::ClosureExpr>::cast);
825 let ty = fn_.and_then(|f| match f {
826 Either::Left(f) => Some(rebase_ty(sema.to_def(&f)?.ret_type(sema.db))),
827 Either::Right(f) => {
828 let ty = sema.type_of_expr(&f.into())?.original.as_callable(sema.db)?;
829 Some(ty.return_type())
830 },
831 });
832 (ty, None)
833 },
834 ast::BreakExpr(it) => {
835 let ty = it.break_token()
836 .and_then(|it| find_loops(sema, &it)?.next())
837 .and_then(|expr| sema.type_of_expr(&expr));
838 (ty.map(TypeInfo::original), None)
839 },
840 ast::ClosureExpr(it) => {
841 let ty = sema.type_of_expr(&it.into());
842 ty.and_then(|ty| ty.original.as_callable(sema.db))
843 .map(|c| (Some(c.return_type()), None))
844 .unwrap_or((None, None))
845 },
846 ast::ParamList(it) => {
847 let closure = it.syntax().parent().and_then(ast::ClosureExpr::cast);
848 let ty = closure
849 .filter(|_| it.syntax().text_range().end() <= self_token.text_range().start())
850 .and_then(|it| sema.type_of_expr(&it.into()));
851 ty.and_then(|ty| ty.original.as_callable(sema.db))
852 .map(|c| (Some(c.return_type()), None))
853 .unwrap_or((None, None))
854 },
855 ast::Variant(it) => {
856 let is_simple_field = |field: ast::TupleField| {
857 let Some(ty) = field.ty() else { return true };
858 matches!(ty, ast::Type::PathType(_)) && ty.generic_arg_list().is_none()
859 };
860 let is_simple_variant = matches!(
861 it.field_list(),
862 Some(ast::FieldList::TupleFieldList(list))
863 if list.syntax().children_with_tokens().all(|it| it.kind() != T![,])
864 && list.fields().next().is_none_or(is_simple_field)
865 );
866 (None, it.name().filter(|_| is_simple_variant).map(NameOrNameRef::Name))
867 },
868 ast::Stmt(_) => (None, None),
869 ast::Item(_) => (None, None),
870 _ => {
871 match node.parent() {
872 Some(n) => {
873 node = n;
874 continue;
875 },
876 None => (None, None),
877 }
878 },
879 }
880 };
881 };
882 let expected_func = original_ty.flatten().and_then(|ty| {
884 let is_direct_arg = token
885 .parent()
886 .filter(|it| ast::NameLike::can_cast(it.kind()) || token.kind() == T![::])
887 .into_iter()
888 .flat_map(|it| it.ancestors().skip(1))
889 .find(|it| {
890 !Either::<Either<ast::PathSegment, ast::Path>, ast::PathExpr>::can_cast(it.kind())
891 })
892 == Some(node);
893 is_direct_arg.then_some(()).and_then(|()| ty.as_callable(sema.db))
894 });
895 ExpectedInfo { expected_type: ty.map(strip_refs), expected_name: name, expected_func }
896}
897
898fn classify_lifetime(
899 sema: &Semantics<'_, RootDatabase>,
900 original_file: &SyntaxNode,
901 lifetime: ast::Lifetime,
902) -> Option<LifetimeContext> {
903 let parent = lifetime.syntax().parent()?;
904 if parent.kind() == SyntaxKind::ERROR {
905 return None;
906 }
907
908 let lifetime =
909 find_node_at_offset::<ast::Lifetime>(original_file, lifetime.syntax().text_range().start());
910 let kind = match_ast! {
911 match parent {
912 ast::LifetimeParam(_) => LifetimeKind::LifetimeParam,
913 ast::BreakExpr(_) => LifetimeKind::LabelRef,
914 ast::ContinueExpr(_) => LifetimeKind::LabelRef,
915 ast::Label(_) => LifetimeKind::LabelDef,
916 _ => {
917 let def = lifetime.as_ref().and_then(|lt| sema.scope(lt.syntax())?.generic_def());
918 LifetimeKind::Lifetime { in_lifetime_param_bound: ast::TypeBound::can_cast(parent.kind()), def }
919 },
920 }
921 };
922
923 Some(LifetimeContext { kind })
924}
925
926fn classify_name(
927 sema: &Semantics<'_, RootDatabase>,
928 original_file: &SyntaxNode,
929 name: ast::Name,
930) -> Option<NameContext> {
931 let parent = name.syntax().parent()?;
932 let kind = match_ast! {
933 match parent {
934 ast::Const(_) => NameKind::Const,
935 ast::ConstParam(_) => NameKind::ConstParam,
936 ast::Enum(_) => NameKind::Enum,
937 ast::Fn(_) => NameKind::Function,
938 ast::IdentPat(bind_pat) => {
939 let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into());
940 if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
941 pat_ctx.record_pat = find_node_in_file_compensated(sema, original_file, &record_field.parent_record_pat());
942 }
943
944 NameKind::IdentPat(pat_ctx)
945 },
946 ast::MacroDef(_) => NameKind::MacroDef,
947 ast::MacroRules(_) => NameKind::MacroRules,
948 ast::Module(module) => NameKind::Module(module),
949 ast::RecordField(_) => NameKind::RecordField,
950 ast::Rename(_) => NameKind::Rename,
951 ast::SelfParam(_) => NameKind::SelfParam,
952 ast::Static(_) => NameKind::Static,
953 ast::Struct(_) => NameKind::Struct,
954 ast::Trait(_) => NameKind::Trait,
955 ast::TypeAlias(_) => NameKind::TypeAlias,
956 ast::TypeParam(_) => NameKind::TypeParam,
957 ast::Union(_) => NameKind::Union,
958 ast::Variant(_) => NameKind::Variant,
959 _ => return None,
960 }
961 };
962 let name = find_node_at_offset(original_file, name.syntax().text_range().start());
963 Some(NameContext { name, kind })
964}
965
966fn classify_name_ref<'db>(
967 sema: &Semantics<'db, RootDatabase>,
968 original_file: &SyntaxNode,
969 name_ref: ast::NameRef,
970 original_offset: TextSize,
971 parent: SyntaxNode,
972) -> Option<(NameRefContext<'db>, QualifierCtx)> {
973 let nameref = find_node_at_offset(original_file, original_offset);
974
975 let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
976
977 if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
978 let dot_prefix = previous_non_trivia_token(name_ref.syntax().clone())
979 .is_some_and(|it| T![.] == it.kind());
980
981 return find_node_in_file_compensated(
982 sema,
983 original_file,
984 &record_field.parent_record_lit(),
985 )
986 .map(|expr| NameRefKind::RecordExpr { expr, dot_prefix })
987 .map(make_res);
988 }
989 if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
990 let kind = NameRefKind::Pattern(PatternContext {
991 param_ctx: None,
992 has_type_ascription: false,
993 ref_token: None,
994 mut_token: None,
995 record_pat: find_node_in_file_compensated(
996 sema,
997 original_file,
998 &record_field.parent_record_pat(),
999 ),
1000 ..pattern_context_for(sema, original_file, record_field.parent_record_pat().into())
1001 });
1002 return Some(make_res(kind));
1003 }
1004
1005 let field_expr_handle = |receiver, node| {
1006 let receiver = find_opt_node_in_file(original_file, receiver);
1007 let receiver_is_ambiguous_float_literal = match &receiver {
1008 Some(ast::Expr::Literal(l)) => {
1009 matches!(l.kind(), ast::LiteralKind::FloatNumber { .. })
1010 && l.syntax().last_token().is_some_and(|it| it.text().ends_with('.'))
1011 }
1012 _ => false,
1013 };
1014
1015 let receiver_is_part_of_indivisible_expression = match &receiver {
1016 Some(ast::Expr::IfExpr(_)) => {
1017 let next_token_kind =
1018 next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind());
1019 next_token_kind == Some(SyntaxKind::ELSE_KW)
1020 }
1021 _ => false,
1022 };
1023 if receiver_is_part_of_indivisible_expression {
1024 return None;
1025 }
1026
1027 let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
1028 if receiver_is_ambiguous_float_literal {
1029 always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
1031 receiver_ty =
1032 Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
1033 }
1034
1035 let kind = NameRefKind::DotAccess(DotAccess {
1036 receiver_ty,
1037 kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
1038 receiver,
1039 ctx: DotAccessExprCtx {
1040 in_block_expr: is_in_block(node),
1041 in_breakable: is_in_breakable(node).unzip().0,
1042 },
1043 });
1044 Some(make_res(kind))
1045 };
1046
1047 let segment = match_ast! {
1048 match parent {
1049 ast::PathSegment(segment) => segment,
1050 ast::FieldExpr(field) => {
1051 return field_expr_handle(field.expr(), name_ref.syntax());
1052 },
1053 ast::ExternCrate(_) => {
1054 let kind = NameRefKind::ExternCrate;
1055 return Some(make_res(kind));
1056 },
1057 ast::MethodCallExpr(method) => {
1058 let receiver = find_opt_node_in_file(original_file, method.receiver());
1059 let has_parens = has_parens(&method);
1060 if !has_parens && let Some(res) = field_expr_handle(method.receiver(), name_ref.syntax()) {
1061 return Some(res)
1062 }
1063 let kind = NameRefKind::DotAccess(DotAccess {
1064 receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
1065 kind: DotAccessKind::Method,
1066 receiver,
1067 ctx: DotAccessExprCtx { in_block_expr: is_in_block(name_ref.syntax()), in_breakable: is_in_breakable(name_ref.syntax()).unzip().0 }
1068 });
1069 return Some(make_res(kind));
1070 },
1071 _ => return None,
1072 }
1073 };
1074
1075 let path = segment.parent_path();
1076 let original_path = find_node_in_file_compensated(sema, original_file, &path);
1077
1078 let mut path_ctx = PathCompletionCtx {
1079 has_call_parens: false,
1080 has_macro_bang: false,
1081 qualified: Qualified::No,
1082 parent: None,
1083 path: path.clone(),
1084 original_path,
1085 kind: PathKind::Item { kind: ItemListKind::SourceFile },
1086 has_type_args: false,
1087 use_tree_parent: false,
1088 };
1089
1090 let func_update_record = |syn: &SyntaxNode| {
1091 if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) {
1092 find_node_in_file_compensated(sema, original_file, &record_expr)
1093 } else {
1094 None
1095 }
1096 };
1097 let prev_expr = |node: SyntaxNode| {
1098 let node = match node.parent().and_then(ast::ExprStmt::cast) {
1099 Some(stmt) => stmt.syntax().clone(),
1100 None => node,
1101 };
1102 let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
1103
1104 match_ast! {
1105 match prev_sibling {
1106 ast::ExprStmt(stmt) => stmt.expr().filter(|_| stmt.semicolon_token().is_none()),
1107 ast::LetStmt(stmt) => stmt.initializer().filter(|_| stmt.semicolon_token().is_none()),
1108 ast::Expr(expr) => Some(expr),
1109 _ => None,
1110 }
1111 }
1112 };
1113 let after_incomplete_let = |node: SyntaxNode| {
1114 prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
1115 };
1116 let before_else_kw = |node: &SyntaxNode| {
1117 node.parent()
1118 .and_then(ast::ExprStmt::cast)
1119 .filter(|stmt| stmt.semicolon_token().is_none())
1120 .and_then(|stmt| non_trivia_sibling(stmt.syntax().clone().into(), Direction::Next))
1121 .and_then(NodeOrToken::into_node)
1122 .filter(|next| next.kind() == SyntaxKind::ERROR)
1123 .and_then(|next| next.first_token())
1124 .is_some_and(|token| token.kind() == SyntaxKind::ELSE_KW)
1125 };
1126
1127 let inbetween_body_and_decl_check = |node: SyntaxNode| {
1135 if let Some(NodeOrToken::Node(n)) =
1136 syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev)
1137 && let Some(item) = ast::Item::cast(n)
1138 {
1139 let is_inbetween = match &item {
1140 ast::Item::Const(it) => it.body().is_none() && it.semicolon_token().is_none(),
1141 ast::Item::Enum(it) => it.variant_list().is_none(),
1142 ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
1143 ast::Item::Fn(it) => it.body().is_none() && it.semicolon_token().is_none(),
1144 ast::Item::Impl(it) => it.assoc_item_list().is_none(),
1145 ast::Item::Module(it) => it.item_list().is_none() && it.semicolon_token().is_none(),
1146 ast::Item::Static(it) => it.body().is_none(),
1147 ast::Item::Struct(it) => {
1148 it.field_list().is_none() && it.semicolon_token().is_none()
1149 }
1150 ast::Item::Trait(it) => it.assoc_item_list().is_none(),
1151 ast::Item::TypeAlias(it) => it.ty().is_none() && it.semicolon_token().is_none(),
1152 ast::Item::Union(it) => it.record_field_list().is_none(),
1153 _ => false,
1154 };
1155 if is_inbetween {
1156 return Some(item);
1157 }
1158 }
1159 None
1160 };
1161
1162 let generic_arg_location = |arg: ast::GenericArg| {
1163 let mut override_location = None;
1164 let location = find_opt_node_in_file_compensated(
1165 sema,
1166 original_file,
1167 arg.syntax().parent().and_then(ast::GenericArgList::cast),
1168 )
1169 .map(|args| {
1170 let mut in_trait = None;
1171 let param = (|| {
1172 let parent = args.syntax().parent()?;
1173 let params = match_ast! {
1174 match parent {
1175 ast::PathSegment(segment) => {
1176 match sema.resolve_path(&segment.parent_path().top_path())? {
1177 hir::PathResolution::Def(def) => match def {
1178 hir::ModuleDef::Function(func) => {
1179 sema.source(func)?.value.generic_param_list()
1180 }
1181 hir::ModuleDef::Adt(adt) => {
1182 sema.source(adt)?.value.generic_param_list()
1183 }
1184 hir::ModuleDef::EnumVariant(variant) => {
1185 sema.source(variant.parent_enum(sema.db))?.value.generic_param_list()
1186 }
1187 hir::ModuleDef::Trait(trait_) => {
1188 if let ast::GenericArg::AssocTypeArg(arg) = &arg {
1189 let arg_name = arg.name_ref()?;
1190 let arg_name = arg_name.text();
1191 for item in trait_.items_with_supertraits(sema.db) {
1192 match item {
1193 hir::AssocItem::TypeAlias(assoc_ty)
1194 if assoc_ty.name(sema.db).as_str() == arg_name => {
1195 override_location = Some(TypeLocation::AssocTypeEq);
1196 return None;
1197 },
1198 hir::AssocItem::Const(const_)
1199 if const_.name(sema.db)?.as_str() == arg_name => {
1200 override_location = Some(TypeLocation::AssocConstEq);
1201 return None;
1202 },
1203 _ => (),
1204 }
1205 }
1206 return None;
1207 } else {
1208 in_trait = Some(trait_);
1209 sema.source(trait_)?.value.generic_param_list()
1210 }
1211 }
1212 hir::ModuleDef::TypeAlias(ty_) => {
1213 sema.source(ty_)?.value.generic_param_list()
1214 }
1215 _ => None,
1216 },
1217 _ => None,
1218 }
1219 },
1220 ast::MethodCallExpr(call) => {
1221 let func = sema.resolve_method_call(&call)?;
1222 sema.source(func)?.value.generic_param_list()
1223 },
1224 ast::AssocTypeArg(arg) => {
1225 let trait_ = ast::PathSegment::cast(arg.syntax().parent()?.parent()?)?;
1226 match sema.resolve_path(&trait_.parent_path().top_path())? {
1227 hir::PathResolution::Def(hir::ModuleDef::Trait(trait_)) => {
1228 let arg_name = arg.name_ref()?;
1229 let arg_name = arg_name.text();
1230 let trait_items = trait_.items_with_supertraits(sema.db);
1231 let assoc_ty = trait_items.iter().find_map(|item| match item {
1232 hir::AssocItem::TypeAlias(assoc_ty) => {
1233 (assoc_ty.name(sema.db).as_str() == arg_name)
1234 .then_some(assoc_ty)
1235 },
1236 _ => None,
1237 })?;
1238 sema.source(*assoc_ty)?.value.generic_param_list()
1239 }
1240 _ => None,
1241 }
1242 },
1243 _ => None,
1244 }
1245 }?;
1246 let mut explicit_lifetime_arg = false;
1255 let arg_idx = arg
1256 .syntax()
1257 .siblings(Direction::Prev)
1258 .skip(1)
1260 .map(|arg| if ast::LifetimeArg::can_cast(arg.kind()) { explicit_lifetime_arg = true })
1261 .count();
1262 let param_idx = if explicit_lifetime_arg {
1263 arg_idx
1264 } else {
1265 arg_idx + params.lifetime_params().count()
1268 };
1269 params.generic_params().nth(param_idx)
1270 })();
1271 (args, in_trait, param)
1272 });
1273 let (arg_list, of_trait, corresponding_param) = match location {
1274 Some((arg_list, of_trait, param)) => (Some(arg_list), of_trait, param),
1275 _ => (None, None, None),
1276 };
1277 override_location.unwrap_or(TypeLocation::GenericArg {
1278 args: arg_list,
1279 of_trait,
1280 corresponding_param,
1281 })
1282 };
1283
1284 let type_location = |node: &SyntaxNode| {
1285 let parent = node.parent()?;
1286 let res = match_ast! {
1287 match parent {
1288 ast::Const(it) => {
1289 let name = find_opt_node_in_file(original_file, it.name())?;
1290 let original = ast::Const::cast(name.syntax().parent()?)?;
1291 TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
1292 },
1293 ast::Static(it) => {
1294 let name = find_opt_node_in_file(original_file, it.name())?;
1295 let original = ast::Static::cast(name.syntax().parent()?)?;
1296 TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
1297 },
1298 ast::RetType(_) => {
1299 let parent = match ast::Fn::cast(parent.parent()?) {
1300 Some(it) => it.param_list(),
1301 None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
1302 };
1303
1304 let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
1305 let body = match_ast! {
1306 match parent {
1307 ast::ClosureExpr(it) => {
1308 it.body()
1309 },
1310 ast::Fn(it) => {
1311 it.body().map(ast::Expr::BlockExpr)
1312 },
1313 _ => return None,
1314 }
1315 };
1316 let item = ast::Fn::cast(parent);
1317 TypeLocation::TypeAscription(TypeAscriptionTarget::RetType { body, item })
1318 },
1319 ast::Param(it) => {
1320 it.colon_token()?;
1321 TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat())))
1322 },
1323 ast::LetStmt(it) => {
1324 it.colon_token()?;
1325 TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
1326 },
1327 ast::Impl(it) => {
1328 match it.trait_() {
1329 Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
1330 _ => match it.self_ty() {
1331 Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
1332 _ => return None,
1333 },
1334 }
1335 },
1336 ast::TypeBound(_) => TypeLocation::TypeBound,
1337 ast::TypeBoundList(_) => TypeLocation::TypeBound,
1339 ast::GenericArg(it) => generic_arg_location(it),
1340 ast::GenericArgList(it) => {
1342 let args = find_opt_node_in_file_compensated(sema, original_file, Some(it));
1343 TypeLocation::GenericArg { args, of_trait: None, corresponding_param: None }
1344 },
1345 ast::TupleField(_) => TypeLocation::TupleField,
1346 _ => return None,
1347 }
1348 };
1349 Some(res)
1350 };
1351
1352 let make_path_kind_expr = |expr: ast::Expr| {
1353 let it = expr.syntax();
1354 let prev_token = iter::successors(it.first_token(), |it| it.prev_token())
1355 .skip(1)
1356 .find(|it| !it.kind().is_trivia());
1357 let in_block_expr = is_in_block(it);
1358 let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip();
1359 let after_if_expr = is_after_if_expr(it.clone());
1360 let after_amp = prev_token.as_ref().is_some_and(|it| it.kind() == SyntaxKind::AMP);
1361 let ref_expr_parent = prev_token.and_then(|it| it.parent()).and_then(ast::RefExpr::cast);
1362 let (innermost_ret_ty, self_param) = {
1363 let find_ret_ty = |it: SyntaxNode| {
1364 if let Some(item) = ast::Item::cast(it.clone()) {
1365 match item {
1366 ast::Item::Fn(f) => Some(sema.to_def(&f).map(|it| it.ret_type(sema.db))),
1367 ast::Item::MacroCall(_) => None,
1368 _ => Some(None),
1369 }
1370 } else {
1371 let expr = ast::Expr::cast(it)?;
1372 let callable = match expr {
1373 ast::Expr::ClosureExpr(_) => sema.type_of_expr(&expr),
1376 _ => return None,
1377 };
1378 Some(
1379 callable
1380 .and_then(|c| c.adjusted().as_callable(sema.db))
1381 .map(|it| it.return_type()),
1382 )
1383 }
1384 };
1385 let fn_self_param =
1386 |fn_: ast::Fn| sema.to_def(&fn_).and_then(|it| it.self_param(sema.db));
1387 let closure_this_param = |closure: ast::ClosureExpr| {
1388 if closure.param_list()?.params().next()?.pat()?.syntax().text() != "this" {
1389 return None;
1390 }
1391 sema.type_of_expr(&closure.into())
1392 .and_then(|it| it.original.as_callable(sema.db))
1393 .and_then(|it| it.params().into_iter().next())
1394 };
1395 let find_fn_self_param = |it: SyntaxNode| {
1396 match_ast! {
1397 match it {
1398 ast::Fn(fn_) => Some(fn_self_param(fn_).map(Either::Left)),
1399 ast::ClosureExpr(f) => closure_this_param(f).map(Either::Right).map(Some),
1400 ast::MacroCall(_) => None,
1401 ast::Item(_) => Some(None),
1402 _ => None,
1403 }
1404 }
1405 };
1406
1407 match find_node_in_file_compensated(sema, original_file, &expr) {
1408 Some(it) => {
1409 let innermost_ret_ty = sema
1411 .ancestors_with_macros(it.syntax().clone())
1412 .find_map(find_ret_ty)
1413 .flatten();
1414
1415 let self_param = sema
1416 .ancestors_with_macros(it.syntax().clone())
1417 .find_map(find_fn_self_param)
1418 .flatten();
1419 (innermost_ret_ty, self_param)
1420 }
1421 None => (None, None),
1422 }
1423 };
1424 let innermost_breakable_ty = innermost_breakable
1425 .and_then(ast::Expr::cast)
1426 .and_then(|expr| find_node_in_file_compensated(sema, original_file, &expr))
1427 .and_then(|expr| sema.type_of_expr(&expr))
1428 .map(|ty| if ty.original.is_never() { ty.adjusted() } else { ty.original() });
1429 let is_func_update = func_update_record(it);
1430 let in_condition = is_in_condition(&expr);
1431 let after_incomplete_let = after_incomplete_let(it.clone()).is_some();
1432 let incomplete_expr_stmt =
1433 it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none());
1434 let before_else_kw = before_else_kw(it);
1435 let incomplete_let = left_ancestors(it.parent())
1436 .find_map(ast::LetStmt::cast)
1437 .is_some_and(|it| it.semicolon_token().is_none())
1438 || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
1439 let in_value = is_in_value(&expr);
1440 let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax())
1441 .and_then(Either::left);
1442
1443 let before_match_arrow = it.parent().and_then(ast::MatchArm::cast).map(|arm| {
1444 arm.fat_arrow_token()
1445 .is_none_or(|arrow| it.text_range().start() < arrow.text_range().start())
1446 });
1447 let in_match_guard = before_match_arrow == Some(true);
1448 let at_optional_block = before_match_arrow == Some(false)
1449 || it.parent().and_then(ast::ClosureExpr::cast).is_some();
1450
1451 PathKind::Expr {
1452 expr_ctx: PathExprCtx {
1453 in_block_expr,
1454 in_breakable: in_loop_body,
1455 after_if_expr,
1456 before_else_kw,
1457 in_condition,
1458 ref_expr_parent,
1459 after_amp,
1460 is_func_update,
1461 innermost_ret_ty,
1462 innermost_breakable_ty,
1463 self_param,
1464 in_value,
1465 incomplete_let,
1466 after_incomplete_let,
1467 impl_,
1468 in_match_guard,
1469 at_optional_block,
1470 },
1471 }
1472 };
1473 let make_path_kind_type = |ty: ast::Type| {
1474 let location = type_location(ty.syntax());
1475 PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
1476 };
1477
1478 let kind_item = |it: &SyntaxNode| {
1479 let parent = it.parent()?;
1480 let kind = match_ast! {
1481 match parent {
1482 ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
1483 ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
1484 Some(it) => match_ast! {
1485 match it {
1486 ast::Trait(_) => ItemListKind::Trait,
1487 ast::Impl(it) => if it.trait_().is_some() {
1488 ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
1489 } else {
1490 ItemListKind::Impl
1491 },
1492 _ => return None
1493 }
1494 },
1495 None => return None,
1496 } },
1497 ast::ExternItemList(it) => {
1498 let exn_blk = it.syntax().parent().and_then(ast::ExternBlock::cast);
1499 PathKind::Item {
1500 kind: ItemListKind::ExternBlock {
1501 is_unsafe: exn_blk.and_then(|it| it.unsafe_token()).is_some(),
1502 }
1503 }
1504 },
1505 ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
1506 _ => return None,
1507 }
1508 };
1509 Some(kind)
1510 };
1511
1512 let mut kind_macro_call = |it: ast::MacroCall| {
1513 path_ctx.has_macro_bang = it.excl_token().is_some();
1514 let parent = it.syntax().parent()?;
1515 if let Some(kind) = kind_item(it.syntax()) {
1516 return Some(kind);
1517 }
1518 let kind = match_ast! {
1519 match parent {
1520 ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
1521 ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
1522 ast::MacroType(ty) => make_path_kind_type(ty.into()),
1523 _ => return None,
1524 }
1525 };
1526 Some(kind)
1527 };
1528 let make_path_kind_attr = |meta: ast::Meta| {
1529 let attr = meta.parent_attr()?;
1530 let kind = attr.kind();
1531 let attached = attr.syntax().parent()?;
1532 let is_trailing_outer_attr = kind != AttrKind::Inner
1533 && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
1534 let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) };
1535 let derive_helpers = annotated_item_kind
1536 .filter(|kind| {
1537 matches!(
1538 kind,
1539 SyntaxKind::STRUCT
1540 | SyntaxKind::ENUM
1541 | SyntaxKind::UNION
1542 | SyntaxKind::VARIANT
1543 | SyntaxKind::TUPLE_FIELD
1544 | SyntaxKind::RECORD_FIELD
1545 )
1546 })
1547 .and_then(|_| find_node_at_offset::<ast::Adt>(original_file, original_offset))
1548 .and_then(|adt| sema.derive_helpers_in_scope(&adt))
1549 .unwrap_or_default();
1550 Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } })
1551 };
1552
1553 let parent = path.syntax().parent()?;
1555 let kind = 'find_kind: {
1556 if parent.kind() == SyntaxKind::ERROR {
1557 if let Some(kind) = inbetween_body_and_decl_check(parent.clone()) {
1558 return Some(make_res(NameRefKind::Keyword(kind)));
1559 }
1560
1561 break 'find_kind kind_item(&parent)?;
1562 }
1563 match_ast! {
1564 match parent {
1565 ast::PathType(it) => make_path_kind_type(it.into()),
1566 ast::PathExpr(it) => {
1567 if let Some(p) = it.syntax().parent() {
1568 let p_kind = p.kind();
1569 let probe = if ast::ExprStmt::can_cast(p_kind) {
1572 Some(p)
1573 } else if ast::StmtList::can_cast(p_kind) {
1574 Some(it.syntax().clone())
1575 } else {
1576 None
1577 };
1578 if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) {
1579 return Some(make_res(NameRefKind::Keyword(kind)));
1580 }
1581 }
1582
1583 path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
1584
1585 make_path_kind_expr(it.into())
1586 },
1587 ast::TupleStructPat(it) => {
1588 path_ctx.has_call_parens = true;
1589 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
1590 },
1591 ast::RecordPat(it) => {
1592 path_ctx.has_call_parens = true;
1593 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
1594 },
1595 ast::PathPat(it) => {
1596 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
1597 },
1598 ast::MacroCall(it) => {
1599 kind_macro_call(it)?
1600 },
1601 ast::Meta(meta) => make_path_kind_attr(meta)?,
1602 ast::VisibilityInner(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
1603 ast::UseTree(_) => PathKind::Use,
1604 ast::Path(parent) => {
1606 path_ctx.parent = Some(parent.clone());
1607 let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
1608 match_ast! {
1609 match parent {
1610 ast::PathType(it) => make_path_kind_type(it.into()),
1611 ast::PathExpr(it) => {
1612 path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
1613
1614 make_path_kind_expr(it.into())
1615 },
1616 ast::TupleStructPat(it) => {
1617 path_ctx.has_call_parens = true;
1618 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
1619 },
1620 ast::RecordPat(it) => {
1621 path_ctx.has_call_parens = true;
1622 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
1623 },
1624 ast::PathPat(it) => {
1625 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
1626 },
1627 ast::MacroCall(it) => {
1628 kind_macro_call(it)?
1629 },
1630 ast::Meta(meta) => make_path_kind_attr(meta)?,
1631 ast::VisibilityInner(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
1632 ast::UseTree(_) => PathKind::Use,
1633 ast::RecordExpr(it) => make_path_kind_expr(it.into()),
1634 _ => return None,
1635 }
1636 }
1637 },
1638 ast::RecordExpr(it) => {
1639 if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
1641 return Some(make_res(NameRefKind::Keyword(kind)));
1642 }
1643 make_path_kind_expr(it.into())
1644 },
1645 _ => return None,
1646 }
1647 }
1648 };
1649
1650 path_ctx.kind = kind;
1651 path_ctx.has_type_args = segment.generic_arg_list().is_some();
1652
1653 if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
1655 path_ctx.use_tree_parent = use_tree_parent;
1656 if !use_tree_parent && segment.coloncolon_token().is_some() {
1657 path_ctx.qualified = Qualified::Absolute;
1658 } else {
1659 let qualifier = qualifier
1660 .segment()
1661 .and_then(|it| find_node_in_file(original_file, &it))
1662 .map(|it| it.parent_path());
1663 if let Some(qualifier) = qualifier {
1664 let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
1665 Some(ast::PathSegmentKind::Type { type_ref: Some(type_ref), trait_ref })
1666 if qualifier.qualifier().is_none() =>
1667 {
1668 Some((type_ref, trait_ref))
1669 }
1670 _ => None,
1671 };
1672
1673 path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
1674 let ty = match ty {
1675 ast::Type::InferType(_) => None,
1676 ty => sema.resolve_type(&ty),
1677 };
1678 let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
1679 Qualified::TypeAnchor { ty, trait_ }
1680 } else {
1681 let res = sema.resolve_path(&qualifier);
1682
1683 let mut segment_count = 0;
1686 let super_count = iter::successors(Some(qualifier.clone()), |p| p.qualifier())
1687 .take_while(|p| {
1688 p.segment()
1689 .and_then(|s| {
1690 segment_count += 1;
1691 s.super_token()
1692 })
1693 .is_some()
1694 })
1695 .count();
1696
1697 let super_chain_len =
1698 if segment_count > super_count { None } else { Some(super_count) };
1699
1700 Qualified::With { path: qualifier, resolution: res, super_chain_len }
1701 }
1702 };
1703 }
1704 } else if let Some(segment) = path.segment()
1705 && segment.coloncolon_token().is_some()
1706 {
1707 path_ctx.qualified = Qualified::Absolute;
1708 }
1709
1710 let mut qualifier_ctx = QualifierCtx::default();
1711 if path_ctx.is_trivial_path() {
1712 let top_node = match path_ctx.kind {
1714 PathKind::Expr { expr_ctx: PathExprCtx { in_block_expr: true, .. } } => {
1715 parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
1716 let parent = p.parent()?;
1717 if ast::StmtList::can_cast(parent.kind()) {
1718 Some(p)
1719 } else if ast::ExprStmt::can_cast(parent.kind()) {
1720 Some(parent)
1721 } else {
1722 None
1723 }
1724 })
1725 }
1726 PathKind::Item { .. } => parent.ancestors().find(|it| it.kind() == SyntaxKind::ERROR),
1727 _ => None,
1728 };
1729 if let Some(top) = top_node {
1730 if let Some(NodeOrToken::Node(error_node)) =
1731 syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev)
1732 && error_node.kind() == SyntaxKind::ERROR
1733 {
1734 for token in error_node.children_with_tokens().filter_map(NodeOrToken::into_token) {
1735 match token.kind() {
1736 SyntaxKind::UNSAFE_KW => qualifier_ctx.unsafe_tok = Some(token),
1737 SyntaxKind::ASYNC_KW => qualifier_ctx.async_tok = Some(token),
1738 SyntaxKind::SAFE_KW => qualifier_ctx.safe_tok = Some(token),
1739 _ => {}
1740 }
1741 }
1742 qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast);
1743 qualifier_ctx.abi_node = error_node.children().find_map(ast::Abi::cast);
1744 }
1745
1746 let allowed_prev_kinds =
1747 [T![;], T!['}'], T!['{'], T![']'], SyntaxKind::INNER_DOC_COMMENT];
1748 if let PathKind::Item { .. } = path_ctx.kind
1749 && qualifier_ctx.none()
1750 && let Some(t) = top.first_token()
1751 && let Some(prev) =
1752 t.prev_token().and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev))
1753 && !allowed_prev_kinds.contains(&prev.kind())
1754 {
1755 return None;
1759 }
1760 }
1761 }
1762 Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
1763}
1764
1765fn has_parens(node: &dyn HasArgList) -> bool {
1774 let Some(arg_list) = node.arg_list() else { return false };
1775 if arg_list.l_paren_token().is_none() {
1776 return false;
1777 }
1778 let prev_siblings = iter::successors(arg_list.syntax().prev_sibling_or_token(), |it| {
1779 it.prev_sibling_or_token()
1780 });
1781 prev_siblings
1782 .take_while(|syntax| syntax.kind().is_trivia())
1783 .filter_map(|syntax| {
1784 syntax.into_token().filter(|token| token.kind() == SyntaxKind::WHITESPACE)
1785 })
1786 .all(|whitespace| !whitespace.text().contains('\n'))
1787}
1788
1789fn pattern_context_for(
1790 sema: &Semantics<'_, RootDatabase>,
1791 original_file: &SyntaxNode,
1792 pat: ast::Pat,
1793) -> PatternContext {
1794 let mut param_ctx = None;
1795
1796 let mut missing_variants = vec![];
1797 let is_pat_like = |kind| {
1798 ast::Pat::can_cast(kind)
1799 || ast::RecordPatField::can_cast(kind)
1800 || ast::RecordPatFieldList::can_cast(kind)
1801 };
1802
1803 let (refutability, has_type_ascription) = pat
1804 .syntax()
1805 .ancestors()
1806 .find(|it| !is_pat_like(it.kind()))
1807 .map_or((PatternRefutability::Irrefutable, false), |node| {
1808 let refutability = match_ast! {
1809 match node {
1810 ast::LetStmt(let_) => return (PatternRefutability::Refutable, let_.ty().is_some()),
1811 ast::Param(param) => {
1812 let has_type_ascription = param.ty().is_some();
1813 param_ctx = (|| {
1814 let fake_param_list = param.syntax().parent().and_then(ast::ParamList::cast)?;
1815 let param_list = find_node_in_file_compensated(sema, original_file, &fake_param_list)?;
1816 let param_list_owner = param_list.syntax().parent()?;
1817 let kind = match_ast! {
1818 match param_list_owner {
1819 ast::ClosureExpr(closure) => ParamKind::Closure(closure),
1820 ast::Fn(fn_) => ParamKind::Function(fn_),
1821 _ => return None,
1822 }
1823 };
1824 Some(ParamContext {
1825 param_list, param, kind
1826 })
1827 })();
1828 return (PatternRefutability::Irrefutable, has_type_ascription)
1829 },
1830 ast::MatchArm(match_arm) => {
1831 let missing_variants_opt = match_arm
1832 .syntax()
1833 .parent()
1834 .and_then(ast::MatchArmList::cast)
1835 .and_then(|match_arm_list| {
1836 match_arm_list
1837 .syntax()
1838 .parent()
1839 .and_then(ast::MatchExpr::cast)
1840 .and_then(|match_expr| {
1841 let expr_opt = find_opt_node_in_file(original_file, match_expr.expr());
1842
1843 expr_opt.and_then(|expr| {
1844 sema.type_of_expr(&expr)?
1845 .adjusted()
1846 .autoderef(sema.db)
1847 .find_map(|ty| match ty.as_adt() {
1848 Some(hir::Adt::Enum(e)) => Some(e),
1849 _ => None,
1850 }).map(|enum_| enum_.variants(sema.db))
1851 })
1852 }).map(|variants| variants.iter().filter_map(|variant| {
1853 let variant_name = variant.name(sema.db);
1854
1855 let variant_already_present = match_arm_list.arms().any(|arm| {
1856 arm.pat().and_then(|pat| {
1857 let pat_already_present = pat.syntax().to_string().contains(variant_name.as_str());
1858 pat_already_present.then_some(pat_already_present)
1859 }).is_some()
1860 });
1861
1862 (!variant_already_present).then_some(*variant)
1863 }).collect::<Vec<EnumVariant>>())
1864 });
1865
1866 if let Some(missing_variants_) = missing_variants_opt {
1867 missing_variants = missing_variants_;
1868 };
1869
1870 PatternRefutability::Refutable
1871 },
1872 ast::LetExpr(_) => PatternRefutability::Refutable,
1873 ast::ForExpr(_) => PatternRefutability::Irrefutable,
1874 _ => PatternRefutability::Irrefutable,
1875 }
1876 };
1877 (refutability, false)
1878 });
1879 let (ref_token, mut_token) = match &pat {
1880 ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()),
1881 _ => (None, None),
1882 };
1883
1884 let should_suggest_name = matches!(
1886 &pat,
1887 ast::Pat::IdentPat(it)
1888 if it.syntax()
1889 .parent().is_some_and(|node| {
1890 let kind = node.kind();
1891 ast::LetStmt::can_cast(kind) || ast::Param::can_cast(kind)
1892 })
1893 );
1894
1895 PatternContext {
1896 refutability,
1897 param_ctx,
1898 has_type_ascription,
1899 should_suggest_name,
1900 after_if_expr: is_after_if_expr(pat.syntax().clone()),
1901 parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
1902 mut_token,
1903 ref_token,
1904 record_pat: None,
1905 impl_or_trait: fetch_immediate_impl_or_trait(sema, original_file, pat.syntax()),
1906 missing_variants,
1907 }
1908}
1909
1910fn fetch_immediate_impl_or_trait(
1911 sema: &Semantics<'_, RootDatabase>,
1912 original_file: &SyntaxNode,
1913 node: &SyntaxNode,
1914) -> Option<Either<ast::Impl, ast::Trait>> {
1915 let mut ancestors = ancestors_in_file_compensated(sema, original_file, node)?
1916 .filter_map(ast::Item::cast)
1917 .filter(|it| !matches!(it, ast::Item::MacroCall(_)));
1918
1919 match ancestors.next()? {
1920 ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (),
1921 ast::Item::Impl(it) => return Some(Either::Left(it)),
1922 ast::Item::Trait(it) => return Some(Either::Right(it)),
1923 _ => return None,
1924 }
1925 match ancestors.next()? {
1926 ast::Item::Impl(it) => Some(Either::Left(it)),
1927 ast::Item::Trait(it) => Some(Either::Right(it)),
1928 _ => None,
1929 }
1930}
1931
1932fn find_opt_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: Option<N>) -> Option<N> {
1935 find_node_in_file(syntax, &node?)
1936}
1937
1938fn find_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: &N) -> Option<N> {
1941 let syntax_range = syntax.text_range();
1942 let range = node.syntax().text_range();
1943 let intersection = range.intersect(syntax_range)?;
1944 syntax.covering_element(intersection).ancestors().find_map(N::cast)
1945}
1946
1947fn find_node_in_file_compensated<N: AstNode>(
1951 sema: &Semantics<'_, RootDatabase>,
1952 in_file: &SyntaxNode,
1953 node: &N,
1954) -> Option<N> {
1955 ancestors_in_file_compensated(sema, in_file, node.syntax())?.find_map(N::cast)
1956}
1957
1958fn ancestors_in_file_compensated<'sema>(
1959 sema: &'sema Semantics<'_, RootDatabase>,
1960 in_file: &SyntaxNode,
1961 node: &SyntaxNode,
1962) -> Option<impl Iterator<Item = SyntaxNode> + 'sema> {
1963 let syntax_range = in_file.text_range();
1964 let range = node.text_range();
1965 let end = range.end().checked_sub(TextSize::try_from(COMPLETION_MARKER.len()).ok()?)?;
1966 if end < range.start() {
1967 return None;
1968 }
1969 let range = TextRange::new(range.start(), end);
1970 let intersection = range.intersect(syntax_range)?;
1972 let node = match in_file.covering_element(intersection) {
1973 NodeOrToken::Node(node) => node,
1974 NodeOrToken::Token(tok) => tok.parent()?,
1975 };
1976 Some(sema.ancestors_with_macros(node))
1977}
1978
1979fn find_opt_node_in_file_compensated<N: AstNode>(
1983 sema: &Semantics<'_, RootDatabase>,
1984 syntax: &SyntaxNode,
1985 node: Option<N>,
1986) -> Option<N> {
1987 find_node_in_file_compensated(sema, syntax, &node?)
1988}
1989
1990fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
1991 if let Some(qual) = path.qualifier() {
1992 return Some((qual, false));
1993 }
1994 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
1995 let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
1996 Some((use_tree.path()?, true))
1997}
1998
1999fn left_ancestors(node: Option<SyntaxNode>) -> impl Iterator<Item = SyntaxNode> {
2000 node.into_iter().flat_map(|node| {
2001 let end = node.text_range().end();
2002 node.ancestors().take_while(move |it| it.text_range().end() == end)
2003 })
2004}
2005
2006fn is_in_token_of_for_loop(path: &ast::Path) -> bool {
2007 (|| {
2009 let expr = path.syntax().parent().and_then(ast::PathExpr::cast)?;
2010 let for_expr = expr.syntax().parent().and_then(ast::ForExpr::cast)?;
2011 if for_expr.in_token().is_some() {
2012 return Some(false);
2013 }
2014 let pat = for_expr.pat()?;
2015 let next_sibl = next_non_trivia_sibling(pat.syntax().clone().into())?;
2016 Some(match next_sibl {
2017 syntax::NodeOrToken::Node(n) => {
2018 n.text_range().start() == path.syntax().text_range().start()
2019 }
2020 syntax::NodeOrToken::Token(t) => {
2021 t.text_range().start() == path.syntax().text_range().start()
2022 }
2023 })
2024 })()
2025 .unwrap_or(false)
2026}
2027
2028fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> {
2029 node.ancestors()
2030 .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR)
2031 .find_map(|it| {
2032 let (breakable, loop_body) = match_ast! {
2033 match it {
2034 ast::ForExpr(it) => (BreakableKind::For, it.loop_body()?),
2035 ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()?),
2036 ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()?),
2037 ast::BlockExpr(it) => return it.label().map(|_| (BreakableKind::Block, it.syntax().clone())),
2038 _ => return None,
2039 }
2040 };
2041 loop_body.syntax().text_range().contains_range(node.text_range())
2042 .then_some((breakable, it))
2043 })
2044}
2045
2046fn is_in_block(node: &SyntaxNode) -> bool {
2047 let in_rightside = ast::NameRef::can_cast(node.kind());
2048 let sense_node = node.ancestors().nth(in_rightside.into()).unwrap_or_else(|| node.clone());
2049 if has_in_newline_expr_first(node, &sense_node) {
2050 return true;
2051 };
2052 sense_node
2053 .parent()
2054 .map(|node| {
2055 ast::ExprStmt::can_cast(node.kind())
2056 || ast::StmtList::can_cast(node.kind())
2057 || ast::MacroStmts::can_cast(node.kind())
2060 })
2061 .unwrap_or(false)
2062}
2063
2064fn has_in_newline_expr_first(node: &SyntaxNode, sense_node: &SyntaxNode) -> bool {
2070 let sense_mode = sense_node != node;
2071 let is_splitable = |node: &SyntaxNode| {
2072 let range = node.text_range();
2073 let sense = sense_node.text_range();
2074 range.start() == sense.start() || sense_mode && range.end() == sense.end()
2075 };
2076 if (ast::PathExpr::can_cast(node.kind()) || sense_mode)
2077 && let Some(next) = node.last_token().and_then(|it| it.next_token())
2078 && next.kind() == SyntaxKind::WHITESPACE
2079 && next.text().contains('\n')
2080 && let Some(stmt_like) = sense_node
2081 .ancestors()
2082 .take_while(is_splitable)
2083 .filter_map(Either::<ast::ExprStmt, ast::Expr>::cast)
2084 .last()
2085 {
2086 stmt_like.syntax().parent().and_then(ast::StmtList::cast).is_some()
2087 } else {
2088 false
2089 }
2090}
2091
2092fn is_after_if_expr(node: SyntaxNode) -> bool {
2093 let node = match node.parent().and_then(Either::<ast::ExprStmt, ast::MatchArm>::cast) {
2094 Some(stmt) => stmt.syntax().clone(),
2095 None => node,
2096 };
2097 let Some(prev_token) = previous_non_trivia_token(node) else { return false };
2098 prev_token
2099 .parent_ancestors()
2100 .take_while(|it| it.text_range().end() == prev_token.text_range().end())
2101 .find_map(ast::IfExpr::cast)
2102 .is_some()
2103}
2104
2105fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
2106 let mut token = match e.into() {
2107 SyntaxElement::Node(n) => n.last_token()?,
2108 SyntaxElement::Token(t) => t,
2109 }
2110 .next_token();
2111 while let Some(inner) = token {
2112 if !inner.kind().is_trivia() {
2113 return Some(inner);
2114 } else {
2115 token = inner.next_token();
2116 }
2117 }
2118 None
2119}
2120
2121fn next_non_trivia_sibling(ele: SyntaxElement) -> Option<SyntaxElement> {
2122 let mut e = ele;
2123 while let Some(next) = e.next_sibling_or_token() {
2124 if !next.kind().is_trivia() {
2125 return Some(next);
2126 } else {
2127 e = next;
2128 }
2129 }
2130 None
2131}
2132
2133fn prev_special_biased_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken {
2134 while token.kind().is_trivia()
2135 && let Some(prev) = token.prev_token()
2136 && let T![=]
2137 | T![+=]
2138 | T![/=]
2139 | T![*=]
2140 | T![%=]
2141 | T![>>=]
2142 | T![<<=]
2143 | T![-=]
2144 | T![|=]
2145 | T![&=]
2146 | T![^=]
2147 | T![|]
2148 | T![return]
2149 | T![break]
2150 | T![continue]
2151 | T![lifetime_ident] = prev.kind()
2152 {
2153 token = prev
2154 }
2155 token
2156}