- 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.
//===---------------------------------------------------------------------===//
"%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<
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
- bool IsArrow, SourceLocation OpLoc,
+ bool &IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclPtrTy ObjCImpDecl);
/// 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) {
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>()) {