Rollup merge of #59297 - euclio:field-method-suggestions, r=estebank

convert field/method confusion help to suggestions
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index b4a1a2d..f933e61 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -332,44 +332,61 @@
                 // If the method name is the name of a field with a function or closure type,
                 // give a helping note that it has to be called as `(x.f)(...)`.
                 if let SelfSource::MethodCall(expr) = source {
-                    for (ty, _) in self.autoderef(span, rcvr_ty) {
-                        if let ty::Adt(def, substs) = ty.sty {
-                            if !def.is_enum() {
+                    let field_receiver = self
+                        .autoderef(span, rcvr_ty)
+                        .find_map(|(ty, _)| match ty.sty {
+                            ty::Adt(def, substs) if !def.is_enum() => {
                                 let variant = &def.non_enum_variant();
-                                if let Some(index) = self.tcx.find_field_index(item_name, variant) {
+                                self.tcx.find_field_index(item_name, variant).map(|index| {
                                     let field = &variant.fields[index];
-                                    let snippet = tcx.sess.source_map().span_to_snippet(expr.span);
-                                    let expr_string = match snippet {
-                                        Ok(expr_string) => expr_string,
-                                        _ => "s".into(), // Default to a generic placeholder for the
-                                                         // expression when we can't generate a
-                                                         // string snippet.
-                                    };
-
                                     let field_ty = field.ty(tcx, substs);
-                                    let scope = self.tcx.hir().get_module_parent_by_hir_id(
-                                        self.body_id);
-                                    if field.vis.is_accessible_from(scope, self.tcx) {
-                                        if self.is_fn_ty(&field_ty, span) {
-                                            err.help(&format!("use `({0}.{1})(...)` if you \
-                                                               meant to call the function \
-                                                               stored in the `{1}` field",
-                                                              expr_string,
-                                                              item_name));
-                                        } else {
-                                            err.help(&format!("did you mean to write `{0}.{1}` \
-                                                               instead of `{0}.{1}(...)`?",
-                                                              expr_string,
-                                                              item_name));
-                                        }
-                                        err.span_label(span, "field, not a method");
-                                    } else {
-                                        err.span_label(span, "private field, not a method");
-                                    }
-                                    break;
-                                }
+                                    (field, field_ty)
+                                })
+                            }
+                            _ => None,
+                        });
+
+                    if let Some((field, field_ty)) = field_receiver {
+                        let scope = self.tcx.hir().get_module_parent_by_hir_id(self.body_id);
+                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+
+                        if is_accessible {
+                            if self.is_fn_ty(&field_ty, span) {
+                                let expr_span = expr.span.to(item_name.span);
+                                err.multipart_suggestion(
+                                    &format!(
+                                        "to call the function stored in `{}`, \
+                                         surround the field access with parentheses",
+                                        item_name,
+                                    ),
+                                    vec![
+                                        (expr_span.shrink_to_lo(), '('.to_string()),
+                                        (expr_span.shrink_to_hi(), ')'.to_string()),
+                                    ],
+                                    Applicability::MachineApplicable,
+                                );
+                            } else {
+                                let call_expr = self.tcx.hir().expect_expr_by_hir_id(
+                                    self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id),
+                                );
+
+                                let span = call_expr.span.trim_start(item_name.span).unwrap();
+
+                                err.span_suggestion(
+                                    span,
+                                    "remove the arguments",
+                                    String::new(),
+                                    Applicability::MaybeIncorrect,
+                                );
                             }
                         }
+
+                        let field_kind = if is_accessible {
+                            "field"
+                        } else {
+                            "private field"
+                        };
+                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
                     }
                 } else {
                     err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr
index 36112cd..03f9d99 100644
--- a/src/test/ui/confuse-field-and-method/issue-18343.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr
@@ -6,8 +6,10 @@
 ...
 LL |     o.closure();
    |       ^^^^^^^ field, not a method
+help: to call the function stored in `closure`, surround the field access with parentheses
    |
-   = help: use `(o.closure)(...)` if you meant to call the function stored in the `closure` field
+LL |     (o.closure)();
+   |     ^         ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr
index 456a4c1..2107318 100644
--- a/src/test/ui/confuse-field-and-method/issue-2392.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr
@@ -6,8 +6,10 @@
 ...
 LL |     o_closure.closure();
    |               ^^^^^^^ field, not a method
+help: to call the function stored in `closure`, surround the field access with parentheses
    |
-   = help: use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field
+LL |     (o_closure.closure)();
+   |     ^                 ^
 
 error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:39:36: 39:41]>` in the current scope
   --> $DIR/issue-2392.rs:42:15
@@ -16,9 +18,9 @@
    | -------------------------------------- method `not_closure` not found for this
 ...
 LL |     o_closure.not_closure();
-   |               ^^^^^^^^^^^ field, not a method
-   |
-   = help: did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`?
+   |               ^^^^^^^^^^^-- help: remove the arguments
+   |               |
+   |               field, not a method
 
 error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
   --> $DIR/issue-2392.rs:46:12
@@ -28,8 +30,10 @@
 ...
 LL |     o_func.closure();
    |            ^^^^^^^ field, not a method
+help: to call the function stored in `closure`, surround the field access with parentheses
    |
-   = help: use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field
+LL |     (o_func.closure)();
+   |     ^              ^
 
 error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
   --> $DIR/issue-2392.rs:49:14
@@ -39,8 +43,10 @@
 ...
 LL |     boxed_fn.boxed_closure();
    |              ^^^^^^^^^^^^^ field, not a method
+help: to call the function stored in `boxed_closure`, surround the field access with parentheses
    |
-   = help: use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field
+LL |     (boxed_fn.boxed_closure)();
+   |     ^                      ^
 
 error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
   --> $DIR/issue-2392.rs:52:19
@@ -50,8 +56,10 @@
 ...
 LL |     boxed_closure.boxed_closure();
    |                   ^^^^^^^^^^^^^ field, not a method
+help: to call the function stored in `boxed_closure`, surround the field access with parentheses
    |
-   = help: use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field
+LL |     (boxed_closure.boxed_closure)();
+   |     ^                           ^
 
 error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
   --> $DIR/issue-2392.rs:57:12
@@ -61,8 +69,10 @@
 ...
 LL |     w.wrap.closure();
    |            ^^^^^^^ field, not a method
+help: to call the function stored in `closure`, surround the field access with parentheses
    |
-   = help: use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field
+LL |     (w.wrap.closure)();
+   |     ^              ^
 
 error[E0599]: no method named `not_closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
   --> $DIR/issue-2392.rs:59:12
@@ -71,9 +81,9 @@
    | -------------------------------------- method `not_closure` not found for this
 ...
 LL |     w.wrap.not_closure();
-   |            ^^^^^^^^^^^ field, not a method
-   |
-   = help: did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`?
+   |            ^^^^^^^^^^^-- help: remove the arguments
+   |            |
+   |            field, not a method
 
 error[E0599]: no method named `closure` found for type `Obj<std::boxed::Box<(dyn std::boxed::FnBox<(), Output = u32> + 'static)>>` in the current scope
   --> $DIR/issue-2392.rs:62:24
@@ -83,8 +93,10 @@
 ...
 LL |     check_expression().closure();
    |                        ^^^^^^^ field, not a method
+help: to call the function stored in `closure`, surround the field access with parentheses
    |
-   = help: use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field
+LL |     (check_expression().closure)();
+   |     ^                          ^
 
 error[E0599]: no method named `f1` found for type `FuncContainer` in the current scope
   --> $DIR/issue-2392.rs:68:31
@@ -94,8 +106,10 @@
 ...
 LL |             (*self.container).f1(1);
    |                               ^^ field, not a method
+help: to call the function stored in `f1`, surround the field access with parentheses
    |
-   = help: use `((*self.container).f1)(...)` if you meant to call the function stored in the `f1` field
+LL |             ((*self.container).f1)(1);
+   |             ^                    ^
 
 error[E0599]: no method named `f2` found for type `FuncContainer` in the current scope
   --> $DIR/issue-2392.rs:69:31
@@ -105,8 +119,10 @@
 ...
 LL |             (*self.container).f2(1);
    |                               ^^ field, not a method
+help: to call the function stored in `f2`, surround the field access with parentheses
    |
-   = help: use `((*self.container).f2)(...)` if you meant to call the function stored in the `f2` field
+LL |             ((*self.container).f2)(1);
+   |             ^                    ^
 
 error[E0599]: no method named `f3` found for type `FuncContainer` in the current scope
   --> $DIR/issue-2392.rs:70:31
@@ -116,8 +132,10 @@
 ...
 LL |             (*self.container).f3(1);
    |                               ^^ field, not a method
+help: to call the function stored in `f3`, surround the field access with parentheses
    |
-   = help: use `((*self.container).f3)(...)` if you meant to call the function stored in the `f3` field
+LL |             ((*self.container).f3)(1);
+   |             ^                    ^
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/confuse-field-and-method/issue-32128.stderr b/src/test/ui/confuse-field-and-method/issue-32128.stderr
index 902f606..fbabb3a 100644
--- a/src/test/ui/confuse-field-and-method/issue-32128.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-32128.stderr
@@ -6,8 +6,10 @@
 ...
 LL |     demo.example(1);
    |          ^^^^^^^ field, not a method
+help: to call the function stored in `example`, surround the field access with parentheses
    |
-   = help: use `(demo.example)(...)` if you meant to call the function stored in the `example` field
+LL |     (demo.example)(1);
+   |     ^            ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/confuse-field-and-method/issue-33784.stderr b/src/test/ui/confuse-field-and-method/issue-33784.stderr
index cce961f..60f1a93 100644
--- a/src/test/ui/confuse-field-and-method/issue-33784.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-33784.stderr
@@ -3,24 +3,30 @@
    |
 LL |     p.closure();
    |       ^^^^^^^ field, not a method
+help: to call the function stored in `closure`, surround the field access with parentheses
    |
-   = help: use `(p.closure)(...)` if you meant to call the function stored in the `closure` field
+LL |     (p.closure)();
+   |     ^         ^
 
 error[E0599]: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
   --> $DIR/issue-33784.rs:29:7
    |
 LL |     q.fn_ptr();
    |       ^^^^^^ field, not a method
+help: to call the function stored in `fn_ptr`, surround the field access with parentheses
    |
-   = help: use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field
+LL |     (q.fn_ptr)();
+   |     ^        ^
 
 error[E0599]: no method named `c_fn_ptr` found for type `&D` in the current scope
   --> $DIR/issue-33784.rs:32:7
    |
 LL |     s.c_fn_ptr();
    |       ^^^^^^^^ field, not a method
+help: to call the function stored in `c_fn_ptr`, surround the field access with parentheses
    |
-   = help: use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` field
+LL |     (s.c_fn_ptr)();
+   |     ^          ^
 
 error: aborting due to 3 previous errors