]> git.lizzy.rs Git - rust.git/blob - crates/ide-completion/src/context.rs
Auto merge of #12159 - Veykril:completions-rev, r=Veykril
[rust.git] / crates / ide-completion / src / context.rs
1 //! See `CompletionContext` structure.
2
3 use std::iter;
4
5 use base_db::SourceDatabaseExt;
6 use hir::{
7     HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo,
8 };
9 use ide_db::{
10     active_parameter::ActiveParameter,
11     base_db::{FilePosition, SourceDatabase},
12     famous_defs::FamousDefs,
13     FxHashMap, FxHashSet, RootDatabase,
14 };
15 use syntax::{
16     algo::{find_node_at_offset, non_trivia_sibling},
17     ast::{self, AttrKind, HasName, NameOrNameRef},
18     match_ast, AstNode, NodeOrToken,
19     SyntaxKind::{self, *},
20     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
21 };
22 use text_edit::Indel;
23
24 use crate::{
25     patterns::{
26         determine_location, determine_prev_sibling, is_in_loop_body, is_in_token_of_for_loop,
27         previous_token, ImmediateLocation, ImmediatePrevSibling,
28     },
29     CompletionConfig,
30 };
31
32 const COMPLETION_MARKER: &str = "intellijRulezz";
33
34 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
35 pub(crate) enum PatternRefutability {
36     Refutable,
37     Irrefutable,
38 }
39
40 pub(crate) enum Visible {
41     Yes,
42     Editable,
43     No,
44 }
45
46 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
47 pub(super) enum PathKind {
48     Expr,
49     Type,
50     Attr {
51         kind: AttrKind,
52         annotated_item_kind: Option<SyntaxKind>,
53     },
54     Derive,
55     /// Path in item position, that is inside an (Assoc)ItemList
56     Item,
57     Pat,
58     Vis {
59         has_in_token: bool,
60     },
61     Use,
62 }
63
64 #[derive(Debug)]
65 pub(crate) struct PathCompletionCtx {
66     /// If this is a call with () already there (or {} in case of record patterns)
67     pub(super) has_call_parens: bool,
68     /// If this has a macro call bang !
69     pub(super) has_macro_bang: bool,
70     /// Whether this path stars with a `::`.
71     pub(super) is_absolute_path: bool,
72     /// The qualifier of the current path if it exists.
73     pub(super) qualifier: Option<PathQualifierCtx>,
74     pub(super) kind: Option<PathKind>,
75     /// Whether the path segment has type args or not.
76     pub(super) has_type_args: bool,
77     /// `true` if we are a statement or a last expr in the block.
78     pub(super) can_be_stmt: bool,
79     pub(super) in_loop_body: bool,
80 }
81
82 #[derive(Debug)]
83 pub(crate) struct PathQualifierCtx {
84     pub(crate) path: ast::Path,
85     pub(crate) resolution: Option<PathResolution>,
86     /// Whether this path consists solely of `super` segments
87     pub(crate) is_super_chain: bool,
88     /// Whether the qualifier comes from a use tree parent or not
89     pub(crate) use_tree_parent: bool,
90 }
91
92 #[derive(Debug)]
93 pub(super) struct PatternContext {
94     pub(super) refutability: PatternRefutability,
95     pub(super) param_ctx: Option<(ast::ParamList, ast::Param, ParamKind)>,
96     pub(super) has_type_ascription: bool,
97     pub(super) parent_pat: Option<ast::Pat>,
98     pub(super) ref_token: Option<SyntaxToken>,
99     pub(super) mut_token: Option<SyntaxToken>,
100 }
101
102 #[derive(Debug)]
103 pub(super) enum LifetimeContext {
104     LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
105     Lifetime,
106     LabelRef,
107     LabelDef,
108 }
109
110 #[derive(Debug)]
111 #[allow(dead_code)]
112 pub(super) enum NameContext {
113     Const,
114     ConstParam,
115     Enum,
116     Function,
117     IdentPat,
118     MacroDef,
119     MacroRules,
120     /// Fake node
121     Module(ast::Module),
122     RecordField,
123     Rename,
124     SelfParam,
125     Static,
126     Struct,
127     Trait,
128     TypeAlias,
129     TypeParam,
130     Union,
131     Variant,
132 }
133
134 #[derive(Clone, Debug, PartialEq, Eq)]
135 pub(crate) enum ParamKind {
136     Function(ast::Fn),
137     Closure(ast::ClosureExpr),
138 }
139
140 /// `CompletionContext` is created early during completion to figure out, where
141 /// exactly is the cursor, syntax-wise.
142 #[derive(Debug)]
143 pub(crate) struct CompletionContext<'a> {
144     pub(super) sema: Semantics<'a, RootDatabase>,
145     pub(super) scope: SemanticsScope<'a>,
146     pub(super) db: &'a RootDatabase,
147     pub(super) config: &'a CompletionConfig,
148     pub(super) position: FilePosition,
149
150     /// The token before the cursor, in the original file.
151     pub(super) original_token: SyntaxToken,
152     /// The token before the cursor, in the macro-expanded file.
153     pub(super) token: SyntaxToken,
154     /// The crate of the current file.
155     pub(super) krate: hir::Crate,
156     /// The module of the `scope`.
157     pub(super) module: hir::Module,
158
159     /// The expected name of what we are completing.
160     /// This is usually the parameter name of the function argument we are completing.
161     pub(super) expected_name: Option<NameOrNameRef>,
162     /// The expected type of what we are completing.
163     pub(super) expected_type: Option<Type>,
164
165     /// The parent function of the cursor position if it exists.
166     pub(super) function_def: Option<ast::Fn>,
167     /// The parent impl of the cursor position if it exists.
168     pub(super) impl_def: Option<ast::Impl>,
169     /// The NameLike under the cursor in the original file if it exists.
170     pub(super) name_syntax: Option<ast::NameLike>,
171     /// Are we completing inside a let statement with a missing semicolon?
172     pub(super) incomplete_let: bool,
173
174     pub(super) completion_location: Option<ImmediateLocation>,
175     pub(super) prev_sibling: Option<ImmediatePrevSibling>,
176     pub(super) fake_attribute_under_caret: Option<ast::Attr>,
177     pub(super) previous_token: Option<SyntaxToken>,
178
179     pub(super) name_ctx: Option<NameContext>,
180     pub(super) lifetime_ctx: Option<LifetimeContext>,
181     pub(super) pattern_ctx: Option<PatternContext>,
182     pub(super) path_context: Option<PathCompletionCtx>,
183
184     pub(super) existing_derives: FxHashSet<hir::Macro>,
185
186     pub(super) locals: FxHashMap<Name, Local>,
187 }
188
189 impl<'a> CompletionContext<'a> {
190     /// The range of the identifier that is being completed.
191     pub(crate) fn source_range(&self) -> TextRange {
192         // check kind of macro-expanded token, but use range of original token
193         let kind = self.token.kind();
194         match kind {
195             CHAR => {
196                 // assume we are completing a lifetime but the user has only typed the '
197                 cov_mark::hit!(completes_if_lifetime_without_idents);
198                 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
199             }
200             IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(),
201             _ if kind.is_keyword() => self.original_token.text_range(),
202             _ => TextRange::empty(self.position.offset),
203         }
204     }
205
206     pub(crate) fn name_ref(&self) -> Option<&ast::NameRef> {
207         self.name_syntax.as_ref().and_then(ast::NameLike::as_name_ref)
208     }
209
210     pub(crate) fn lifetime(&self) -> Option<&ast::Lifetime> {
211         self.name_syntax.as_ref().and_then(ast::NameLike::as_lifetime)
212     }
213
214     pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool {
215         self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind)
216     }
217
218     pub(crate) fn famous_defs(&self) -> FamousDefs {
219         FamousDefs(&self.sema, self.krate)
220     }
221
222     pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> {
223         match &self.completion_location {
224             Some(
225                 ImmediateLocation::MethodCall { receiver, .. }
226                 | ImmediateLocation::FieldAccess { receiver, .. },
227             ) => receiver.as_ref(),
228             _ => None,
229         }
230     }
231
232     pub(crate) fn has_dot_receiver(&self) -> bool {
233         matches!(
234             &self.completion_location,
235             Some(ImmediateLocation::FieldAccess { receiver, .. } | ImmediateLocation::MethodCall { receiver,.. })
236                 if receiver.is_some()
237         )
238     }
239
240     pub(crate) fn expects_assoc_item(&self) -> bool {
241         matches!(self.completion_location, Some(ImmediateLocation::Trait | ImmediateLocation::Impl))
242     }
243
244     pub(crate) fn expects_variant(&self) -> bool {
245         matches!(self.name_ctx, Some(NameContext::Variant))
246     }
247
248     pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
249         matches!(self.completion_location, Some(ImmediateLocation::Impl))
250     }
251
252     pub(crate) fn expects_item(&self) -> bool {
253         matches!(self.completion_location, Some(ImmediateLocation::ItemList))
254     }
255
256     pub(crate) fn expects_generic_arg(&self) -> bool {
257         matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_)))
258     }
259
260     pub(crate) fn has_block_expr_parent(&self) -> bool {
261         matches!(self.completion_location, Some(ImmediateLocation::StmtList))
262     }
263
264     pub(crate) fn expects_ident_ref_expr(&self) -> bool {
265         matches!(self.completion_location, Some(ImmediateLocation::RefExpr))
266     }
267
268     pub(crate) fn expect_field(&self) -> bool {
269         matches!(self.completion_location, Some(ImmediateLocation::TupleField))
270             || matches!(self.name_ctx, Some(NameContext::RecordField))
271     }
272
273     pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
274         matches!(
275             self.prev_sibling,
276             Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName)
277         )
278     }
279
280     pub(crate) fn has_impl_prev_sibling(&self) -> bool {
281         matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType))
282     }
283
284     pub(crate) fn has_visibility_prev_sibling(&self) -> bool {
285         matches!(self.prev_sibling, Some(ImmediatePrevSibling::Visibility))
286     }
287
288     pub(crate) fn after_if(&self) -> bool {
289         matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr))
290     }
291
292     pub(crate) fn is_path_disallowed(&self) -> bool {
293         self.previous_token_is(T![unsafe])
294             || matches!(
295                 self.prev_sibling,
296                 Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility)
297             )
298             || matches!(
299                 self.completion_location,
300                 Some(ImmediateLocation::RecordPat(_) | ImmediateLocation::RecordExpr(_))
301             )
302             || matches!(self.name_ctx, Some(NameContext::Module(_) | NameContext::Rename))
303     }
304
305     pub(crate) fn expects_expression(&self) -> bool {
306         matches!(self.path_context, Some(PathCompletionCtx { kind: Some(PathKind::Expr), .. }))
307     }
308
309     pub(crate) fn expects_type(&self) -> bool {
310         matches!(self.path_context, Some(PathCompletionCtx { kind: Some(PathKind::Type), .. }))
311     }
312
313     pub(crate) fn path_is_call(&self) -> bool {
314         self.path_context.as_ref().map_or(false, |it| it.has_call_parens)
315     }
316
317     pub(crate) fn is_non_trivial_path(&self) -> bool {
318         matches!(
319             self.path_context,
320             Some(
321                 PathCompletionCtx { is_absolute_path: true, .. }
322                     | PathCompletionCtx { qualifier: Some(_), .. }
323             )
324         )
325     }
326
327     pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
328         self.path_context.as_ref().and_then(|it| it.qualifier.as_ref().map(|it| &it.path))
329     }
330
331     pub(crate) fn path_kind(&self) -> Option<PathKind> {
332         self.path_context.as_ref().and_then(|it| it.kind)
333     }
334
335     pub(crate) fn is_immediately_after_macro_bang(&self) -> bool {
336         self.token.kind() == BANG && self.token.parent().map_or(false, |it| it.kind() == MACRO_CALL)
337     }
338
339     /// Checks if an item is visible and not `doc(hidden)` at the completion site.
340     pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
341     where
342         I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
343     {
344         self.is_visible_impl(&item.visibility(self.db), &item.attrs(self.db), item.krate(self.db))
345     }
346
347     pub(crate) fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
348         if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
349             return self.is_doc_hidden(&attrs, krate);
350         }
351
352         false
353     }
354
355     /// Check if an item is `#[doc(hidden)]`.
356     pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool {
357         let attrs = item.attrs(self.db);
358         let krate = item.krate(self.db);
359         match (attrs, krate) {
360             (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate),
361             _ => false,
362         }
363     }
364     /// Whether the given trait is an operator trait or not.
365     pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
366         match trait_.attrs(self.db).lang() {
367             Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()),
368             None => false,
369         }
370     }
371
372     /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
373     pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
374         let _p = profile::span("CompletionContext::process_all_names");
375         self.scope.process_all_names(&mut |name, def| {
376             if self.is_scope_def_hidden(def) {
377                 return;
378             }
379
380             f(name, def);
381         });
382     }
383
384     pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
385         let _p = profile::span("CompletionContext::process_all_names_raw");
386         self.scope.process_all_names(&mut |name, def| f(name, def));
387     }
388
389     fn is_visible_impl(
390         &self,
391         vis: &hir::Visibility,
392         attrs: &hir::Attrs,
393         defining_crate: hir::Crate,
394     ) -> Visible {
395         if !vis.is_visible_from(self.db, self.module.into()) {
396             if !self.config.enable_private_editable {
397                 return Visible::No;
398             }
399             // If the definition location is editable, also show private items
400             let root_file = defining_crate.root_file(self.db);
401             let source_root_id = self.db.file_source_root(root_file);
402             let is_editable = !self.db.source_root(source_root_id).is_library;
403             return if is_editable { Visible::Editable } else { Visible::No };
404         }
405
406         if self.is_doc_hidden(attrs, defining_crate) {
407             Visible::No
408         } else {
409             Visible::Yes
410         }
411     }
412
413     fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
414         // `doc(hidden)` items are only completed within the defining crate.
415         self.krate != defining_crate && attrs.has_doc_hidden()
416     }
417 }
418
419 // CompletionContext construction
420 impl<'a> CompletionContext<'a> {
421     pub(super) fn new(
422         db: &'a RootDatabase,
423         position @ FilePosition { file_id, offset }: FilePosition,
424         config: &'a CompletionConfig,
425     ) -> Option<CompletionContext<'a>> {
426         let _p = profile::span("CompletionContext::new");
427         let sema = Semantics::new(db);
428
429         let original_file = sema.parse(file_id);
430
431         // Insert a fake ident to get a valid parse tree. We will use this file
432         // to determine context, though the original_file will be used for
433         // actual completion.
434         let file_with_fake_ident = {
435             let parse = db.parse(file_id);
436             let edit = Indel::insert(offset, COMPLETION_MARKER.to_string());
437             parse.reparse(&edit).tree()
438         };
439         let fake_ident_token =
440             file_with_fake_ident.syntax().token_at_offset(offset).right_biased()?;
441
442         let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
443         let token = sema.descend_into_macros_single(original_token.clone());
444         let scope = sema.scope_at_offset(&token.parent()?, offset)?;
445         let krate = scope.krate();
446         let module = scope.module();
447
448         let mut locals = FxHashMap::default();
449         scope.process_all_names(&mut |name, scope| {
450             if let ScopeDef::Local(local) = scope {
451                 locals.insert(name, local);
452             }
453         });
454
455         let mut ctx = CompletionContext {
456             sema,
457             scope,
458             db,
459             config,
460             position,
461             original_token,
462             token,
463             krate,
464             module,
465             expected_name: None,
466             expected_type: None,
467             function_def: None,
468             impl_def: None,
469             name_syntax: None,
470             lifetime_ctx: None,
471             pattern_ctx: None,
472             name_ctx: None,
473             completion_location: None,
474             prev_sibling: None,
475             fake_attribute_under_caret: None,
476             previous_token: None,
477             path_context: None,
478             locals,
479             incomplete_let: false,
480             existing_derives: Default::default(),
481         };
482         ctx.expand_and_fill(
483             original_file.syntax().clone(),
484             file_with_fake_ident.syntax().clone(),
485             offset,
486             fake_ident_token,
487         );
488         Some(ctx)
489     }
490
491     /// Expand attributes and macro calls at the current cursor position for both the original file
492     /// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
493     /// and speculative states stay in sync.
494     fn expand_and_fill(
495         &mut self,
496         mut original_file: SyntaxNode,
497         mut speculative_file: SyntaxNode,
498         mut offset: TextSize,
499         mut fake_ident_token: SyntaxToken,
500     ) {
501         let _p = profile::span("CompletionContext::expand_and_fill");
502         let mut derive_ctx = None;
503
504         'expansion: loop {
505             let parent_item =
506                 |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
507             let ancestor_items = iter::successors(
508                 Option::zip(
509                     find_node_at_offset::<ast::Item>(&original_file, offset),
510                     find_node_at_offset::<ast::Item>(&speculative_file, offset),
511                 ),
512                 |(a, b)| parent_item(a).zip(parent_item(b)),
513             );
514
515             // first try to expand attributes as these are always the outermost macro calls
516             'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
517                 match (
518                     self.sema.expand_attr_macro(&actual_item),
519                     self.sema.speculative_expand_attr_macro(
520                         &actual_item,
521                         &item_with_fake_ident,
522                         fake_ident_token.clone(),
523                     ),
524                 ) {
525                     // maybe parent items have attributes, so continue walking the ancestors
526                     (None, None) => continue 'ancestors,
527                     // successful expansions
528                     (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
529                         let new_offset = fake_mapped_token.text_range().start();
530                         if new_offset > actual_expansion.text_range().end() {
531                             // offset outside of bounds from the original expansion,
532                             // stop here to prevent problems from happening
533                             break 'expansion;
534                         }
535                         original_file = actual_expansion;
536                         speculative_file = fake_expansion;
537                         fake_ident_token = fake_mapped_token;
538                         offset = new_offset;
539                         continue 'expansion;
540                     }
541                     // exactly one expansion failed, inconsistent state so stop expanding completely
542                     _ => break 'expansion,
543                 }
544             }
545
546             // No attributes have been expanded, so look for macro_call! token trees or derive token trees
547             let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
548                 Some(it) => it,
549                 None => break 'expansion,
550             };
551             let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
552                 Some(it) => it,
553                 None => break 'expansion,
554             };
555
556             // Expand pseudo-derive expansion
557             if let (Some(orig_attr), Some(spec_attr)) = (
558                 orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
559                 spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
560             ) {
561                 if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = (
562                     self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
563                     self.sema.speculative_expand_derive_as_pseudo_attr_macro(
564                         &orig_attr,
565                         &spec_attr,
566                         fake_ident_token.clone(),
567                     ),
568                 ) {
569                     derive_ctx = Some((
570                         actual_expansion,
571                         fake_expansion,
572                         fake_mapped_token.text_range().start(),
573                         orig_attr,
574                     ));
575                 }
576                 // at this point we won't have any more successful expansions, so stop
577                 break 'expansion;
578             }
579
580             // Expand fn-like macro calls
581             if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
582                 orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
583                 spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
584             ) {
585                 let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
586                 let mac_call_path1 =
587                     macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
588
589                 // inconsistent state, stop expanding
590                 if mac_call_path0 != mac_call_path1 {
591                     break 'expansion;
592                 }
593                 let speculative_args = match macro_call_with_fake_ident.token_tree() {
594                     Some(tt) => tt,
595                     None => break 'expansion,
596                 };
597
598                 match (
599                     self.sema.expand(&actual_macro_call),
600                     self.sema.speculative_expand(
601                         &actual_macro_call,
602                         &speculative_args,
603                         fake_ident_token.clone(),
604                     ),
605                 ) {
606                     // successful expansions
607                     (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
608                         let new_offset = fake_mapped_token.text_range().start();
609                         if new_offset > actual_expansion.text_range().end() {
610                             // offset outside of bounds from the original expansion,
611                             // stop here to prevent problems from happening
612                             break 'expansion;
613                         }
614                         original_file = actual_expansion;
615                         speculative_file = fake_expansion;
616                         fake_ident_token = fake_mapped_token;
617                         offset = new_offset;
618                         continue 'expansion;
619                     }
620                     // at least on expansion failed, we won't have anything to expand from this point
621                     // onwards so break out
622                     _ => break 'expansion,
623                 }
624             }
625
626             // none of our states have changed so stop the loop
627             break 'expansion;
628         }
629
630         self.fill(&original_file, speculative_file, offset, derive_ctx);
631     }
632
633     /// Calculate the expected type and name of the cursor position.
634     fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
635         let mut node = match self.token.parent() {
636             Some(it) => it,
637             None => return (None, None),
638         };
639         loop {
640             break match_ast! {
641                 match node {
642                     ast::LetStmt(it) => {
643                         cov_mark::hit!(expected_type_let_with_leading_char);
644                         cov_mark::hit!(expected_type_let_without_leading_char);
645                         let ty = it.pat()
646                             .and_then(|pat| self.sema.type_of_pat(&pat))
647                             .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it)))
648                             .map(TypeInfo::original);
649                         let name = match it.pat() {
650                             Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
651                             Some(_) | None => None,
652                         };
653
654                         (ty, name)
655                     },
656                     ast::LetExpr(it) => {
657                         cov_mark::hit!(expected_type_if_let_without_leading_char);
658                         let ty = it.pat()
659                             .and_then(|pat| self.sema.type_of_pat(&pat))
660                             .or_else(|| it.expr().and_then(|it| self.sema.type_of_expr(&it)))
661                             .map(TypeInfo::original);
662                         (ty, None)
663                     },
664                     ast::ArgList(_) => {
665                         cov_mark::hit!(expected_type_fn_param);
666                         ActiveParameter::at_token(
667                             &self.sema,
668                             self.token.clone(),
669                         ).map(|ap| {
670                             let name = ap.ident().map(NameOrNameRef::Name);
671                             let ty = if has_ref(&self.token) {
672                                 cov_mark::hit!(expected_type_fn_param_ref);
673                                 ap.ty.remove_ref()
674                             } else {
675                                 Some(ap.ty)
676                             };
677                             (ty, name)
678                         })
679                         .unwrap_or((None, None))
680                     },
681                     ast::RecordExprFieldList(it) => {
682                         // wouldn't try {} be nice...
683                         (|| {
684                             if self.token.kind() == T![..]
685                                 || self.token.prev_token().map(|t| t.kind()) == Some(T![..])
686                             {
687                                 cov_mark::hit!(expected_type_struct_func_update);
688                                 let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?;
689                                 let ty = self.sema.type_of_expr(&record_expr.into())?;
690                                 Some((
691                                     Some(ty.original),
692                                     None
693                                 ))
694                             } else {
695                                 cov_mark::hit!(expected_type_struct_field_without_leading_char);
696                                 let expr_field = self.token.prev_sibling_or_token()?
697                                     .into_node()
698                                     .and_then(ast::RecordExprField::cast)?;
699                                 let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
700                                 Some((
701                                     Some(ty),
702                                     expr_field.field_name().map(NameOrNameRef::NameRef),
703                                 ))
704                             }
705                         })().unwrap_or((None, None))
706                     },
707                     ast::RecordExprField(it) => {
708                         if let Some(expr) = it.expr() {
709                             cov_mark::hit!(expected_type_struct_field_with_leading_char);
710                             (
711                                 self.sema.type_of_expr(&expr).map(TypeInfo::original),
712                                 it.field_name().map(NameOrNameRef::NameRef),
713                             )
714                         } else {
715                             cov_mark::hit!(expected_type_struct_field_followed_by_comma);
716                             let ty = self.sema.resolve_record_field(&it)
717                                 .map(|(_, _, ty)| ty);
718                             (
719                                 ty,
720                                 it.field_name().map(NameOrNameRef::NameRef),
721                             )
722                         }
723                     },
724                     ast::MatchExpr(it) => {
725                         cov_mark::hit!(expected_type_match_arm_without_leading_char);
726                         let ty = it.expr().and_then(|e| self.sema.type_of_expr(&e)).map(TypeInfo::original);
727                         (ty, None)
728                     },
729                     ast::IfExpr(it) => {
730                         let ty = it.condition()
731                             .and_then(|e| self.sema.type_of_expr(&e))
732                             .map(TypeInfo::original);
733                         (ty, None)
734                     },
735                     ast::IdentPat(it) => {
736                         cov_mark::hit!(expected_type_if_let_with_leading_char);
737                         cov_mark::hit!(expected_type_match_arm_with_leading_char);
738                         let ty = self.sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original);
739                         (ty, None)
740                     },
741                     ast::Fn(it) => {
742                         cov_mark::hit!(expected_type_fn_ret_with_leading_char);
743                         cov_mark::hit!(expected_type_fn_ret_without_leading_char);
744                         let def = self.sema.to_def(&it);
745                         (def.map(|def| def.ret_type(self.db)), None)
746                     },
747                     ast::ClosureExpr(it) => {
748                         let ty = self.sema.type_of_expr(&it.into());
749                         ty.and_then(|ty| ty.original.as_callable(self.db))
750                             .map(|c| (Some(c.return_type()), None))
751                             .unwrap_or((None, None))
752                     },
753                     ast::ParamList(_) => (None, None),
754                     ast::Stmt(_) => (None, None),
755                     ast::Item(_) => (None, None),
756                     _ => {
757                         match node.parent() {
758                             Some(n) => {
759                                 node = n;
760                                 continue;
761                             },
762                             None => (None, None),
763                         }
764                     },
765                 }
766             };
767         }
768     }
769
770     /// Fill the completion context, this is what does semantic reasoning about the surrounding context
771     /// of the completion location.
772     fn fill(
773         &mut self,
774         original_file: &SyntaxNode,
775         file_with_fake_ident: SyntaxNode,
776         offset: TextSize,
777         derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
778     ) {
779         let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
780         let syntax_element = NodeOrToken::Token(fake_ident_token);
781         if is_in_token_of_for_loop(syntax_element.clone()) {
782             // for pat $0
783             // there is nothing to complete here except `in` keyword
784             // don't bother populating the context
785             // FIXME: the completion calculations should end up good enough
786             // such that this special case becomes unnecessary
787             return;
788         }
789
790         self.previous_token = previous_token(syntax_element.clone());
791         self.fake_attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
792
793         self.incomplete_let =
794             syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
795                 it.syntax().text_range().end() == syntax_element.text_range().end()
796             });
797
798         (self.expected_type, self.expected_name) = self.expected_type_and_name();
799
800         // Overwrite the path kind for derives
801         if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
802             self.existing_derives = self
803                 .sema
804                 .resolve_derive_macro(&origin_attr)
805                 .into_iter()
806                 .flatten()
807                 .flatten()
808                 .collect();
809
810             if let Some(ast::NameLike::NameRef(name_ref)) =
811                 find_node_at_offset(&file_with_fake_ident, offset)
812             {
813                 self.name_syntax =
814                     find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
815                 if let Some((path_ctx, _)) =
816                     Self::classify_name_ref(&self.sema, &original_file, name_ref)
817                 {
818                     self.path_context =
819                         Some(PathCompletionCtx { kind: Some(PathKind::Derive), ..path_ctx });
820                 }
821             }
822             return;
823         }
824
825         let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
826             Some(it) => it,
827             None => return,
828         };
829         self.completion_location =
830             determine_location(&self.sema, original_file, offset, &name_like);
831         self.prev_sibling = determine_prev_sibling(&name_like);
832         self.name_syntax =
833             find_node_at_offset(original_file, name_like.syntax().text_range().start());
834         self.impl_def = self
835             .sema
836             .token_ancestors_with_macros(self.token.clone())
837             .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
838             .find_map(ast::Impl::cast);
839         self.function_def = self
840             .sema
841             .token_ancestors_with_macros(self.token.clone())
842             .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
843             .find_map(ast::Fn::cast);
844
845         match name_like {
846             ast::NameLike::Lifetime(lifetime) => {
847                 self.lifetime_ctx = Self::classify_lifetime(&self.sema, original_file, lifetime);
848             }
849             ast::NameLike::NameRef(name_ref) => {
850                 if let Some((path_ctx, pat_ctx)) =
851                     Self::classify_name_ref(&self.sema, original_file, name_ref)
852                 {
853                     self.path_context = Some(path_ctx);
854                     self.pattern_ctx = pat_ctx;
855                 }
856             }
857             ast::NameLike::Name(name) => {
858                 if let Some((name_ctx, pat_ctx)) =
859                     Self::classify_name(&self.sema, original_file, name)
860                 {
861                     self.pattern_ctx = pat_ctx;
862                     self.name_ctx = Some(name_ctx);
863                 }
864             }
865         }
866     }
867
868     fn classify_lifetime(
869         _sema: &Semantics<RootDatabase>,
870         _original_file: &SyntaxNode,
871         lifetime: ast::Lifetime,
872     ) -> Option<LifetimeContext> {
873         let parent = lifetime.syntax().parent()?;
874         if parent.kind() == ERROR {
875             return None;
876         }
877
878         Some(match_ast! {
879             match parent {
880                 ast::LifetimeParam(param) => LifetimeContext::LifetimeParam {
881                     is_decl: param.lifetime().as_ref() == Some(&lifetime),
882                     param
883                 },
884                 ast::BreakExpr(_) => LifetimeContext::LabelRef,
885                 ast::ContinueExpr(_) => LifetimeContext::LabelRef,
886                 ast::Label(_) => LifetimeContext::LabelDef,
887                 _ => LifetimeContext::Lifetime,
888             }
889         })
890     }
891
892     fn classify_name(
893         _sema: &Semantics<RootDatabase>,
894         original_file: &SyntaxNode,
895         name: ast::Name,
896     ) -> Option<(NameContext, Option<PatternContext>)> {
897         let parent = name.syntax().parent()?;
898         let mut pat_ctx = None;
899         let name_ctx = match_ast! {
900             match parent {
901                 ast::Const(_) => NameContext::Const,
902                 ast::ConstParam(_) => NameContext::ConstParam,
903                 ast::Enum(_) => NameContext::Enum,
904                 ast::Fn(_) => NameContext::Function,
905                 ast::IdentPat(bind_pat) => {
906                     let is_name_in_field_pat = bind_pat
907                         .syntax()
908                         .parent()
909                         .and_then(ast::RecordPatField::cast)
910                         .map_or(false, |pat_field| pat_field.name_ref().is_none());
911                     if !is_name_in_field_pat {
912                         pat_ctx = Some(pattern_context_for(original_file, bind_pat.into()));
913                     }
914
915                     NameContext::IdentPat
916                 },
917                 ast::MacroDef(_) => NameContext::MacroDef,
918                 ast::MacroRules(_) => NameContext::MacroRules,
919                 ast::Module(module) => NameContext::Module(module),
920                 ast::RecordField(_) => NameContext::RecordField,
921                 ast::Rename(_) => NameContext::Rename,
922                 ast::SelfParam(_) => NameContext::SelfParam,
923                 ast::Static(_) => NameContext::Static,
924                 ast::Struct(_) => NameContext::Struct,
925                 ast::Trait(_) => NameContext::Trait,
926                 ast::TypeAlias(_) => NameContext::TypeAlias,
927                 ast::TypeParam(_) => NameContext::TypeParam,
928                 ast::Union(_) => NameContext::Union,
929                 ast::Variant(_) => NameContext::Variant,
930                 _ => return None,
931             }
932         };
933         Some((name_ctx, pat_ctx))
934     }
935
936     fn classify_name_ref(
937         sema: &Semantics<RootDatabase>,
938         original_file: &SyntaxNode,
939         name_ref: ast::NameRef,
940     ) -> Option<(PathCompletionCtx, Option<PatternContext>)> {
941         let parent = name_ref.syntax().parent()?;
942         let segment = ast::PathSegment::cast(parent)?;
943         let path = segment.parent_path();
944
945         let mut path_ctx = PathCompletionCtx {
946             has_call_parens: false,
947             is_absolute_path: false,
948             qualifier: None,
949             has_type_args: false,
950             can_be_stmt: false,
951             in_loop_body: false,
952             has_macro_bang: false,
953             kind: None,
954         };
955         let mut pat_ctx = None;
956         path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
957
958         path_ctx.kind = path.syntax().ancestors().find_map(|it| {
959             // using Option<Option<PathKind>> as extra controlflow
960             let kind = match_ast! {
961                 match it {
962                     ast::PathType(_) => Some(PathKind::Type),
963                     ast::PathExpr(it) => {
964                         path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
965                         Some(PathKind::Expr)
966                     },
967                     ast::TupleStructPat(it) => {
968                         path_ctx.has_call_parens = true;
969                         pat_ctx = Some(pattern_context_for(original_file, it.into()));
970                         Some(PathKind::Pat)
971                     },
972                     ast::RecordPat(it) => {
973                         path_ctx.has_call_parens = true;
974                         pat_ctx = Some(pattern_context_for(original_file, it.into()));
975                         Some(PathKind::Pat)
976                     },
977                     ast::PathPat(it) => {
978                         pat_ctx = Some(pattern_context_for(original_file, it.into()));
979                         Some(PathKind::Pat)
980                     },
981                     ast::MacroCall(it) => {
982                         path_ctx.has_macro_bang = it.excl_token().is_some();
983                         match it.syntax().parent().map(|it| it.kind()) {
984                             Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
985                             Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type),
986                             Some(SyntaxKind::MACRO_EXPR) => Some(PathKind::Expr),
987                             Some(
988                                 SyntaxKind::ITEM_LIST
989                                 | SyntaxKind::ASSOC_ITEM_LIST
990                                 | SyntaxKind::EXTERN_ITEM_LIST
991                                 | SyntaxKind::SOURCE_FILE
992                             ) => Some(PathKind::Item),
993                             _ => return Some(None),
994                         }
995                     },
996                     ast::Meta(meta) => (|| {
997                         let attr = meta.parent_attr()?;
998                         let kind = attr.kind();
999                         let attached = attr.syntax().parent()?;
1000                         let is_trailing_outer_attr = kind != AttrKind::Inner
1001                             && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
1002                         let annotated_item_kind = if is_trailing_outer_attr {
1003                             None
1004                         } else {
1005                             Some(attached.kind())
1006                         };
1007                         Some(PathKind::Attr {
1008                             kind,
1009                             annotated_item_kind,
1010                         })
1011                     })(),
1012                     ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
1013                     ast::UseTree(_) => Some(PathKind::Use),
1014                     ast::ItemList(_) => Some(PathKind::Item),
1015                     ast::AssocItemList(_) => Some(PathKind::Item),
1016                     ast::ExternItemList(_) => Some(PathKind::Item),
1017                     ast::SourceFile(_) => Some(PathKind::Item),
1018                     _ => return None,
1019                 }
1020             };
1021             Some(kind)
1022         }).flatten();
1023         path_ctx.has_type_args = segment.generic_arg_list().is_some();
1024
1025         if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
1026             if !use_tree_parent {
1027                 path_ctx.is_absolute_path =
1028                     path.top_path().segment().map_or(false, |it| it.coloncolon_token().is_some());
1029             }
1030
1031             let path = path
1032                 .segment()
1033                 .and_then(|it| find_node_in_file(original_file, &it))
1034                 .map(|it| it.parent_path());
1035             path_ctx.qualifier = path.map(|path| {
1036                 let res = sema.resolve_path(&path);
1037                 let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier())
1038                     .all(|p| p.segment().and_then(|s| s.super_token()).is_some());
1039                 PathQualifierCtx { path, resolution: res, is_super_chain, use_tree_parent }
1040             });
1041             return Some((path_ctx, pat_ctx));
1042         }
1043
1044         if let Some(segment) = path.segment() {
1045             if segment.coloncolon_token().is_some() {
1046                 path_ctx.is_absolute_path = true;
1047                 return Some((path_ctx, pat_ctx));
1048             }
1049         }
1050
1051         // Find either enclosing expr statement (thing with `;`) or a
1052         // block. If block, check that we are the last expr.
1053         path_ctx.can_be_stmt = name_ref
1054             .syntax()
1055             .ancestors()
1056             .find_map(|node| {
1057                 if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
1058                     return Some(stmt.syntax().text_range() == name_ref.syntax().text_range());
1059                 }
1060                 if let Some(stmt_list) = ast::StmtList::cast(node) {
1061                     return Some(
1062                         stmt_list.tail_expr().map(|e| e.syntax().text_range())
1063                             == Some(name_ref.syntax().text_range()),
1064                     );
1065                 }
1066                 None
1067             })
1068             .unwrap_or(false);
1069         Some((path_ctx, pat_ctx))
1070     }
1071 }
1072
1073 fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternContext {
1074     let mut is_param = None;
1075     let (refutability, has_type_ascription) =
1076     pat
1077         .syntax()
1078         .ancestors()
1079         .skip_while(|it| ast::Pat::can_cast(it.kind()))
1080         .next()
1081         .map_or((PatternRefutability::Irrefutable, false), |node| {
1082             let refutability = match_ast! {
1083                 match node {
1084                     ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
1085                     ast::Param(param) => {
1086                         let has_type_ascription = param.ty().is_some();
1087                         is_param = (|| {
1088                             let fake_param_list = param.syntax().parent().and_then(ast::ParamList::cast)?;
1089                             let param_list = find_node_in_file_compensated(original_file, &fake_param_list)?;
1090                             let param_list_owner = param_list.syntax().parent()?;
1091                             let kind = match_ast! {
1092                                 match param_list_owner {
1093                                     ast::ClosureExpr(closure) => ParamKind::Closure(closure),
1094                                     ast::Fn(fn_) => ParamKind::Function(fn_),
1095                                     _ => return None,
1096                                 }
1097                             };
1098                             Some((param_list, param, kind))
1099                         })();
1100                         return (PatternRefutability::Irrefutable, has_type_ascription)
1101                     },
1102                     ast::MatchArm(_) => PatternRefutability::Refutable,
1103                     ast::LetExpr(_) => PatternRefutability::Refutable,
1104                     ast::ForExpr(_) => PatternRefutability::Irrefutable,
1105                     _ => PatternRefutability::Irrefutable,
1106                 }
1107             };
1108             (refutability, false)
1109         });
1110     let (ref_token, mut_token) = match &pat {
1111         ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()),
1112         _ => (None, None),
1113     };
1114     PatternContext {
1115         refutability,
1116         param_ctx: is_param,
1117         has_type_ascription,
1118         parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
1119         mut_token,
1120         ref_token,
1121     }
1122 }
1123
1124 /// Attempts to find `node` inside `syntax` via `node`'s text range.
1125 fn find_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: &N) -> Option<N> {
1126     let syntax_range = syntax.text_range();
1127     let range = node.syntax().text_range();
1128     let intersection = range.intersect(syntax_range)?;
1129     syntax.covering_element(intersection).ancestors().find_map(N::cast)
1130 }
1131
1132 /// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
1133 /// for the offset introduced by the fake ident.
1134 /// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
1135 fn find_node_in_file_compensated<N: AstNode>(syntax: &SyntaxNode, node: &N) -> Option<N> {
1136     let syntax_range = syntax.text_range();
1137     let range = node.syntax().text_range();
1138     let end = range.end().checked_sub(TextSize::try_from(COMPLETION_MARKER.len()).ok()?)?;
1139     if end < range.start() {
1140         return None;
1141     }
1142     let range = TextRange::new(range.start(), end);
1143     // our inserted ident could cause `range` to be go outside of the original syntax, so cap it
1144     let intersection = range.intersect(syntax_range)?;
1145     syntax.covering_element(intersection).ancestors().find_map(N::cast)
1146 }
1147
1148 fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
1149     if let Some(qual) = path.qualifier() {
1150         return Some((qual, false));
1151     }
1152     let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
1153     let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
1154     Some((use_tree.path()?, true))
1155 }
1156
1157 fn has_ref(token: &SyntaxToken) -> bool {
1158     let mut token = token.clone();
1159     for skip in [IDENT, WHITESPACE, T![mut]] {
1160         if token.kind() == skip {
1161             token = match token.prev_token() {
1162                 Some(it) => it,
1163                 None => return false,
1164             }
1165         }
1166     }
1167     token.kind() == T![&]
1168 }
1169
1170 const OP_TRAIT_LANG_NAMES: &[&str] = &[
1171     "add_assign",
1172     "add",
1173     "bitand_assign",
1174     "bitand",
1175     "bitor_assign",
1176     "bitor",
1177     "bitxor_assign",
1178     "bitxor",
1179     "deref_mut",
1180     "deref",
1181     "div_assign",
1182     "div",
1183     "eq",
1184     "fn_mut",
1185     "fn_once",
1186     "fn",
1187     "index_mut",
1188     "index",
1189     "mul_assign",
1190     "mul",
1191     "neg",
1192     "not",
1193     "partial_ord",
1194     "rem_assign",
1195     "rem",
1196     "shl_assign",
1197     "shl",
1198     "shr_assign",
1199     "shr",
1200     "sub",
1201 ];
1202
1203 #[cfg(test)]
1204 mod tests {
1205     use expect_test::{expect, Expect};
1206     use hir::HirDisplay;
1207
1208     use crate::tests::{position, TEST_CONFIG};
1209
1210     use super::CompletionContext;
1211
1212     fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) {
1213         let (db, pos) = position(ra_fixture);
1214         let config = TEST_CONFIG;
1215         let completion_context = CompletionContext::new(&db, pos, &config).unwrap();
1216
1217         let ty = completion_context
1218             .expected_type
1219             .map(|t| t.display_test(&db).to_string())
1220             .unwrap_or("?".to_owned());
1221
1222         let name = completion_context
1223             .expected_name
1224             .map_or_else(|| "?".to_owned(), |name| name.to_string());
1225
1226         expect.assert_eq(&format!("ty: {}, name: {}", ty, name));
1227     }
1228
1229     #[test]
1230     fn expected_type_let_without_leading_char() {
1231         cov_mark::check!(expected_type_let_without_leading_char);
1232         check_expected_type_and_name(
1233             r#"
1234 fn foo() {
1235     let x: u32 = $0;
1236 }
1237 "#,
1238             expect![[r#"ty: u32, name: x"#]],
1239         );
1240     }
1241
1242     #[test]
1243     fn expected_type_let_with_leading_char() {
1244         cov_mark::check!(expected_type_let_with_leading_char);
1245         check_expected_type_and_name(
1246             r#"
1247 fn foo() {
1248     let x: u32 = c$0;
1249 }
1250 "#,
1251             expect![[r#"ty: u32, name: x"#]],
1252         );
1253     }
1254
1255     #[test]
1256     fn expected_type_let_pat() {
1257         check_expected_type_and_name(
1258             r#"
1259 fn foo() {
1260     let x$0 = 0u32;
1261 }
1262 "#,
1263             expect![[r#"ty: u32, name: ?"#]],
1264         );
1265         check_expected_type_and_name(
1266             r#"
1267 fn foo() {
1268     let $0 = 0u32;
1269 }
1270 "#,
1271             expect![[r#"ty: u32, name: ?"#]],
1272         );
1273     }
1274
1275     #[test]
1276     fn expected_type_fn_param() {
1277         cov_mark::check!(expected_type_fn_param);
1278         check_expected_type_and_name(
1279             r#"
1280 fn foo() { bar($0); }
1281 fn bar(x: u32) {}
1282 "#,
1283             expect![[r#"ty: u32, name: x"#]],
1284         );
1285         check_expected_type_and_name(
1286             r#"
1287 fn foo() { bar(c$0); }
1288 fn bar(x: u32) {}
1289 "#,
1290             expect![[r#"ty: u32, name: x"#]],
1291         );
1292     }
1293
1294     #[test]
1295     fn expected_type_fn_param_ref() {
1296         cov_mark::check!(expected_type_fn_param_ref);
1297         check_expected_type_and_name(
1298             r#"
1299 fn foo() { bar(&$0); }
1300 fn bar(x: &u32) {}
1301 "#,
1302             expect![[r#"ty: u32, name: x"#]],
1303         );
1304         check_expected_type_and_name(
1305             r#"
1306 fn foo() { bar(&mut $0); }
1307 fn bar(x: &mut u32) {}
1308 "#,
1309             expect![[r#"ty: u32, name: x"#]],
1310         );
1311         check_expected_type_and_name(
1312             r#"
1313 fn foo() { bar(& c$0); }
1314 fn bar(x: &u32) {}
1315         "#,
1316             expect![[r#"ty: u32, name: x"#]],
1317         );
1318         check_expected_type_and_name(
1319             r#"
1320 fn foo() { bar(&mut c$0); }
1321 fn bar(x: &mut u32) {}
1322 "#,
1323             expect![[r#"ty: u32, name: x"#]],
1324         );
1325         check_expected_type_and_name(
1326             r#"
1327 fn foo() { bar(&c$0); }
1328 fn bar(x: &u32) {}
1329         "#,
1330             expect![[r#"ty: u32, name: x"#]],
1331         );
1332     }
1333
1334     #[test]
1335     fn expected_type_struct_field_without_leading_char() {
1336         cov_mark::check!(expected_type_struct_field_without_leading_char);
1337         check_expected_type_and_name(
1338             r#"
1339 struct Foo { a: u32 }
1340 fn foo() {
1341     Foo { a: $0 };
1342 }
1343 "#,
1344             expect![[r#"ty: u32, name: a"#]],
1345         )
1346     }
1347
1348     #[test]
1349     fn expected_type_struct_field_followed_by_comma() {
1350         cov_mark::check!(expected_type_struct_field_followed_by_comma);
1351         check_expected_type_and_name(
1352             r#"
1353 struct Foo { a: u32 }
1354 fn foo() {
1355     Foo { a: $0, };
1356 }
1357 "#,
1358             expect![[r#"ty: u32, name: a"#]],
1359         )
1360     }
1361
1362     #[test]
1363     fn expected_type_generic_struct_field() {
1364         check_expected_type_and_name(
1365             r#"
1366 struct Foo<T> { a: T }
1367 fn foo() -> Foo<u32> {
1368     Foo { a: $0 }
1369 }
1370 "#,
1371             expect![[r#"ty: u32, name: a"#]],
1372         )
1373     }
1374
1375     #[test]
1376     fn expected_type_struct_field_with_leading_char() {
1377         cov_mark::check!(expected_type_struct_field_with_leading_char);
1378         check_expected_type_and_name(
1379             r#"
1380 struct Foo { a: u32 }
1381 fn foo() {
1382     Foo { a: c$0 };
1383 }
1384 "#,
1385             expect![[r#"ty: u32, name: a"#]],
1386         );
1387     }
1388
1389     #[test]
1390     fn expected_type_match_arm_without_leading_char() {
1391         cov_mark::check!(expected_type_match_arm_without_leading_char);
1392         check_expected_type_and_name(
1393             r#"
1394 enum E { X }
1395 fn foo() {
1396    match E::X { $0 }
1397 }
1398 "#,
1399             expect![[r#"ty: E, name: ?"#]],
1400         );
1401     }
1402
1403     #[test]
1404     fn expected_type_match_arm_with_leading_char() {
1405         cov_mark::check!(expected_type_match_arm_with_leading_char);
1406         check_expected_type_and_name(
1407             r#"
1408 enum E { X }
1409 fn foo() {
1410    match E::X { c$0 }
1411 }
1412 "#,
1413             expect![[r#"ty: E, name: ?"#]],
1414         );
1415     }
1416
1417     #[test]
1418     fn expected_type_if_let_without_leading_char() {
1419         cov_mark::check!(expected_type_if_let_without_leading_char);
1420         check_expected_type_and_name(
1421             r#"
1422 enum Foo { Bar, Baz, Quux }
1423
1424 fn foo() {
1425     let f = Foo::Quux;
1426     if let $0 = f { }
1427 }
1428 "#,
1429             expect![[r#"ty: Foo, name: ?"#]],
1430         )
1431     }
1432
1433     #[test]
1434     fn expected_type_if_let_with_leading_char() {
1435         cov_mark::check!(expected_type_if_let_with_leading_char);
1436         check_expected_type_and_name(
1437             r#"
1438 enum Foo { Bar, Baz, Quux }
1439
1440 fn foo() {
1441     let f = Foo::Quux;
1442     if let c$0 = f { }
1443 }
1444 "#,
1445             expect![[r#"ty: Foo, name: ?"#]],
1446         )
1447     }
1448
1449     #[test]
1450     fn expected_type_fn_ret_without_leading_char() {
1451         cov_mark::check!(expected_type_fn_ret_without_leading_char);
1452         check_expected_type_and_name(
1453             r#"
1454 fn foo() -> u32 {
1455     $0
1456 }
1457 "#,
1458             expect![[r#"ty: u32, name: ?"#]],
1459         )
1460     }
1461
1462     #[test]
1463     fn expected_type_fn_ret_with_leading_char() {
1464         cov_mark::check!(expected_type_fn_ret_with_leading_char);
1465         check_expected_type_and_name(
1466             r#"
1467 fn foo() -> u32 {
1468     c$0
1469 }
1470 "#,
1471             expect![[r#"ty: u32, name: ?"#]],
1472         )
1473     }
1474
1475     #[test]
1476     fn expected_type_fn_ret_fn_ref_fully_typed() {
1477         check_expected_type_and_name(
1478             r#"
1479 fn foo() -> u32 {
1480     foo$0
1481 }
1482 "#,
1483             expect![[r#"ty: u32, name: ?"#]],
1484         )
1485     }
1486
1487     #[test]
1488     fn expected_type_closure_param_return() {
1489         // FIXME: make this work with `|| $0`
1490         check_expected_type_and_name(
1491             r#"
1492 //- minicore: fn
1493 fn foo() {
1494     bar(|| a$0);
1495 }
1496
1497 fn bar(f: impl FnOnce() -> u32) {}
1498 "#,
1499             expect![[r#"ty: u32, name: ?"#]],
1500         );
1501     }
1502
1503     #[test]
1504     fn expected_type_generic_function() {
1505         check_expected_type_and_name(
1506             r#"
1507 fn foo() {
1508     bar::<u32>($0);
1509 }
1510
1511 fn bar<T>(t: T) {}
1512 "#,
1513             expect![[r#"ty: u32, name: t"#]],
1514         );
1515     }
1516
1517     #[test]
1518     fn expected_type_generic_method() {
1519         check_expected_type_and_name(
1520             r#"
1521 fn foo() {
1522     S(1u32).bar($0);
1523 }
1524
1525 struct S<T>(T);
1526 impl<T> S<T> {
1527     fn bar(self, t: T) {}
1528 }
1529 "#,
1530             expect![[r#"ty: u32, name: t"#]],
1531         );
1532     }
1533
1534     #[test]
1535     fn expected_type_functional_update() {
1536         cov_mark::check!(expected_type_struct_func_update);
1537         check_expected_type_and_name(
1538             r#"
1539 struct Foo { field: u32 }
1540 fn foo() {
1541     Foo {
1542         ..$0
1543     }
1544 }
1545 "#,
1546             expect![[r#"ty: Foo, name: ?"#]],
1547         );
1548     }
1549
1550     #[test]
1551     fn expected_type_param_pat() {
1552         check_expected_type_and_name(
1553             r#"
1554 struct Foo { field: u32 }
1555 fn foo(a$0: Foo) {}
1556 "#,
1557             expect![[r#"ty: Foo, name: ?"#]],
1558         );
1559         check_expected_type_and_name(
1560             r#"
1561 struct Foo { field: u32 }
1562 fn foo($0: Foo) {}
1563 "#,
1564             // FIXME make this work, currently fails due to pattern recovery eating the `:`
1565             expect![[r#"ty: ?, name: ?"#]],
1566         );
1567     }
1568 }