about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-04 19:35:03 +0000
committerbors <bors@rust-lang.org>2023-03-04 19:35:03 +0000
commite6ba791dcecfb2d69e831e204f06f2d3bf86323a (patch)
treea1079dd73900d944470d2b5ea6421e0456f01a16
parent94dc7a3eb092b5ea641a4d344fae5f3ad4158853 (diff)
parent5a91f015b489627d3c9578ec2b01735687c8880a (diff)
downloadrust-e6ba791dcecfb2d69e831e204f06f2d3bf86323a.tar.gz
rust-e6ba791dcecfb2d69e831e204f06f2d3bf86323a.zip
Auto merge of #14252 - Veykril:field-mcall-fallback, r=Veykril
internal: Handle fields called as method calls as the fields they resolve to

Confusing PR title tbf but this makes it so `bar` in `foo.bar()` resolves to the field if it exists and no method with the same name exists. Improves UX slightly when incorrectly calling a field.
-rw-r--r--crates/hir/src/semantics.rs19
-rw-r--r--crates/hir/src/source_analyzer.rs16
-rw-r--r--crates/ide-db/src/defs.rs9
-rw-r--r--crates/ide/src/hover/tests.rs23
4 files changed, 63 insertions, 4 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index be2dffc29cc..697f4b43bc7 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -12,7 +12,7 @@ use hir_def::{
     macro_id_to_def_id,
     resolver::{self, HasResolver, Resolver, TypeNs},
     type_ref::Mutability,
-    AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
+    AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
 };
 use hir_expand::{
     db::AstDatabase,
@@ -366,6 +366,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_method_call(call).map(Function::from)
     }
 
+    /// Attempts to resolve this call expression as a method call falling back to resolving it as a field.
+    pub fn resolve_method_call_field_fallback(
+        &self,
+        call: &ast::MethodCallExpr,
+    ) -> Option<Either<Function, Field>> {
+        self.imp
+            .resolve_method_call_fallback(call)
+            .map(|it| it.map_left(Function::from).map_right(Field::from))
+    }
+
     pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
         self.imp.resolve_await_to_poll(await_expr).map(Function::from)
     }
@@ -1146,6 +1156,13 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(call.syntax())?.resolve_method_call(self.db, call)
     }
 
+    fn resolve_method_call_fallback(
+        &self,
+        call: &ast::MethodCallExpr,
+    ) -> Option<Either<FunctionId, FieldId>> {
+        self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
+    }
+
     fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
         self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
     }
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index ada529fa74c..118a7f8ea86 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -10,6 +10,7 @@ use std::{
     sync::Arc,
 };
 
+use either::Either;
 use hir_def::{
     body::{
         self,
@@ -266,6 +267,21 @@ impl SourceAnalyzer {
         Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
     }
 
+    pub(crate) fn resolve_method_call_fallback(
+        &self,
+        db: &dyn HirDatabase,
+        call: &ast::MethodCallExpr,
+    ) -> Option<Either<FunctionId, FieldId>> {
+        let expr_id = self.expr_id(db, &call.clone().into())?;
+        let inference_result = self.infer.as_ref()?;
+        match inference_result.method_resolution(expr_id) {
+            Some((f_in_trait, substs)) => {
+                Some(Either::Left(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)))
+            }
+            None => inference_result.field_resolution(expr_id).map(Either::Right),
+        }
+    }
+
     pub(crate) fn resolve_await_to_poll(
         &self,
         db: &dyn HirDatabase,
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index cce33dcfe46..1322f5228e8 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -469,9 +469,12 @@ impl NameRefClass {
         match_ast! {
             match parent {
                 ast::MethodCallExpr(method_call) => {
-                    sema.resolve_method_call(&method_call)
-                        .map(Definition::Function)
-                        .map(NameRefClass::Definition)
+                    sema.resolve_method_call_field_fallback(&method_call)
+                        .map(|it| {
+                            it.map_left(Definition::Function)
+                                .map_right(Definition::Field)
+                                .either(NameRefClass::Definition, NameRefClass::Definition)
+                        })
                 },
                 ast::FieldExpr(field_expr) => {
                     sema.resolve_field(&field_expr)
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 42f7c4339c7..2e67056b913 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -5797,3 +5797,26 @@ mod m {
         "#]],
     );
 }
+
+#[test]
+fn field_as_method_call_fallback() {
+    check(
+        r#"
+struct S { f: u32 }
+fn test() {
+    S { f: 0 }.f$0();
+}
+"#,
+        expect![[r#"
+            *f*
+
+            ```rust
+            test::S
+            ```
+
+            ```rust
+            f: u32 // size = 4, align = 4, offset = 0
+            ```
+        "#]],
+    );
+}