]> granicus.if.org Git - clang/commitdiff
Recover from dot accesses to record pointers and arrow accesses to records.
authorJohn McCall <rjmccall@apple.com>
Mon, 7 Dec 2009 22:46:59 +0000 (22:46 +0000)
committerJohn McCall <rjmccall@apple.com>
Mon, 7 Dec 2009 22:46:59 +0000 (22:46 +0000)
Patch by Nicola Gigante!

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

TODO.txt
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp

index 7ceb0da15b36546dcbb6aed6f0dc6d8c709603b1..067f07b9d323c779aea6126fa944a88e81e1093a 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -65,7 +65,6 @@ More ideas for code modification hints:
   - If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1).
   - If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration.
   - Fix-it hints for the inclusion of headers when needed for particular features (e.g., <typeinfo> for typeid)
-  - Change "foo.bar" to "foo->bar" when "foo" is a pointer.
 
 //===---------------------------------------------------------------------===//
 
index d20da85ab30f07b043d3a58f50779075af8788ff..57e1d33717922efc533037fe3d4e42cd7831812c 100644 (file)
@@ -1520,6 +1520,8 @@ def err_typecheck_member_reference_ivar : Error<
   "%0 does not have a member named %1">;
 def err_typecheck_member_reference_arrow : Error<
   "member reference type %0 is not a pointer">;
+def err_typecheck_member_reference_suggestion : Error<
+  "member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">;
 def err_typecheck_member_reference_type : Error<
   "cannot refer to type member %0 with '%select{.|->}1'">;
 def err_typecheck_member_reference_unknown : Error<
index 4295655528c20703b0c367dd6a0eee557eceba76..fbf1c414104b578c9494ae6289efe24b0b645619 100644 (file)
@@ -1550,7 +1550,7 @@ public:
                                  const TemplateArgumentListInfo *TemplateArgs);
 
   OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
-                                    bool IsArrow, SourceLocation OpLoc,
+                                    bool &IsArrow, SourceLocation OpLoc,
                                     const CXXScopeSpec &SS,
                                     NamedDecl *FirstQualifierInScope,
                                     DeclPtrTy ObjCImpDecl);
index 8332bf8f7b13860f9155e92384cc9e9ed4e1b561..a63ce1e598d0c3d28cca62e8ab79068fa1cc775c 100644 (file)
@@ -2473,7 +2473,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
 /// fixed for ObjC++.
 Sema::OwningExprResult
 Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
-                       bool IsArrow, SourceLocation OpLoc,
+                       bool &IsArrow, SourceLocation OpLoc,
                        const CXXScopeSpec &SS,
                        NamedDecl *FirstQualifierInScope,
                        DeclPtrTy ObjCImpDecl) {
@@ -2614,13 +2614,42 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
       BaseType = PT->getPointeeType();
     else if (BaseType->isObjCObjectPointerType())
       ;
-    else {
+    else if (BaseType->isRecordType()) {
+      // Recover from arrow accesses to records, e.g.:
+      //   struct MyRecord foo;
+      //   foo->bar
+      // This is actually well-formed in C++ if MyRecord has an
+      // overloaded operator->, but that should have been dealt with
+      // by now.
+      Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+        << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+        << CodeModificationHint::CreateReplacement(OpLoc, ".");
+      IsArrow = false;
+    } else {
       Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
         << BaseType << BaseExpr->getSourceRange();
       return ExprError();
     }
+  } else {
+    // Recover from dot accesses to pointers, e.g.:
+    //   type *foo;
+    //   foo.bar
+    // This is actually well-formed in two cases:
+    //   - 'type' is an Objective C type
+    //   - 'bar' is a pseudo-destructor name which happens to refer to
+    //     the appropriate pointer type
+    if (MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+      const PointerType *PT = BaseType->getAs<PointerType>();
+      if (PT && PT->getPointeeType()->isRecordType()) {
+        Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+          << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+          << CodeModificationHint::CreateReplacement(OpLoc, "->");
+        BaseType = PT->getPointeeType();
+        IsArrow = true;
+      }
+    }
   }
-
+  
   // Handle field access to simple records.  This also handles access
   // to fields of the ObjC 'id' struct.
   if (const RecordType *RTy = BaseType->getAs<RecordType>()) {