Skip to main content

ide_completion/context/
analysis.rs

1//! Module responsible for analyzing the code surrounding the cursor for completion.
2use 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    /// The offset in the original file.
40    original_offset: TextSize,
41    /// The offset in the speculatively expanded file.
42    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    /// the original token of the expanded file
52    pub(super) token: SyntaxToken,
53    /// The offset in the original file.
54    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    // as we insert after the offset, right biased will *always* pick the identifier no matter
65    // if there is an ident already typed or not
66    let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?;
67    // the relative offset between the cursor and the *identifier* token we are completing on
68    let relative_offset = offset - fake_ident_token.text_range().start();
69    // make the offset point to the start of the original token, as that is what the
70    // intermediate offsets calculated in expansion always points to
71    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    // add the relative offset back, so that left_biased finds the proper token
90    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
103/// Expand attributes and macro calls at the current cursor position for both the original file
104/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
105/// and speculative states stay in sync.
106///
107/// We do this by recursively expanding all macros and picking the best possible match. We cannot just
108/// choose the first expansion each time because macros can expand to something that does not include
109/// our completion marker, e.g.:
110///
111/// ```ignore
112/// macro_rules! helper { ($v:ident) => {} }
113/// macro_rules! my_macro {
114///     ($v:ident) => {
115///         helper!($v);
116///         $v
117///     };
118/// }
119///
120/// my_macro!(complete_me_here);
121/// ```
122/// If we would expand the first thing we encounter only (which in fact this method used to do), we would
123/// be unable to complete here, because we would be walking directly into the void. So we instead try
124/// *every* possible path.
125///
126/// This can also creates discrepancies between the speculative and real expansions: because we insert
127/// tokens, we insert characters, which means if we try the second occurrence it may not be at the same
128/// position in the original and speculative file. We take an educated guess here, and for each token
129/// that we check, we subtract `COMPLETION_MARKER.len()`. This may not be accurate because proc macros
130/// can insert the text of the completion marker in other places while removing the span, but this is
131/// the best we can do.
132fn 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    // We can't check whether the fake expansion is inside macro call, because that requires semantic info.
152    // But hopefully checking just the real one should be enough.
153    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        // Recursion base case.
159        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    // first try to expand attributes as these are always the outermost macro calls
198    '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            // maybe parent items have attributes, so continue walking the ancestors
208            (None, None) => continue 'ancestors,
209            // successful expansions
210            (
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                            // Proc macros can make the same span with different text, we don't
222                            // want them to participate in completion because the macro author probably
223                            // didn't intend them to.
224                            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                            // offset outside of bounds from the original expansion,
232                            // stop here to prevent problems from happening
233                            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            // exactly one expansion failed, inconsistent state so stop expanding completely
252            _ => break 'ancestors,
253        }
254    }
255
256    // No attributes have been expanded, so look for macro_call! token trees or derive token trees
257    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    // Expand pseudo-derive expansion aka `derive(Debug$0)`
287    if let Some((orig_attr, spec_attr)) = attrs
288        && let Some(orig_meta) = orig_attr.meta()
289    {
290        // FIXME: Support speculative expansion with `cfg_attr`.
291        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            // might be the path of derive helper or a token tree inside of one
325            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                        // we are inside a derive helper token tree, treat this as being inside
333                        // the derive expansion
334                        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                                    // Proc macros can make the same span with different text, we don't
343                                    // want them to participate in completion because the macro author probably
344                                    // didn't intend them to.
345                                    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                                    // offset outside of bounds from the original expansion,
353                                    // stop here to prevent problems from happening
354                                    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        // at this point we won't have any more successful expansions, so stop
376        return None;
377    }
378
379    // Expand fn-like macro calls
380    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    // inconsistent state, stop expanding
389    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        // successful expansions
399        (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                        // Proc macros can make the same span with different text, we don't
408                        // want them to participate in completion because the macro author probably
409                        // didn't intend them to.
410                        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                        // offset outside of bounds from the original expansion,
418                        // stop here to prevent problems from happening
419                        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        // at least one expansion failed, we won't have anything to expand from this point
435        // onwards so break out
436        _ => None,
437    }
438}
439
440/// Fill the completion context, this is what does semantic reasoning about the surrounding context
441/// of the completion location.
442fn 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        // FIXME: This check can be removed once we use speculative database forking for completions
460        && !(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    // Overwrite the path kind for derives
468    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            // Fix up trailing whitespace problem
503            // #[attr(foo = $0
504            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                // for pat $0
572                // there is nothing to complete here except `in` keyword
573                // don't bother populating the context
574                // Ideally this special casing wouldn't be needed, but the parser recovers
575                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
589/// Calculate the expected type and name of the cursor position.
590fn 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                            // don't infer the let type if the expr is a function,
675                            // preventing parenthesis from vanishing
676                            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                    // wouldn't try {} be nice...
721                    (|| {
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                // match foo { $0 }
757                // match foo { ..., pat => $0 }
758                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                        // match foo { ..., pat => $0 }
763                        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                        // match foo { $0 }
768                        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                        // match foo { ..., pat => $0 }
780                        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                        // match foo { $0 }
785                        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    // FIXME: Heuristic hack for PathExpr in ArgList
883    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            // `123.|` is parsed as a float but should actually be an integer.
1030            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    // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
1128    // ex. trait Foo $0 {}
1129    // in these cases parser recovery usually kicks in for our inserted identifier, causing it
1130    // to either be parsed as an ExprStmt or a ItemRecovery, depending on whether it is in a block
1131    // expression or an item list.
1132    // The following code checks if the body is missing, if it is we either cut off the body
1133    // from the item or it was missing in the first place
1134    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                // Determine the index of the argument in the `GenericArgList` and match it with
1247                // the corresponding parameter in the `GenericParamList`. Since lifetime parameters
1248                // are often omitted, ignore them for the purposes of matching the argument with
1249                // its parameter unless a lifetime argument is provided explicitly. That is, for
1250                // `struct S<'a, 'b, T>`, match `S::<$0>` to `T` and `S::<'a, $0, _>` to `'b`.
1251                // FIXME: This operates on the syntax tree and will produce incorrect results when
1252                // generic parameters are disabled by `#[cfg]` directives. It should operate on the
1253                // HIR, but the functionality necessary to do so is not exposed at the moment.
1254                let mut explicit_lifetime_arg = false;
1255                let arg_idx = arg
1256                    .syntax()
1257                    .siblings(Direction::Prev)
1258                    // Skip the node itself
1259                    .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                    // Lifetimes parameters always precede type and generic parameters,
1266                    // so offset the argument index by the total number of lifetime params
1267                    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                // is this case needed?
1338                ast::TypeBoundList(_) => TypeLocation::TypeBound,
1339                ast::GenericArg(it) => generic_arg_location(it),
1340                // is this case needed?
1341                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                        // FIXME
1374                        // ast::Expr::BlockExpr(b) if b.async_token().is_some() || b.try_token().is_some() => sema.type_of_expr(b),
1375                        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                    // buggy
1410                    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    // Infer the path kind
1554    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                        // The syntax node of interest, for which we want to check whether
1570                        // it is sandwiched between an item decl signature and its body.
1571                        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                // completing inside a qualifier
1605                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                    // A record expression in this position is usually a result of parsing recovery, so check that
1640                    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    // calculate the qualifier context
1654    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                    // For understanding how and why super_chain_len is calculated the way it
1684                    // is check the documentation at its definition
1685                    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        // fetch the full expression that may have qualifiers attached to it
1713        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                // This was inferred to be an item position path, but it seems
1756                // to be part of some other broken node which leaked into an item
1757                // list
1758                return None;
1759            }
1760        }
1761    }
1762    Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
1763}
1764
1765/// When writing in the middle of some code the following situation commonly occurs (`|` denotes the cursor):
1766/// ```ignore
1767/// value.method|
1768/// (1, 2, 3)
1769/// ```
1770/// Here, we want to complete the method parentheses & arguments (if the corresponding settings are on),
1771/// but the thing is parsed as a method call with parentheses. Therefore we use heuristics: if the parentheses
1772/// are on the next line, consider them non-existent.
1773fn 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    // Only suggest name in let-stmt or fn param
1885    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
1932/// Attempts to find `node` inside `syntax` via `node`'s text range.
1933/// If the fake identifier has been inserted after this node or inside of this node use the `_compensated` version instead.
1934fn find_opt_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: Option<N>) -> Option<N> {
1935    find_node_in_file(syntax, &node?)
1936}
1937
1938/// Attempts to find `node` inside `syntax` via `node`'s text range.
1939/// If the fake identifier has been inserted after this node or inside of this node use the `_compensated` version instead.
1940fn 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
1947/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
1948/// for the offset introduced by the fake ident.
1949/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
1950fn 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    // our inserted ident could cause `range` to go outside of the original syntax, so cap it
1971    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
1979/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
1980/// for the offset introduced by the fake ident..
1981/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
1982fn 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    // oh my ...
2008    (|| {
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                // Because `is_in_block` is only called in the context of an expression,
2058                // there is no need to consider expanding it into a type or pattern
2059                || ast::MacroStmts::can_cast(node.kind())
2060        })
2061        .unwrap_or(false)
2062}
2063
2064/// Similar to `has_parens`, heuristic sensing incomplete statement before ambiguous `Expr`
2065///
2066/// Heuristic:
2067///
2068/// Check if `node` follows a newline and if the ancestors of `sense_node` can be split all the way to `StmtList`
2069fn 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}