From 58f11d6245ce8bd5cc8a0f01dee9726cf6d1cbd7 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 3 May 2010 15:49:20 +0000 Subject: [PATCH] Do not issue warning on unimplemented property in the class, if it conforms to a protocol as one of its super classes does. This is because conforming super class will implement the property. This implements new warning rules for unimplemented properties (radar 7884086). llvm-svn: 102919 --- clang/lib/Sema/Sema.h | 9 ++++ clang/lib/Sema/SemaObjCProperty.cpp | 32 ++++++++++++- clang/test/SemaObjC/default-synthesize.m | 4 +- .../super-class-protocol-conformance.m | 47 +++++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 clang/test/SemaObjC/super-class-protocol-conformance.m diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 6c52ae5ceeae..ba20ed1e1a7f 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1539,6 +1539,15 @@ public: /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, llvm::DenseMap& PropMap); + + /// ProtocolConformsToSuperClass - Returns true if class has a super class + /// and it, or its nested super class conforms to the protocol. + bool ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, + const ObjCProtocolDecl *PDecl); + /// ProtocolConformsToProtocol - Returns true if 2nd Protocol (PDecl) is + /// qualified by the 1st. + bool ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol, + const ObjCProtocolDecl *PDecl); /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 13c75e4fe960..b73739fc5551 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -719,7 +719,10 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, // scan through class's protocols. for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), E = IDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); + // Exclude property for protocols which conform to class's super-class, + // as super-class has to implement the property. + if (!ProtocolConformsToSuperClass(IDecl, (*PI))) + CollectImmediateProperties((*PI), PropMap); } if (ObjCCategoryDecl *CATDecl = dyn_cast(CDecl)) { if (!CATDecl->IsClassExtension()) @@ -748,6 +751,33 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } +/// ProtocolConformsToSuperClass - Returns true if class's given protocol +/// conforms to one of its super class's protocols. +bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, + const ObjCProtocolDecl *PDecl) { + if (const ObjCInterfaceDecl *CDecl = IDecl->getSuperClass()) { + for (ObjCInterfaceDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) { + if (ProtocolConformsToProtocol((*PI), PDecl)) + return true; + return ProtocolConformsToSuperClass(CDecl, PDecl); + } + } + return false; +} + +bool Sema::ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol, + const ObjCProtocolDecl *PDecl) { + if (PDecl->getIdentifier() == NestedProtocol->getIdentifier()) + return true; + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + if (ProtocolConformsToProtocol(NestedProtocol, (*PI))) + return true; + return false; +} + /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, diff --git a/clang/test/SemaObjC/default-synthesize.m b/clang/test/SemaObjC/default-synthesize.m index 21453d384145..283ad260a94e 100644 --- a/clang/test/SemaObjC/default-synthesize.m +++ b/clang/test/SemaObjC/default-synthesize.m @@ -85,14 +85,14 @@ @interface TopClass { - id myString; // expected-note {{previously declared 'myString' here}} + id myString; } @end @interface SubClass : TopClass @end -@implementation SubClass @end // expected-error {{property 'myString' attempting to use ivar 'myString' declared in super class 'TopClass'}} +@implementation SubClass @end // rdar: // 7920807 @interface C @end diff --git a/clang/test/SemaObjC/super-class-protocol-conformance.m b/clang/test/SemaObjC/super-class-protocol-conformance.m new file mode 100644 index 000000000000..ac8bc70a9989 --- /dev/null +++ b/clang/test/SemaObjC/super-class-protocol-conformance.m @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar: // 7884086 + +@interface NSObject @end + +@protocol TopProtocol + @property (readonly) id myString; // expected-warning {{property 'myString' requires method 'myString' to be defined}} +@end + +@protocol SubProtocol +@end + +@interface TopClass : NSObject {} +@end + +@interface SubClass : TopClass {} +@end + +@interface SubClass1 : TopClass {} +@end + +@implementation SubClass1 @end // Test1 - No Warning + +@implementation TopClass // expected-note {{implementation is here}} +@end + +@implementation SubClass // Test3 - No Warning +@end + +@interface SubClass2 : TopClass +@end + +@implementation SubClass2 @end // Test 4 - No Warning + +@interface SubClass3 : TopClass @end +@implementation SubClass3 @end // Test 5 - No Warning + +@interface SubClass4 : SubClass3 @end +@implementation SubClass4 @end // Test 5 - No Warning + +@protocol NewProtocol + @property (readonly) id myNewString; // expected-warning {{property 'myNewString' requires method 'myNewString' to be defined}} +@end + +@interface SubClass5 : SubClass4 @end +@implementation SubClass5 @end // expected-note {{implementation is here}} +