]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/context.rs
Merge #9012
[rust.git] / crates / ide_completion / src / context.rs
1 //! See `CompletionContext` structure.
2
3 use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
4 use ide_db::{
5     base_db::{FilePosition, SourceDatabase},
6     call_info::ActiveParameter,
7     RootDatabase,
8 };
9 use syntax::{
10     algo::find_node_at_offset,
11     ast::{self, NameOrNameRef, NameOwner},
12     match_ast, AstNode, NodeOrToken,
13     SyntaxKind::{self, *},
14     SyntaxNode, SyntaxToken, TextRange, TextSize, T,
15 };
16 use text_edit::Indel;
17
18 use crate::{
19     patterns::{
20         for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent,
21         has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent,
22         has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, inside_impl_trait_block,
23         is_in_loop_body, is_match_arm, previous_token,
24     },
25     CompletionConfig,
26 };
27
28 /// `CompletionContext` is created early during completion to figure out, where
29 /// exactly is the cursor, syntax-wise.
30 #[derive(Debug)]
31 pub(crate) struct CompletionContext<'a> {
32     pub(super) sema: Semantics<'a, RootDatabase>,
33     pub(super) scope: SemanticsScope<'a>,
34     pub(super) db: &'a RootDatabase,
35     pub(super) config: &'a CompletionConfig,
36     pub(super) position: FilePosition,
37     /// The token before the cursor, in the original file.
38     pub(super) original_token: SyntaxToken,
39     /// The token before the cursor, in the macro-expanded file.
40     pub(super) token: SyntaxToken,
41     pub(super) krate: Option<hir::Crate>,
42     pub(super) expected_name: Option<NameOrNameRef>,
43     pub(super) expected_type: Option<Type>,
44     pub(super) name_ref_syntax: Option<ast::NameRef>,
45     pub(super) lifetime_syntax: Option<ast::Lifetime>,
46     pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
47     pub(super) function_syntax: Option<ast::Fn>,
48     pub(super) use_item_syntax: Option<ast::Use>,
49     pub(super) record_lit_syntax: Option<ast::RecordExpr>,
50     pub(super) record_pat_syntax: Option<ast::RecordPat>,
51     pub(super) record_field_syntax: Option<ast::RecordExprField>,
52     pub(super) impl_def: Option<ast::Impl>,
53     pub(super) lifetime_allowed: bool,
54     /// FIXME: `ActiveParameter` is string-based, which is very very wrong
55     pub(super) active_parameter: Option<ActiveParameter>,
56     pub(super) is_param: bool,
57     pub(super) is_label_ref: bool,
58     /// If a name-binding or reference to a const in a pattern.
59     /// Irrefutable patterns (like let) are excluded.
60     pub(super) is_pat_binding_or_const: bool,
61     pub(super) is_irrefutable_pat_binding: bool,
62     /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
63     pub(super) is_trivial_path: bool,
64     /// If not a trivial path, the prefix (qualifier).
65     pub(super) path_qual: Option<ast::Path>,
66     pub(super) after_if: bool,
67     /// `true` if we are a statement or a last expr in the block.
68     pub(super) can_be_stmt: bool,
69     /// `true` if we expect an expression at the cursor position.
70     pub(super) is_expr: bool,
71     /// Something is typed at the "top" level, in module or impl/trait.
72     pub(super) is_new_item: bool,
73     /// The receiver if this is a field or method access, i.e. writing something.$0
74     pub(super) dot_receiver: Option<ast::Expr>,
75     pub(super) dot_receiver_is_ambiguous_float_literal: bool,
76     /// If this is a call (method or function) in particular, i.e. the () are already there.
77     pub(super) is_call: bool,
78     /// Like `is_call`, but for tuple patterns.
79     pub(super) is_pattern_call: bool,
80     /// If this is a macro call, i.e. the () are already there.
81     pub(super) is_macro_call: bool,
82     pub(super) is_path_type: bool,
83     pub(super) has_type_args: bool,
84     pub(super) attribute_under_caret: Option<ast::Attr>,
85     pub(super) locals: Vec<(String, Local)>,
86
87     pub(super) mod_declaration_under_caret: Option<ast::Module>,
88     pub(super) has_trait_parent: bool,
89     pub(super) has_impl_parent: bool,
90
91     // keyword patterns
92     pub(super) previous_token: Option<SyntaxToken>,
93     pub(super) block_expr_parent: bool,
94     pub(super) bind_pat_parent: bool,
95     pub(super) ref_pat_parent: bool,
96     pub(super) in_loop_body: bool,
97     pub(super) has_field_list_parent: bool,
98     pub(super) trait_as_prev_sibling: bool,
99     pub(super) impl_as_prev_sibling: bool,
100     pub(super) is_match_arm: bool,
101     pub(super) has_item_list_or_source_file_parent: bool,
102     pub(super) incomplete_let: bool,
103
104     no_completion_required: bool,
105 }
106
107 impl<'a> CompletionContext<'a> {
108     pub(super) fn new(
109         db: &'a RootDatabase,
110         position: FilePosition,
111         config: &'a CompletionConfig,
112     ) -> Option<CompletionContext<'a>> {
113         let sema = Semantics::new(db);
114
115         let original_file = sema.parse(position.file_id);
116
117         // Insert a fake ident to get a valid parse tree. We will use this file
118         // to determine context, though the original_file will be used for
119         // actual completion.
120         let file_with_fake_ident = {
121             let parse = db.parse(position.file_id);
122             let edit = Indel::insert(position.offset, "intellijRulezz".to_string());
123             parse.reparse(&edit).tree()
124         };
125         let fake_ident_token =
126             file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap();
127
128         let krate = sema.to_module_def(position.file_id).map(|m| m.krate());
129         let original_token =
130             original_file.syntax().token_at_offset(position.offset).left_biased()?;
131         let token = sema.descend_into_macros(original_token.clone());
132         let scope = sema.scope_at_offset(&token, position.offset);
133         let mut locals = vec![];
134         scope.process_all_names(&mut |name, scope| {
135             if let ScopeDef::Local(local) = scope {
136                 locals.push((name.to_string(), local));
137             }
138         });
139         let mut ctx = CompletionContext {
140             sema,
141             scope,
142             db,
143             config,
144             position,
145             original_token,
146             token,
147             krate,
148             lifetime_allowed: false,
149             expected_name: None,
150             expected_type: None,
151             name_ref_syntax: None,
152             lifetime_syntax: None,
153             lifetime_param_syntax: None,
154             function_syntax: None,
155             use_item_syntax: None,
156             record_lit_syntax: None,
157             record_pat_syntax: None,
158             record_field_syntax: None,
159             impl_def: None,
160             active_parameter: ActiveParameter::at(db, position),
161             is_label_ref: false,
162             is_param: false,
163             is_pat_binding_or_const: false,
164             is_irrefutable_pat_binding: false,
165             is_trivial_path: false,
166             path_qual: None,
167             after_if: false,
168             can_be_stmt: false,
169             is_expr: false,
170             is_new_item: false,
171             dot_receiver: None,
172             dot_receiver_is_ambiguous_float_literal: false,
173             is_call: false,
174             is_pattern_call: false,
175             is_macro_call: false,
176             is_path_type: false,
177             has_type_args: false,
178             attribute_under_caret: None,
179             mod_declaration_under_caret: None,
180             previous_token: None,
181             block_expr_parent: false,
182             bind_pat_parent: false,
183             ref_pat_parent: false,
184             in_loop_body: false,
185             has_trait_parent: false,
186             has_impl_parent: false,
187             has_field_list_parent: false,
188             trait_as_prev_sibling: false,
189             impl_as_prev_sibling: false,
190             is_match_arm: false,
191             has_item_list_or_source_file_parent: false,
192             no_completion_required: false,
193             incomplete_let: false,
194             locals,
195         };
196
197         let mut original_file = original_file.syntax().clone();
198         let mut speculative_file = file_with_fake_ident.syntax().clone();
199         let mut offset = position.offset;
200         let mut fake_ident_token = fake_ident_token;
201
202         // Are we inside a macro call?
203         while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
204             find_node_at_offset::<ast::MacroCall>(&original_file, offset),
205             find_node_at_offset::<ast::MacroCall>(&speculative_file, offset),
206         ) {
207             if actual_macro_call.path().as_ref().map(|s| s.syntax().text())
208                 != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text())
209             {
210                 break;
211             }
212             let speculative_args = match macro_call_with_fake_ident.token_tree() {
213                 Some(tt) => tt,
214                 None => break,
215             };
216             if let (Some(actual_expansion), Some(speculative_expansion)) = (
217                 ctx.sema.expand(&actual_macro_call),
218                 ctx.sema.speculative_expand(
219                     &actual_macro_call,
220                     &speculative_args,
221                     fake_ident_token,
222                 ),
223             ) {
224                 let new_offset = speculative_expansion.1.text_range().start();
225                 if new_offset > actual_expansion.text_range().end() {
226                     break;
227                 }
228                 original_file = actual_expansion;
229                 speculative_file = speculative_expansion.0;
230                 fake_ident_token = speculative_expansion.1;
231                 offset = new_offset;
232             } else {
233                 break;
234             }
235         }
236         ctx.fill_keyword_patterns(&speculative_file, offset);
237         ctx.fill(&original_file, speculative_file, offset);
238         Some(ctx)
239     }
240
241     /// Checks whether completions in that particular case don't make much sense.
242     /// Examples:
243     /// - `fn $0` -- we expect function name, it's unlikely that "hint" will be helpful.
244     ///   Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names.
245     /// - `for _ i$0` -- obviously, it'll be "in" keyword.
246     pub(crate) fn no_completion_required(&self) -> bool {
247         self.no_completion_required
248     }
249
250     /// The range of the identifier that is being completed.
251     pub(crate) fn source_range(&self) -> TextRange {
252         // check kind of macro-expanded token, but use range of original token
253         let kind = self.token.kind();
254         if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() {
255             cov_mark::hit!(completes_if_prefix_is_keyword);
256             self.original_token.text_range()
257         } else if kind == CHAR {
258             // assume we are completing a lifetime but the user has only typed the '
259             cov_mark::hit!(completes_if_lifetime_without_idents);
260             TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
261         } else {
262             TextRange::empty(self.position.offset)
263         }
264     }
265
266     pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool {
267         self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind)
268     }
269
270     fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
271         let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
272         let syntax_element = NodeOrToken::Token(fake_ident_token);
273         self.previous_token = previous_token(syntax_element.clone());
274         self.block_expr_parent = has_block_expr_parent(syntax_element.clone());
275         self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone());
276         self.ref_pat_parent = has_ref_parent(syntax_element.clone());
277         self.in_loop_body = is_in_loop_body(syntax_element.clone());
278         self.has_trait_parent = has_trait_parent(syntax_element.clone());
279         self.has_impl_parent = has_impl_parent(syntax_element.clone());
280         self.has_field_list_parent = has_field_list_parent(syntax_element.clone());
281         self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
282         self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
283         self.is_match_arm = is_match_arm(syntax_element.clone());
284
285         self.has_item_list_or_source_file_parent =
286             has_item_list_or_source_file_parent(syntax_element.clone());
287         self.mod_declaration_under_caret =
288             find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
289                 .filter(|module| module.item_list().is_none());
290         self.incomplete_let =
291             syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
292                 it.syntax().text_range().end() == syntax_element.text_range().end()
293             });
294
295         let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
296         let fn_is_prev = self.previous_token_is(T![fn]);
297         let for_is_prev2 = for_is_prev2(syntax_element.clone());
298         self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2;
299     }
300
301     fn fill_impl_def(&mut self) {
302         self.impl_def = self
303             .sema
304             .token_ancestors_with_macros(self.token.clone())
305             .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
306             .find_map(ast::Impl::cast);
307     }
308
309     fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
310         let mut node = match self.token.parent() {
311             Some(it) => it,
312             None => return (None, None),
313         };
314         loop {
315             break match_ast! {
316                 match node {
317                     ast::LetStmt(it) => {
318                         cov_mark::hit!(expected_type_let_with_leading_char);
319                         cov_mark::hit!(expected_type_let_without_leading_char);
320                         let ty = it.pat()
321                             .and_then(|pat| self.sema.type_of_pat(&pat))
322                             .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it)));
323                         let name = if let Some(ast::Pat::IdentPat(ident)) = it.pat() {
324                             ident.name().map(NameOrNameRef::Name)
325                         } else {
326                             None
327                         };
328
329                         (ty, name)
330                     },
331                     ast::ArgList(_it) => {
332                         cov_mark::hit!(expected_type_fn_param_with_leading_char);
333                         cov_mark::hit!(expected_type_fn_param_without_leading_char);
334                         ActiveParameter::at_token(
335                             &self.sema,
336                             self.token.clone(),
337                         ).map(|ap| {
338                             let name = ap.ident().map(NameOrNameRef::Name);
339                             (Some(ap.ty), name)
340                         })
341                         .unwrap_or((None, None))
342                     },
343                     ast::RecordExprFieldList(_it) => {
344                         cov_mark::hit!(expected_type_struct_field_without_leading_char);
345                         // wouldn't try {} be nice...
346                         (|| {
347                             let expr_field = self.token.prev_sibling_or_token()?
348                                       .into_node()
349                                       .and_then(|node| ast::RecordExprField::cast(node))?;
350                             let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
351                             Some((
352                                 Some(ty),
353                                 expr_field.field_name().map(NameOrNameRef::NameRef),
354                             ))
355                         })().unwrap_or((None, None))
356                     },
357                     ast::RecordExprField(it) => {
358                         cov_mark::hit!(expected_type_struct_field_with_leading_char);
359                         (
360                             it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)),
361                             it.field_name().map(NameOrNameRef::NameRef),
362                         )
363                     },
364                     ast::MatchExpr(it) => {
365                         cov_mark::hit!(expected_type_match_arm_without_leading_char);
366                         let ty = it.expr()
367                             .and_then(|e| self.sema.type_of_expr(&e));
368                         (ty, None)
369                     },
370                     ast::IfExpr(it) => {
371                         cov_mark::hit!(expected_type_if_let_without_leading_char);
372                         let ty = it.condition()
373                             .and_then(|cond| cond.expr())
374                             .and_then(|e| self.sema.type_of_expr(&e));
375                         (ty, None)
376                     },
377                     ast::IdentPat(it) => {
378                         cov_mark::hit!(expected_type_if_let_with_leading_char);
379                         cov_mark::hit!(expected_type_match_arm_with_leading_char);
380                         let ty = self.sema.type_of_pat(&ast::Pat::from(it));
381                         (ty, None)
382                     },
383                     ast::Fn(it) => {
384                         cov_mark::hit!(expected_type_fn_ret_with_leading_char);
385                         cov_mark::hit!(expected_type_fn_ret_without_leading_char);
386                         let def = self.sema.to_def(&it);
387                         (def.map(|def| def.ret_type(self.db)), None)
388                     },
389                     ast::ClosureExpr(it) => {
390                         let ty = self.sema.type_of_expr(&it.into());
391                         ty.and_then(|ty| ty.as_callable(self.db))
392                             .map(|c| (Some(c.return_type()), None))
393                             .unwrap_or((None, None))
394                     },
395                     ast::Stmt(_it) => (None, None),
396                     _ => {
397                         match node.parent() {
398                             Some(n) => {
399                                 node = n;
400                                 continue;
401                             },
402                             None => (None, None),
403                         }
404                     },
405                 }
406             };
407         }
408     }
409
410     fn fill(
411         &mut self,
412         original_file: &SyntaxNode,
413         file_with_fake_ident: SyntaxNode,
414         offset: TextSize,
415     ) {
416         let (expected_type, expected_name) = self.expected_type_and_name();
417         self.expected_type = expected_type;
418         self.expected_name = expected_name;
419         self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset);
420
421         if let Some(lifetime) = find_node_at_offset::<ast::Lifetime>(&file_with_fake_ident, offset)
422         {
423             self.classify_lifetime(original_file, lifetime, offset);
424         }
425
426         // First, let's try to complete a reference to some declaration.
427         if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
428             // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
429             // See RFC#1685.
430             if is_node::<ast::Param>(name_ref.syntax()) {
431                 self.is_param = true;
432                 return;
433             }
434             // FIXME: remove this (V) duplication and make the check more precise
435             if name_ref.syntax().ancestors().find_map(ast::RecordPatFieldList::cast).is_some() {
436                 self.record_pat_syntax =
437                     self.sema.find_node_at_offset_with_macros(&original_file, offset);
438             }
439             self.classify_name_ref(original_file, name_ref, offset);
440         }
441
442         // Otherwise, see if this is a declaration. We can use heuristics to
443         // suggest declaration names, see `CompletionKind::Magic`.
444         if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
445             if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::IdentPat::cast) {
446                 self.is_pat_binding_or_const = true;
447                 if bind_pat.at_token().is_some()
448                     || bind_pat.ref_token().is_some()
449                     || bind_pat.mut_token().is_some()
450                 {
451                     self.is_pat_binding_or_const = false;
452                 }
453                 if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() {
454                     self.is_pat_binding_or_const = false;
455                 }
456                 if let Some(Some(pat)) = bind_pat.syntax().ancestors().find_map(|node| {
457                     match_ast! {
458                         match node {
459                             ast::LetStmt(it) => Some(it.pat()),
460                             ast::Param(it) => Some(it.pat()),
461                             _ => None,
462                         }
463                     }
464                 }) {
465                     if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) {
466                         self.is_pat_binding_or_const = false;
467                         self.is_irrefutable_pat_binding = true;
468                     }
469                 }
470
471                 self.fill_impl_def();
472             }
473             if is_node::<ast::Param>(name.syntax()) {
474                 self.is_param = true;
475                 return;
476             }
477             // FIXME: remove this (^) duplication and make the check more precise
478             if name.syntax().ancestors().find_map(ast::RecordPatFieldList::cast).is_some() {
479                 self.record_pat_syntax =
480                     self.sema.find_node_at_offset_with_macros(&original_file, offset);
481             }
482         }
483     }
484
485     fn classify_lifetime(
486         &mut self,
487         original_file: &SyntaxNode,
488         lifetime: ast::Lifetime,
489         offset: TextSize,
490     ) {
491         self.lifetime_syntax =
492             find_node_at_offset(original_file, lifetime.syntax().text_range().start());
493         if let Some(parent) = lifetime.syntax().parent() {
494             if parent.kind() == ERROR {
495                 return;
496             }
497
498             match_ast! {
499                 match parent {
500                     ast::LifetimeParam(_it) => {
501                         self.lifetime_allowed = true;
502                         self.lifetime_param_syntax =
503                             self.sema.find_node_at_offset_with_macros(original_file, offset);
504                     },
505                     ast::BreakExpr(_it) => self.is_label_ref = true,
506                     ast::ContinueExpr(_it) => self.is_label_ref = true,
507                     ast::Label(_it) => (),
508                     _ => self.lifetime_allowed = true,
509                 }
510             }
511         }
512     }
513
514     fn classify_name_ref(
515         &mut self,
516         original_file: &SyntaxNode,
517         name_ref: ast::NameRef,
518         offset: TextSize,
519     ) {
520         self.name_ref_syntax =
521             find_node_at_offset(original_file, name_ref.syntax().text_range().start());
522         let name_range = name_ref.syntax().text_range();
523         if ast::RecordExprField::for_field_name(&name_ref).is_some() {
524             self.record_lit_syntax =
525                 self.sema.find_node_at_offset_with_macros(original_file, offset);
526         }
527
528         self.fill_impl_def();
529
530         let top_node = name_ref
531             .syntax()
532             .ancestors()
533             .take_while(|it| it.text_range() == name_range)
534             .last()
535             .unwrap();
536
537         match top_node.parent().map(|it| it.kind()) {
538             Some(SOURCE_FILE) | Some(ITEM_LIST) => {
539                 self.is_new_item = true;
540                 return;
541             }
542             _ => (),
543         }
544
545         self.use_item_syntax =
546             self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
547
548         self.function_syntax = self
549             .sema
550             .token_ancestors_with_macros(self.token.clone())
551             .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
552             .find_map(ast::Fn::cast);
553
554         self.record_field_syntax = self
555             .sema
556             .token_ancestors_with_macros(self.token.clone())
557             .take_while(|it| {
558                 it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR
559             })
560             .find_map(ast::RecordExprField::cast);
561
562         let parent = match name_ref.syntax().parent() {
563             Some(it) => it,
564             None => return,
565         };
566
567         if let Some(segment) = ast::PathSegment::cast(parent.clone()) {
568             let path = segment.parent_path();
569             self.is_call = path
570                 .syntax()
571                 .parent()
572                 .and_then(ast::PathExpr::cast)
573                 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
574                 .is_some();
575             self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();
576             self.is_pattern_call =
577                 path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some();
578
579             self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
580             self.has_type_args = segment.generic_arg_list().is_some();
581
582             if let Some(path) = path_or_use_tree_qualifier(&path) {
583                 self.path_qual = path
584                     .segment()
585                     .and_then(|it| {
586                         find_node_with_range::<ast::PathSegment>(
587                             original_file,
588                             it.syntax().text_range(),
589                         )
590                     })
591                     .map(|it| it.parent_path());
592                 return;
593             }
594
595             if let Some(segment) = path.segment() {
596                 if segment.coloncolon_token().is_some() {
597                     return;
598                 }
599             }
600
601             self.is_trivial_path = true;
602
603             // Find either enclosing expr statement (thing with `;`) or a
604             // block. If block, check that we are the last expr.
605             self.can_be_stmt = name_ref
606                 .syntax()
607                 .ancestors()
608                 .find_map(|node| {
609                     if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
610                         return Some(stmt.syntax().text_range() == name_ref.syntax().text_range());
611                     }
612                     if let Some(block) = ast::BlockExpr::cast(node) {
613                         return Some(
614                             block.tail_expr().map(|e| e.syntax().text_range())
615                                 == Some(name_ref.syntax().text_range()),
616                         );
617                     }
618                     None
619                 })
620                 .unwrap_or(false);
621             self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
622
623             if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
624                 if let Some(if_expr) =
625                     self.sema.find_node_at_offset_with_macros::<ast::IfExpr>(original_file, off)
626                 {
627                     if if_expr.syntax().text_range().end() < name_ref.syntax().text_range().start()
628                     {
629                         self.after_if = true;
630                     }
631                 }
632             }
633         }
634         if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
635             // The receiver comes before the point of insertion of the fake
636             // ident, so it should have the same range in the non-modified file
637             self.dot_receiver = field_expr
638                 .expr()
639                 .map(|e| e.syntax().text_range())
640                 .and_then(|r| find_node_with_range(original_file, r));
641             self.dot_receiver_is_ambiguous_float_literal =
642                 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
643                     match l.kind() {
644                         ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
645                         _ => false,
646                     }
647                 } else {
648                     false
649                 };
650         }
651         if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
652             // As above
653             self.dot_receiver = method_call_expr
654                 .receiver()
655                 .map(|e| e.syntax().text_range())
656                 .and_then(|r| find_node_with_range(original_file, r));
657             self.is_call = true;
658         }
659     }
660 }
661
662 fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
663     syntax.covering_element(range).ancestors().find_map(N::cast)
664 }
665
666 fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
667     match node.ancestors().find_map(N::cast) {
668         None => false,
669         Some(n) => n.syntax().text_range() == node.text_range(),
670     }
671 }
672
673 fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> {
674     if let Some(qual) = path.qualifier() {
675         return Some(qual);
676     }
677     let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
678     let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
679     use_tree.path()
680 }
681
682 #[cfg(test)]
683 mod tests {
684     use expect_test::{expect, Expect};
685     use hir::HirDisplay;
686
687     use crate::test_utils::{position, TEST_CONFIG};
688
689     use super::CompletionContext;
690
691     fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) {
692         let (db, pos) = position(ra_fixture);
693         let completion_context = CompletionContext::new(&db, pos, &TEST_CONFIG).unwrap();
694
695         let ty = completion_context
696             .expected_type
697             .map(|t| t.display_test(&db).to_string())
698             .unwrap_or("?".to_owned());
699
700         let name = completion_context
701             .expected_name
702             .map_or_else(|| "?".to_owned(), |name| name.to_string());
703
704         expect.assert_eq(&format!("ty: {}, name: {}", ty, name));
705     }
706
707     #[test]
708     fn expected_type_let_without_leading_char() {
709         cov_mark::check!(expected_type_let_without_leading_char);
710         check_expected_type_and_name(
711             r#"
712 fn foo() {
713     let x: u32 = $0;
714 }
715 "#,
716             expect![[r#"ty: u32, name: x"#]],
717         );
718     }
719
720     #[test]
721     fn expected_type_let_with_leading_char() {
722         cov_mark::check!(expected_type_let_with_leading_char);
723         check_expected_type_and_name(
724             r#"
725 fn foo() {
726     let x: u32 = c$0;
727 }
728 "#,
729             expect![[r#"ty: u32, name: x"#]],
730         );
731     }
732
733     #[test]
734     fn expected_type_let_pat() {
735         check_expected_type_and_name(
736             r#"
737 fn foo() {
738     let x$0 = 0u32;
739 }
740 "#,
741             expect![[r#"ty: u32, name: ?"#]],
742         );
743         check_expected_type_and_name(
744             r#"
745 fn foo() {
746     let $0 = 0u32;
747 }
748 "#,
749             expect![[r#"ty: u32, name: ?"#]],
750         );
751     }
752
753     #[test]
754     fn expected_type_fn_param_without_leading_char() {
755         cov_mark::check!(expected_type_fn_param_without_leading_char);
756         check_expected_type_and_name(
757             r#"
758 fn foo() {
759     bar($0);
760 }
761
762 fn bar(x: u32) {}
763 "#,
764             expect![[r#"ty: u32, name: x"#]],
765         );
766     }
767
768     #[test]
769     fn expected_type_fn_param_with_leading_char() {
770         cov_mark::check!(expected_type_fn_param_with_leading_char);
771         check_expected_type_and_name(
772             r#"
773 fn foo() {
774     bar(c$0);
775 }
776
777 fn bar(x: u32) {}
778 "#,
779             expect![[r#"ty: u32, name: x"#]],
780         );
781     }
782
783     #[test]
784     fn expected_type_struct_field_without_leading_char() {
785         cov_mark::check!(expected_type_struct_field_without_leading_char);
786         check_expected_type_and_name(
787             r#"
788 struct Foo { a: u32 }
789 fn foo() {
790     Foo { a: $0 };
791 }
792 "#,
793             expect![[r#"ty: u32, name: a"#]],
794         )
795     }
796
797     #[test]
798     fn expected_type_generic_struct_field() {
799         check_expected_type_and_name(
800             r#"
801 struct Foo<T> { a: T }
802 fn foo() -> Foo<u32> {
803     Foo { a: $0 }
804 }
805 "#,
806             expect![[r#"ty: u32, name: a"#]],
807         )
808     }
809
810     #[test]
811     fn expected_type_struct_field_with_leading_char() {
812         cov_mark::check!(expected_type_struct_field_with_leading_char);
813         check_expected_type_and_name(
814             r#"
815 struct Foo { a: u32 }
816 fn foo() {
817     Foo { a: c$0 };
818 }
819 "#,
820             expect![[r#"ty: u32, name: a"#]],
821         );
822     }
823
824     #[test]
825     fn expected_type_match_arm_without_leading_char() {
826         cov_mark::check!(expected_type_match_arm_without_leading_char);
827         check_expected_type_and_name(
828             r#"
829 enum E { X }
830 fn foo() {
831    match E::X { $0 }
832 }
833 "#,
834             expect![[r#"ty: E, name: ?"#]],
835         );
836     }
837
838     #[test]
839     fn expected_type_match_arm_with_leading_char() {
840         cov_mark::check!(expected_type_match_arm_with_leading_char);
841         check_expected_type_and_name(
842             r#"
843 enum E { X }
844 fn foo() {
845    match E::X { c$0 }
846 }
847 "#,
848             expect![[r#"ty: E, name: ?"#]],
849         );
850     }
851
852     #[test]
853     fn expected_type_if_let_without_leading_char() {
854         cov_mark::check!(expected_type_if_let_without_leading_char);
855         check_expected_type_and_name(
856             r#"
857 enum Foo { Bar, Baz, Quux }
858
859 fn foo() {
860     let f = Foo::Quux;
861     if let $0 = f { }
862 }
863 "#,
864             expect![[r#"ty: Foo, name: ?"#]],
865         )
866     }
867
868     #[test]
869     fn expected_type_if_let_with_leading_char() {
870         cov_mark::check!(expected_type_if_let_with_leading_char);
871         check_expected_type_and_name(
872             r#"
873 enum Foo { Bar, Baz, Quux }
874
875 fn foo() {
876     let f = Foo::Quux;
877     if let c$0 = f { }
878 }
879 "#,
880             expect![[r#"ty: Foo, name: ?"#]],
881         )
882     }
883
884     #[test]
885     fn expected_type_fn_ret_without_leading_char() {
886         cov_mark::check!(expected_type_fn_ret_without_leading_char);
887         check_expected_type_and_name(
888             r#"
889 fn foo() -> u32 {
890     $0
891 }
892 "#,
893             expect![[r#"ty: u32, name: ?"#]],
894         )
895     }
896
897     #[test]
898     fn expected_type_fn_ret_with_leading_char() {
899         cov_mark::check!(expected_type_fn_ret_with_leading_char);
900         check_expected_type_and_name(
901             r#"
902 fn foo() -> u32 {
903     c$0
904 }
905 "#,
906             expect![[r#"ty: u32, name: ?"#]],
907         )
908     }
909
910     #[test]
911     fn expected_type_fn_ret_fn_ref_fully_typed() {
912         check_expected_type_and_name(
913             r#"
914 fn foo() -> u32 {
915     foo$0
916 }
917 "#,
918             expect![[r#"ty: u32, name: ?"#]],
919         )
920     }
921
922     #[test]
923     fn expected_type_closure_param_return() {
924         // FIXME: make this work with `|| $0`
925         check_expected_type_and_name(
926             r#"
927 fn foo() {
928     bar(|| a$0);
929 }
930
931 fn bar(f: impl FnOnce() -> u32) {}
932 #[lang = "fn_once"]
933 trait FnOnce { type Output; }
934 "#,
935             expect![[r#"ty: u32, name: ?"#]],
936         );
937     }
938
939     #[test]
940     fn expected_type_generic_function() {
941         check_expected_type_and_name(
942             r#"
943 fn foo() {
944     bar::<u32>($0);
945 }
946
947 fn bar<T>(t: T) {}
948 "#,
949             expect![[r#"ty: u32, name: t"#]],
950         );
951     }
952
953     #[test]
954     fn expected_type_generic_method() {
955         check_expected_type_and_name(
956             r#"
957 fn foo() {
958     S(1u32).bar($0);
959 }
960
961 struct S<T>(T);
962 impl<T> S<T> {
963     fn bar(self, t: T) {}
964 }
965 "#,
966             expect![[r#"ty: u32, name: t"#]],
967         );
968     }
969 }