From: Manman Ren Date: Tue, 28 Jun 2016 23:01:49 +0000 (+0000) Subject: ObjC Class Property: diagnostics when accessing a class property using instance. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=982542debc28b9714c6c93c6417d0e1ea1a032ad;p=clang ObjC Class Property: diagnostics when accessing a class property using instance. When a class property is accessed with an object instance, before this commit, we try to apply a typo correction of the same property: property 'c' not found on object of type 'A *'; did you mean 'c'? With this commit, we correctly emit a diagnostics: property 'c' is a class property; did you mean to access it with class 'A'? rdar://26866973 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@274076 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index dcb4d70bc7..245921324c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -7761,6 +7761,8 @@ def err_typecheck_member_reference_ivar_suggest : Error< "%0 does not have a member named %1; did you mean %2?">; def err_property_not_found_suggest : Error< "property %0 not found on object of type %1; did you mean %2?">; +def err_class_property_found : Error< + "property %0 is a class property; did you mean to access it with class '%1'?">; def err_ivar_access_using_property_syntax_suggest : Error< "property %0 not found on object of type %1; did you mean to access instance variable %2?">; def warn_property_access_suggest : Warning< diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 598ae2098a..8f0d4ff695 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1817,7 +1817,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - // May be founf in property's qualified list. + // May be found in property's qualified list. if (!Getter) Getter = LookupMethodInQualifiedType(Sel, OPT, true); @@ -1837,7 +1837,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - // May be founf in property's qualified list. + // May be found in property's qualified list. if (!Setter) Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); @@ -1885,12 +1885,29 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, LookupOrdinaryName, nullptr, nullptr, llvm::make_unique>(), CTK_ErrorRecovery, IFace, false, OPT)) { - diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) - << MemberName << QualType(OPT, 0)); DeclarationName TypoResult = Corrected.getCorrection(); - return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, - TypoResult, MemberLoc, - SuperLoc, SuperType, Super); + if (TypoResult.isIdentifier() && + TypoResult.getAsIdentifierInfo() == Member) { + // There is no need to try the correction if it is the same. + NamedDecl *ChosenDecl = + Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl(); + if (ChosenDecl && isa(ChosenDecl)) + if (cast(ChosenDecl)->isClassProperty()) { + // This is a class property, we should not use the instance to + // access it. + Diag(MemberLoc, diag::err_class_property_found) << MemberName + << OPT->getInterfaceDecl()->getName() + << FixItHint::CreateReplacement(BaseExpr->getSourceRange(), + OPT->getInterfaceDecl()->getName()); + return ExprError(); + } + } else { + diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) + << MemberName << QualType(OPT, 0)); + return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, + TypoResult, MemberLoc, + SuperLoc, SuperType, Super); + } } ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m index f41f75f1d7..3e9ff60523 100644 --- a/test/FixIt/fixit-objc.m +++ b/test/FixIt/fixit-objc.m @@ -67,3 +67,11 @@ void sentinel_test(Sentinel *a) { sentinel(1, 2, 3); // expected-warning{{missing sentinel in function call}} [a sentinel:1, 2, 3]; // expected-warning{{missing sentinel in method dispatch}} } + +@interface A +@property (class) int c; +@end + +int test(A *a) { + return a.c; // expected-error {{property 'c' is a class property; did you mean to access it with class 'A'}} +} diff --git a/test/SemaObjC/objc-class-property.m b/test/SemaObjC/objc-class-property.m index f6733574c0..56285976e1 100644 --- a/test/SemaObjC/objc-class-property.m +++ b/test/SemaObjC/objc-class-property.m @@ -33,6 +33,7 @@ int test() { A *a = [[A alloc] init]; + a.c; // expected-error {{property 'c' is a class property; did you mean to access it with class 'A'}} return a.x + A.c; }