From: John McCall Date: Mon, 7 Dec 2009 22:46:59 +0000 (+0000) Subject: Recover from dot accesses to record pointers and arrow accesses to records. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=812c15476c9dddb72a8fd48deb7ca86402664b94;p=clang Recover from dot accesses to record pointers and arrow accesses to records. Patch by Nicola Gigante! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90814 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/TODO.txt b/TODO.txt index 7ceb0da15b..067f07b9d3 100644 --- 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., for typeid) - - Change "foo.bar" to "foo->bar" when "foo" is a pointer. //===---------------------------------------------------------------------===// diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d20da85ab3..57e1d33717 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4295655528..fbf1c41410 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8332bf8f7b..a63ce1e598 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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(); + 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()) {