]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_completion/src/patterns.rs
Add MethodCall and FieldAccess variants to ImmediateLocation
[rust.git] / crates / ide_completion / src / patterns.rs
index 26516046bcf32ee8aa583f796ad5faf079409d0c..bf3a3f61ebbb8578ea5807270667d6eadb5c19cc 100644 (file)
@@ -7,7 +7,7 @@
     ast::{self, LoopBodyOwner},
     match_ast, AstNode, Direction, SyntaxElement,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextSize, T,
+    SyntaxNode, SyntaxToken, TextRange, TextSize, T,
 };
 
 #[cfg(test)]
@@ -37,6 +37,15 @@ pub(crate) enum ImmediateLocation {
     // Fake file ast node
     ModDeclaration(ast::Module),
     // Original file ast node
+    MethodCall {
+        receiver: Option<ast::Expr>,
+    },
+    // Original file ast node
+    FieldAccess {
+        receiver: Option<ast::Expr>,
+        receiver_is_ambiguous_float_literal: bool,
+    },
+    // Original file ast node
     /// The record expr of the field name we are completing
     RecordExpr(ast::RecordExpr),
     // Original file ast node
@@ -164,12 +173,38 @@ pub(crate) fn determine_location(
                 Some(TRAIT) => ImmediateLocation::Trait,
                 _ => return None,
             },
-            ast::Module(it) => if it.item_list().is_none() {
+            ast::Module(it) => {
+                if it.item_list().is_none() {
                     ImmediateLocation::ModDeclaration(it)
                 } else {
-                    return None
+                    return None;
+                }
             },
             ast::Attr(it) => ImmediateLocation::Attribute(it),
+            ast::FieldExpr(it) => {
+                let receiver = it
+                    .expr()
+                    .map(|e| e.syntax().text_range())
+                    .and_then(|r| find_node_with_range(original_file, r));
+                let receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = &receiver {
+                    match l.kind() {
+                        ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
+                        _ => false,
+                    }
+                } else {
+                    false
+                };
+                ImmediateLocation::FieldAccess {
+                    receiver,
+                    receiver_is_ambiguous_float_literal,
+                }
+            },
+            ast::MethodCallExpr(it) => ImmediateLocation::MethodCall {
+                receiver: it
+                    .receiver()
+                    .map(|e| e.syntax().text_range())
+                    .and_then(|r| find_node_with_range(original_file, r)),
+            },
             _ => return None,
         }
     };
@@ -194,6 +229,10 @@ fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode {
     name_ref.syntax().clone()
 }
 
+fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
+    syntax.covering_element(range).ancestors().find_map(N::cast)
+}
+
 pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool {
     // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`,
     // where we only check the first parent with different text range.