diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -1071,6 +1071,9 @@ 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 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -232,6 +232,19 @@ 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 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -112,8 +112,8 @@ 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 @@ 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 --- /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