Author: alexdenisov Date: Wed Aug 5 23:51:14 2015 New Revision: 244193 URL: http://llvm.org/viewvc/llvm-project?rev=244193&view=rev Log: [ObjC] Circular containers: add support of subclasses
Modified: cfe/trunk/include/clang/AST/NSAPI.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/NSAPI.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/SemaObjC/circular-container.m Modified: cfe/trunk/include/clang/AST/NSAPI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NSAPI.h?rev=244193&r1=244192&r2=244193&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/NSAPI.h (original) +++ cfe/trunk/include/clang/AST/NSAPI.h Wed Aug 5 23:51:14 2015 @@ -16,6 +16,7 @@ namespace clang { class ASTContext; + class ObjCInterfaceDecl; class QualType; class Expr; @@ -35,11 +36,10 @@ public: ClassId_NSMutableDictionary, ClassId_NSNumber, ClassId_NSMutableSet, - ClassId_NSCountedSet, ClassId_NSMutableOrderedSet, ClassId_NSValue }; - static const unsigned NumClassIds = 11; + static const unsigned NumClassIds = 10; enum NSStringMethodKind { NSStr_stringWithString, @@ -220,6 +220,10 @@ public: /// \brief Returns \c true if \p Id is currently defined as a macro. bool isMacroDefined(StringRef Id) const; + /// \brief Returns \c true if \p InterfaceDecl is subclass of \p NSClassKind + bool isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl, + NSClassIdKindKind NSClassKind) const; + private: bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const; bool isObjCEnumerator(const Expr *E, Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=244193&r1=244192&r2=244193&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Aug 5 23:51:14 2015 @@ -5370,7 +5370,7 @@ def err_objc_object_catch : Error< def err_incomplete_type_objc_at_encode : Error< "'@encode' of incomplete type %0">; def warn_objc_circular_container : Warning< - "adding '%0' to '%0' might cause circular dependency in container">, + "adding '%0' to '%1' might cause circular dependency in container">, InGroup<DiagGroup<"objc-circular-container">>; def note_objc_circular_container_declared_here : Note<"'%0' declared here">; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=244193&r1=244192&r2=244193&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Wed Aug 5 23:51:14 2015 @@ -729,27 +729,12 @@ public: /// \brief The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; - /// \brief Pointer to NSMutableArray type (NSMutableArray *). - QualType NSMutableArrayPointer; - /// \brief The declaration of the arrayWithObjects:count: method. ObjCMethodDecl *ArrayWithObjectsMethod; /// \brief The declaration of the Objective-C NSDictionary class. ObjCInterfaceDecl *NSDictionaryDecl; - /// \brief Pointer to NSMutableDictionary type (NSMutableDictionary *). - QualType NSMutableDictionaryPointer; - - /// \brief Pointer to NSMutableSet type (NSMutableSet *). - QualType NSMutableSetPointer; - - /// \brief Pointer to NSCountedSet type (NSCountedSet *). - QualType NSCountedSetPointer; - - /// \brief Pointer to NSMutableOrderedSet type (NSMutableOrderedSet *). - QualType NSMutableOrderedSetPointer; - /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method. ObjCMethodDecl *DictionaryWithObjectsMethod; Modified: cfe/trunk/lib/AST/NSAPI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?rev=244193&r1=244192&r2=244193&view=diff ============================================================================== --- cfe/trunk/lib/AST/NSAPI.cpp (original) +++ cfe/trunk/lib/AST/NSAPI.cpp Wed Aug 5 23:51:14 2015 @@ -9,6 +9,7 @@ #include "clang/AST/NSAPI.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "llvm/ADT/StringSwitch.h" @@ -29,7 +30,6 @@ IdentifierInfo *NSAPI::getNSClassId(NSCl "NSMutableDictionary", "NSNumber", "NSMutableSet", - "NSCountedSet", "NSMutableOrderedSet", "NSValue" }; @@ -511,6 +511,26 @@ bool NSAPI::isMacroDefined(StringRef Id) return Ctx.Idents.get(Id).hasMacroDefinition(); } +bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl, + NSClassIdKindKind NSClassKind) const { + if (!InterfaceDecl) { + return false; + } + + IdentifierInfo *NSClassID = getNSClassId(NSClassKind); + + bool IsSubclass = false; + do { + IsSubclass = NSClassID == InterfaceDecl->getIdentifier(); + + if (IsSubclass) { + break; + } + } while ((InterfaceDecl = InterfaceDecl->getSuperClass())); + + return IsSubclass; +} + bool NSAPI::isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const { if (!Ctx.getLangOpts().ObjC1) Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=244193&r1=244192&r2=244193&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Aug 5 23:51:14 2015 @@ -8727,23 +8727,10 @@ static bool isSetterLikeSelector(Selecto static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S, ObjCMessageExpr *Message) { - if (S.NSMutableArrayPointer.isNull()) { - IdentifierInfo *NSMutableArrayId = - S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableArray); - NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableArrayId, - Message->getLocStart(), - Sema::LookupOrdinaryName); - ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - if (!InterfaceDecl) { - return None; - } - QualType NSMutableArrayObject = - S.Context.getObjCInterfaceType(InterfaceDecl); - S.NSMutableArrayPointer = - S.Context.getObjCObjectPointerType(NSMutableArrayObject); - } - - if (S.NSMutableArrayPointer != Message->getReceiverType()) { + bool IsMutableArray = S.NSAPIObj->isSubclassOfNSClass( + Message->getReceiverInterface(), + NSAPI::ClassId_NSMutableArray); + if (!IsMutableArray) { return None; } @@ -8775,24 +8762,10 @@ static Optional<int> GetNSMutableArrayAr static Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S, ObjCMessageExpr *Message) { - - if (S.NSMutableDictionaryPointer.isNull()) { - IdentifierInfo *NSMutableDictionaryId = - S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableDictionary); - NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableDictionaryId, - Message->getLocStart(), - Sema::LookupOrdinaryName); - ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - if (!InterfaceDecl) { - return None; - } - QualType NSMutableDictionaryObject = - S.Context.getObjCInterfaceType(InterfaceDecl); - S.NSMutableDictionaryPointer = - S.Context.getObjCObjectPointerType(NSMutableDictionaryObject); - } - - if (S.NSMutableDictionaryPointer != Message->getReceiverType()) { + bool IsMutableDictionary = S.NSAPIObj->isSubclassOfNSClass( + Message->getReceiverInterface(), + NSAPI::ClassId_NSMutableDictionary); + if (!IsMutableDictionary) { return None; } @@ -8820,63 +8793,14 @@ Optional<int> GetNSMutableDictionaryArgu } static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) { - - ObjCInterfaceDecl *InterfaceDecl; - if (S.NSMutableSetPointer.isNull()) { - IdentifierInfo *NSMutableSetId = - S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableSet); - NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableSetId, - Message->getLocStart(), - Sema::LookupOrdinaryName); - InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - if (InterfaceDecl) { - QualType NSMutableSetObject = - S.Context.getObjCInterfaceType(InterfaceDecl); - S.NSMutableSetPointer = - S.Context.getObjCObjectPointerType(NSMutableSetObject); - } - } - - if (S.NSCountedSetPointer.isNull()) { - IdentifierInfo *NSCountedSetId = - S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSCountedSet); - NamedDecl *IF = S.LookupSingleName(S.TUScope, NSCountedSetId, - Message->getLocStart(), - Sema::LookupOrdinaryName); - InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - if (InterfaceDecl) { - QualType NSCountedSetObject = - S.Context.getObjCInterfaceType(InterfaceDecl); - S.NSCountedSetPointer = - S.Context.getObjCObjectPointerType(NSCountedSetObject); - } - } - - if (S.NSMutableOrderedSetPointer.isNull()) { - IdentifierInfo *NSOrderedSetId = - S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableOrderedSet); - NamedDecl *IF = S.LookupSingleName(S.TUScope, NSOrderedSetId, - Message->getLocStart(), - Sema::LookupOrdinaryName); - InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - if (InterfaceDecl) { - QualType NSOrderedSetObject = - S.Context.getObjCInterfaceType(InterfaceDecl); - S.NSMutableOrderedSetPointer = - S.Context.getObjCObjectPointerType(NSOrderedSetObject); - } - } - - QualType ReceiverType = Message->getReceiverType(); - - bool IsMutableSet = !S.NSMutableSetPointer.isNull() && - ReceiverType == S.NSMutableSetPointer; - bool IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() && - ReceiverType == S.NSMutableOrderedSetPointer; - bool IsCountedSet = !S.NSCountedSetPointer.isNull() && - ReceiverType == S.NSCountedSetPointer; - - if (!IsMutableSet && !IsMutableOrderedSet && !IsCountedSet) { + bool IsMutableSet = S.NSAPIObj->isSubclassOfNSClass( + Message->getReceiverInterface(), + NSAPI::ClassId_NSMutableSet); + + bool IsMutableOrderedSet = S.NSAPIObj->isSubclassOfNSClass( + Message->getReceiverInterface(), + NSAPI::ClassId_NSMutableOrderedSet); + if (!IsMutableSet && !IsMutableOrderedSet) { return None; } @@ -8917,38 +8841,51 @@ void Sema::CheckObjCCircularContainer(Ob int ArgIndex = *ArgOpt; - Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts(); - if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) { - Receiver = OE->getSourceExpr()->IgnoreImpCasts(); - } - Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts(); if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Arg)) { Arg = OE->getSourceExpr()->IgnoreImpCasts(); } - if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) { + if (Message->getReceiverKind() == ObjCMessageExpr::SuperInstance) { if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) { - if (ReceiverRE->getDecl() == ArgRE->getDecl()) { - ValueDecl *Decl = ReceiverRE->getDecl(); + if (ArgRE->isObjCSelfExpr()) { Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName(); - Diag(Decl->getLocation(), - diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << ArgRE->getDecl()->getName() << StringRef("super"); } } - } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) { - if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) { - if (IvarRE->getDecl() == IvarArgRE->getDecl()) { - ObjCIvarDecl *Decl = IvarRE->getDecl(); - Diag(Message->getSourceRange().getBegin(), - diag::warn_objc_circular_container) - << Decl->getName(); - Diag(Decl->getLocation(), - diag::note_objc_circular_container_declared_here) - << Decl->getName(); + } else { + Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts(); + + if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) { + Receiver = OE->getSourceExpr()->IgnoreImpCasts(); + } + + if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) { + if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) { + if (ReceiverRE->getDecl() == ArgRE->getDecl()) { + ValueDecl *Decl = ReceiverRE->getDecl(); + Diag(Message->getSourceRange().getBegin(), + diag::warn_objc_circular_container) + << Decl->getName() << Decl->getName(); + if (!ArgRE->isObjCSelfExpr()) { + Diag(Decl->getLocation(), + diag::note_objc_circular_container_declared_here) + << Decl->getName(); + } + } + } + } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) { + if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) { + if (IvarRE->getDecl() == IvarArgRE->getDecl()) { + ObjCIvarDecl *Decl = IvarRE->getDecl(); + Diag(Message->getSourceRange().getBegin(), + diag::warn_objc_circular_container) + << Decl->getName() << Decl->getName(); + Diag(Decl->getLocation(), + diag::note_objc_circular_container_declared_here) + << Decl->getName(); + } } } } Modified: cfe/trunk/test/SemaObjC/circular-container.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/circular-container.m?rev=244193&r1=244192&r2=244193&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/circular-container.m (original) +++ cfe/trunk/test/SemaObjC/circular-container.m Wed Aug 5 23:51:14 2015 @@ -144,3 +144,64 @@ void checkNSMutableOrderedSet() { [s replaceObjectAtIndex:0 withObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}} } +// Test subclassing + +@interface FootableSet : NSMutableSet +@end + +@implementation FootableSet +- (void)meth { + [super addObject:self]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}} + [super addObject:nil]; // no-warning + [self addObject:self]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}} +} +@end + +@interface FootableArray : NSMutableArray +@end + +@implementation FootableArray +- (void)meth { + [super addObject:self]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}} + [super addObject:nil]; // no-warning + [self addObject:self]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}} +} +@end + +@interface FootableDictionary : NSMutableDictionary +@end + +@implementation FootableDictionary +- (void)meth { + [super setObject:self forKey:@"key"]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}} + [super setObject:nil forKey:@"key"]; // no-warning + [self setObject:self forKey:@"key"]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}} +} +@end + + +void subclassingNSMutableArray() { + FootableArray *a = nil; // expected-note 5 {{'a' declared here}} 5 + + [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}} + [a insertObject:a atIndex:0]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}} + [a replaceObjectAtIndex:0 withObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}} + [a setObject:a atIndexedSubscript:0]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}} + a[0] = a; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}} +} + +void subclassingNSMutableDictionary() { + FootableDictionary *d = nil; // expected-note 4 {{'d' declared here}} + + [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}} + [d setObject:d forKeyedSubscript:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}} + [d setValue:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}} + d[@"key"] = d; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}} +} + +void subclassingNSMutableSet() { + FootableSet *s = nil; // expected-note {{'s' declared here}} + + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}} +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits