From fda47db8ee1d3eca8c42819cf1b65ab0ef7df7b8 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Wed, 29 Dec 2021 22:02:21 +0000 Subject: [Clang][Sema] Fix attribute mismatch warning for ObjC class properties If a class declares an instance property, and an inheritor class declares a class property with the same name, Clang Sema currently treats the latter as an overridden property, and compares the attributes of the two properties to check for a mismatch. The resulting diagnostics might be misleading, since neither of the properties actually overrides the another one. rdar://86018435 Differential Revision: https://reviews.llvm.org/D116412 --- clang/include/clang/AST/DeclObjC.h | 3 ++ clang/lib/AST/DeclObjC.cpp | 12 ++++++++ clang/lib/Sema/SemaObjCProperty.cpp | 8 ++--- clang/test/SemaObjC/class-property-inheritance.m | 39 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 clang/test/SemaObjC/class-property-inheritance.m diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index f227561b8fcb..110b7dc0c6f2 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -1071,6 +1071,9 @@ public: bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const; ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; + ObjCPropertyDecl *getProperty(const IdentifierInfo *Id, + bool IsInstance) const; + ObjCPropertyDecl * FindPropertyDeclaration(const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const; diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index ba827a79c022..f15dd78929e2 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -232,6 +232,18 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const { return &Ctx.Idents.get(ivarName.str()); } +ObjCPropertyDecl *ObjCContainerDecl::getProperty(const IdentifierInfo *Id, + bool IsInstance) const { + for (auto *LookupResult : lookup(Id)) { + if (auto *Prop = dyn_cast(LookupResult)) { + if (Prop->isInstanceProperty() == IsInstance) { + return Prop; + } + } + } + return nullptr; +} + /// FindPropertyDeclaration - Finds declaration of the property given its name /// in 'PropertyId' and returns it. It returns 0, if not found. ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 74c73ace3c5f..118afb81dd72 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -112,8 +112,8 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, return; // Look for a property with the same name. - if (ObjCPropertyDecl *ProtoProp = - Proto->lookup(Prop->getDeclName()).find_first()) { + if (ObjCPropertyDecl *ProtoProp = Proto->getProperty( + Prop->getIdentifier(), Prop->isInstanceProperty())) { S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true); return; } @@ -231,8 +231,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, bool FoundInSuper = false; ObjCInterfaceDecl *CurrentInterfaceDecl = IFace; while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) { - if (ObjCPropertyDecl *SuperProp = - Super->lookup(Res->getDeclName()).find_first()) { + if (ObjCPropertyDecl *SuperProp = Super->getProperty( + Res->getIdentifier(), Res->isInstanceProperty())) { DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false); FoundInSuper = true; break; diff --git a/clang/test/SemaObjC/class-property-inheritance.m b/clang/test/SemaObjC/class-property-inheritance.m new file mode 100644 index 000000000000..9d8a4fe44053 --- /dev/null +++ b/clang/test/SemaObjC/class-property-inheritance.m @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@class MyObject; + + +@interface TopClassWithClassProperty0 +@property(nullable, readonly, strong, class) MyObject *foo; +@end + +@interface SubClassWithClassProperty0 : TopClassWithClassProperty0 +@property(nonnull, readonly, copy, class) MyObject *foo; // expected-warning {{'copy' attribute on property 'foo' does not match the property inherited from 'TopClassWithClassProperty0'}} +@end + + + +@interface TopClassWithInstanceProperty1 +@property(nullable, readonly, strong) MyObject *foo; +@end + +@interface ClassWithClassProperty1 : TopClassWithInstanceProperty1 +@property(nonnull, readonly, copy, class) MyObject *foo; // no-warning +@end + +@interface SubClassWithInstanceProperty1 : ClassWithClassProperty1 +@property(nullable, readonly, copy) MyObject *foo; // expected-warning {{'copy' attribute on property 'foo' does not match the property inherited from 'TopClassWithInstanceProperty1'}} +@end + + +@interface TopClassWithClassProperty2 +@property(nullable, readonly, strong, class) MyObject *foo; +@end + +@interface ClassWithInstanceProperty2 : TopClassWithClassProperty2 +@property(nonnull, readonly, copy) MyObject *foo; // no-warning +@end + +@interface SubClassWithClassProperty2 : ClassWithInstanceProperty2 +@property(nonnull, readonly, copy, class) MyObject *foo; // expected-warning {{'copy' attribute on property 'foo' does not match the property inherited from 'TopClassWithClassProperty2'}} +@end -- cgit v1.2.1