]> granicus.if.org Git - clang/commitdiff
Rework the fix-it hint for code like
authorDouglas Gregor <dgregor@apple.com>
Fri, 6 Nov 2009 06:30:47 +0000 (06:30 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 6 Nov 2009 06:30:47 +0000 (06:30 +0000)
  get_origin->x

where get_origin is actually a function and the user has forgotten the
parentheses. Instead of giving a lame note for the fix-it, give a
full-fledge error, early, then build the call expression to try to
recover.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86238 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/FixIt/fixit-errors.c
test/SemaCXX/member-expr.cpp

index 729395a32a3b4271026340b2b82a2ea6f7f78141..a3cce6c163b0c65464b079fc3cafc87d4a23cfe7 100644 (file)
@@ -1447,8 +1447,9 @@ def err_typecheck_member_reference_type : Error<
   "cannot refer to type member %0 with '%select{.|->}1'">;
 def err_typecheck_member_reference_unknown : Error<
   "cannot refer to member %0 with '%select{.|->}1'">;
-def note_member_reference_needs_call : Note<
-  "perhaps you meant to call this function with '()'?">;
+def err_member_reference_needs_call : Error<
+  "base of member reference has function type %0; perhaps you meant to call "
+  "this function with '()'?">;
 def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
   InGroup<CharSubscript>, DefaultIgnore;
 
index f5bae072ef0ed2b435cd0565a96cab44ef9802ff..031bbe77aca631d20757aeee0bd74eca074f1348 100644 (file)
@@ -1882,6 +1882,38 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
   DefaultFunctionArrayConversion(BaseExpr);
 
   QualType BaseType = BaseExpr->getType();
+
+  // If the user is trying to apply -> or . to a function pointer
+  // type, it's probably because the forgot parentheses to call that
+  // function. Suggest the addition of those parentheses, build the
+  // call, and continue on.
+  if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+    if (const FunctionProtoType *Fun
+          = Ptr->getPointeeType()->getAs<FunctionProtoType>()) {
+      QualType ResultTy = Fun->getResultType();
+      if (Fun->getNumArgs() == 0 &&
+          ((OpKind == tok::period && ResultTy->isRecordType()) ||
+           (OpKind == tok::arrow && ResultTy->isPointerType() &&
+            ResultTy->getAs<PointerType>()->getPointeeType()
+                                                          ->isRecordType()))) {
+        SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
+        Diag(Loc, diag::err_member_reference_needs_call)
+          << QualType(Fun, 0)
+          << CodeModificationHint::CreateInsertion(Loc, "()");
+        
+        OwningExprResult NewBase
+          = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc, 
+                          MultiExprArg(*this, 0, 0), 0, Loc);
+        if (NewBase.isInvalid())
+          return move(NewBase);
+        
+        BaseExpr = NewBase.takeAs<Expr>();
+        DefaultFunctionArrayConversion(BaseExpr);
+        BaseType = BaseExpr->getType();
+      }
+    }
+  }
+
   // If this is an Objective-C pseudo-builtin and a definition is provided then
   // use that.
   if (BaseType->isObjCIdType()) {
@@ -2437,18 +2469,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
   Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
     << BaseType << BaseExpr->getSourceRange();
 
-  // If the user is trying to apply -> or . to a function or function
-  // pointer, it's probably because they forgot parentheses to call
-  // the function. Suggest the addition of those parentheses.
-  if (BaseType == Context.OverloadTy ||
-      BaseType->isFunctionType() ||
-      (BaseType->isPointerType() &&
-       BaseType->getAs<PointerType>()->isFunctionType())) {
-    SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
-    Diag(Loc, diag::note_member_reference_needs_call)
-      << CodeModificationHint::CreateInsertion(Loc, "()");
-  }
-
   return ExprError();
 }
 
index 9c5258dbcb743e6bb1bd6a6833a8b2dd52bf8451..996e940f2c85af17e2fc754aa17e4c068a57af9d 100644 (file)
@@ -8,3 +8,13 @@
 struct s; // expected-note{{previous use is here}}
 
 union s *s1; // expected-error{{use of 's' with tag type that does not match previous declaration}}
+
+struct Point {
+  float x, y, z;
+};
+
+struct Point *get_origin();
+
+void test_point() {
+  (void)get_origin->x;
+}
index 069f52605b92e9a376df277d9c963bb6966bb464..cd13bcc3670ea016b2153fdf1864b948a234e2ed 100644 (file)
@@ -28,8 +28,7 @@ struct B {
  A *f0();
 };
 int f0(B *b) {
-  return b->f0->f0; // expected-error{{member reference base type 'struct A *()' is not a structure or union}} \
-  // expected-note{{perhaps you meant to call this function}}
+  return b->f0->f0; // expected-error{{perhaps you meant to call this function}}
 }
 
 int i;