summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEgor Zhdan <e_zhdan@apple.com>2021-12-29 22:02:21 +0000
committerEgor Zhdan <e_zhdan@apple.com>2022-01-11 12:10:18 +0000
commitfda47db8ee1d3eca8c42819cf1b65ab0ef7df7b8 (patch)
tree65f25940b61062acbac9c7607a18387d41a6e9c7
parentacc39873b70eae53a0c32ca5073f08ea55bbab1c (diff)
downloadllvm-fda47db8ee1d3eca8c42819cf1b65ab0ef7df7b8.tar.gz
[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
-rw-r--r--clang/include/clang/AST/DeclObjC.h3
-rw-r--r--clang/lib/AST/DeclObjC.cpp12
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp8
-rw-r--r--clang/test/SemaObjC/class-property-inheritance.m39
4 files changed, 58 insertions, 4 deletions
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<ObjCPropertyDecl>(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<ObjCPropertyDecl>()) {
+ 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<ObjCPropertyDecl>()) {
+ 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