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