Neat! > On Mar 4, 2015, at 9:55 AM, Alex Denisov <[email protected]> wrote: > > Author: alexdenisov > Date: Wed Mar 4 11:55:52 2015 > New Revision: 231265 > > URL: http://llvm.org/viewvc/llvm-project?rev=231265&view=rev > Log: > New ObjC warning: circular containers. > > This commit adds new warning to prevent user from creating 'circular > containers'. > > Mutable collections from NSFoundation allows user to add collection to > itself, e.g.: > > NSMutableArray *a = [NSMutableArray new]; > [a addObject:a]; > > The code above leads to really weird behaviour (crashes, 'endless' recursion) > and > retain cycles (collection retains itself) if ARC enabled. > > Patch checks the following collections: > - NSMutableArray, > - NSMutableDictionary, > - NSMutableSet, > - NSMutableOrderedSet, > - NSCountedSet. > > > Added: > cfe/trunk/test/SemaObjC/circular-container.m > 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/lib/Sema/SemaExprObjC.cpp > > Modified: cfe/trunk/include/clang/AST/NSAPI.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NSAPI.h?rev=231265&r1=231264&r2=231265&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/NSAPI.h (original) > +++ cfe/trunk/include/clang/AST/NSAPI.h Wed Mar 4 11:55:52 2015 > @@ -33,9 +33,12 @@ public: > ClassId_NSMutableArray, > ClassId_NSDictionary, > ClassId_NSMutableDictionary, > - ClassId_NSNumber > + ClassId_NSNumber, > + ClassId_NSMutableSet, > + ClassId_NSCountedSet, > + ClassId_NSMutableOrderedSet, > }; > - static const unsigned NumClassIds = 7; > + static const unsigned NumClassIds = 10; > > enum NSStringMethodKind { > NSStr_stringWithString, > @@ -67,7 +70,8 @@ public: > return isObjCEnumerator(E, > "NSASCIIStringEncoding",NSASCIIStringEncodingId); > } > > - /// \brief Enumerates the NSArray methods used to generate literals. > + /// \brief Enumerates the NSArray/NSMutableArray methods used to generate > + /// literals and to apply some checks. > enum NSArrayMethodKind { > NSArr_array, > NSArr_arrayWithArray, > @@ -77,9 +81,12 @@ public: > NSArr_initWithArray, > NSArr_initWithObjects, > NSArr_objectAtIndex, > - NSMutableArr_replaceObjectAtIndex > + NSMutableArr_replaceObjectAtIndex, > + NSMutableArr_addObject, > + NSMutableArr_insertObjectAtIndex, > + NSMutableArr_setObjectAtIndexedSubscript > }; > - static const unsigned NumNSArrayMethods = 9; > + static const unsigned NumNSArrayMethods = 12; > > /// \brief The Objective-C NSArray selectors. > Selector getNSArraySelector(NSArrayMethodKind MK) const; > @@ -87,7 +94,8 @@ public: > /// \brief Return NSArrayMethodKind if \p Sel is such a selector. > Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel); > > - /// \brief Enumerates the NSDictionary methods used to generate literals. > + /// \brief Enumerates the NSDictionary/NSMutableDictionary methods used > + /// to generate literals and to apply some checks. > enum NSDictionaryMethodKind { > NSDict_dictionary, > NSDict_dictionaryWithDictionary, > @@ -99,9 +107,11 @@ public: > NSDict_initWithObjectsAndKeys, > NSDict_initWithObjectsForKeys, > NSDict_objectForKey, > - NSMutableDict_setObjectForKey > + NSMutableDict_setObjectForKey, > + NSMutableDict_setObjectForKeyedSubscript, > + NSMutableDict_setValueForKey > }; > - static const unsigned NumNSDictionaryMethods = 12; > + static const unsigned NumNSDictionaryMethods = 14; > > /// \brief The Objective-C NSDictionary selectors. > Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const; > @@ -109,6 +119,23 @@ public: > /// \brief Return NSDictionaryMethodKind if \p Sel is such a selector. > Optional<NSDictionaryMethodKind> getNSDictionaryMethodKind(Selector Sel); > > + /// \brief Enumerates the NSMutableSet/NSOrderedSet methods used > + /// to apply some checks. > + enum NSSetMethodKind { > + NSMutableSet_addObject, > + NSOrderedSet_insertObjectAtIndex, > + NSOrderedSet_setObjectAtIndex, > + NSOrderedSet_setObjectAtIndexedSubscript, > + NSOrderedSet_replaceObjectAtIndexWithObject > + }; > + static const unsigned NumNSSetMethods = 5; > + > + /// \brief The Objective-C NSSet selectors. > + Selector getNSSetSelector(NSSetMethodKind MK) const; > + > + /// \brief Return NSSetMethodKind if \p Sel is such a selector. > + Optional<NSSetMethodKind> getNSSetMethodKind(Selector Sel); > + > /// \brief Returns selector for "objectForKeyedSubscript:". > Selector getObjectForKeyedSubscriptSelector() const { > return getOrInitSelector(StringRef("objectForKeyedSubscript"), > @@ -207,6 +234,9 @@ private: > /// \brief The selectors for Objective-C NSDictionary methods. > mutable Selector NSDictionarySelectors[NumNSDictionaryMethods]; > > + /// \brief The selectors for Objective-C NSSet methods. > + mutable Selector NSSetSelectors[NumNSSetMethods]; > + > /// \brief The Objective-C NSNumber selectors used to create NSNumber > literals. > mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods]; > mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods]; > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=231265&r1=231264&r2=231265&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Mar 4 11:55:52 > 2015 > @@ -5263,6 +5263,10 @@ def err_objc_object_catch : Error< > "can't catch an Objective-C object by value">; > 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">, > + InGroup<DiagGroup<"objc-circular-container">>; > +def note_objc_circular_container_declared_here : Note<"'%0' declared here">; > > def warn_setter_getter_impl_required : Warning< > "property %0 requires method %1 to be defined - " > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=231265&r1=231264&r2=231265&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar 4 11:55:52 2015 > @@ -683,12 +683,27 @@ 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; > > @@ -8645,6 +8660,10 @@ private: > /// statement that produces control flow different from GCC. > void CheckBreakContinueBinding(Expr *E); > > + /// \brief Check whether receiver is mutable ObjC container which > + /// attempts to add itself into the container > + void CheckObjCCircularContainer(ObjCMessageExpr *Message); > + > public: > /// \brief Register a magic integral constant to be used as a type tag. > void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, > > Modified: cfe/trunk/lib/AST/NSAPI.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?rev=231265&r1=231264&r2=231265&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/NSAPI.cpp (original) > +++ cfe/trunk/lib/AST/NSAPI.cpp Wed Mar 4 11:55:52 2015 > @@ -27,7 +27,10 @@ IdentifierInfo *NSAPI::getNSClassId(NSCl > "NSMutableArray", > "NSDictionary", > "NSMutableDictionary", > - "NSNumber" > + "NSNumber", > + "NSMutableSet", > + "NSCountedSet", > + "NSMutableOrderedSet" > }; > > if (!ClassIds[K]) > @@ -124,6 +127,25 @@ Selector NSAPI::getNSArraySelector(NSArr > Sel = Ctx.Selectors.getSelector(2, KeyIdents); > break; > } > + case NSMutableArr_addObject: > + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); > + break; > + case NSMutableArr_insertObjectAtIndex: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("insertObject"), > + &Ctx.Idents.get("atIndex") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > + case NSMutableArr_setObjectAtIndexedSubscript: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("setObject"), > + &Ctx.Idents.get("atIndexedSubscript") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > } > return (NSArraySelectors[MK] = Sel); > } > @@ -209,6 +231,22 @@ Selector NSAPI::getNSDictionarySelector( > Sel = Ctx.Selectors.getSelector(2, KeyIdents); > break; > } > + case NSMutableDict_setObjectForKeyedSubscript: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("setObject"), > + &Ctx.Idents.get("forKeyedSubscript") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > + case NSMutableDict_setValueForKey: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("setValue"), > + &Ctx.Idents.get("forKey") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > } > return (NSDictionarySelectors[MK] = Sel); > } > @@ -224,6 +262,63 @@ NSAPI::getNSDictionaryMethodKind(Selecto > return MK; > } > > + return None; > +} > + > +Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const { > + if (NSSetSelectors[MK].isNull()) { > + Selector Sel; > + switch (MK) { > + case NSMutableSet_addObject: > + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); > + break; > + case NSOrderedSet_insertObjectAtIndex: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("insertObject"), > + &Ctx.Idents.get("atIndex") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > + case NSOrderedSet_setObjectAtIndex: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("setObject"), > + &Ctx.Idents.get("atIndex") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > + case NSOrderedSet_setObjectAtIndexedSubscript: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("setObject"), > + &Ctx.Idents.get("atIndexedSubscript") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > + case NSOrderedSet_replaceObjectAtIndexWithObject: { > + IdentifierInfo *KeyIdents[] = { > + &Ctx.Idents.get("replaceObjectAtIndex"), > + &Ctx.Idents.get("withObject") > + }; > + Sel = Ctx.Selectors.getSelector(2, KeyIdents); > + break; > + } > + } > + return (NSSetSelectors[MK] = Sel); > + } > + > + return NSSetSelectors[MK]; > +} > + > +Optional<NSAPI::NSSetMethodKind> > +NSAPI::getNSSetMethodKind(Selector Sel) { > + for (unsigned i = 0; i != NumNSSetMethods; ++i) { > + NSSetMethodKind MK = NSSetMethodKind(i); > + if (Sel == getNSSetSelector(MK)) > + return MK; > + } > + > return None; > } > > > Modified: cfe/trunk/lib/Sema/SemaChecking.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=231265&r1=231264&r2=231265&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) > +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Mar 4 11:55:52 2015 > @@ -8187,6 +8187,236 @@ static bool isSetterLikeSelector(Selecto > return !isLowercase(str.front()); > } > > +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()) { > + return None; > + } > + > + Selector Sel = Message->getSelector(); > + > + Optional<NSAPI::NSArrayMethodKind> MKOpt = > + S.NSAPIObj->getNSArrayMethodKind(Sel); > + if (!MKOpt) { > + return None; > + } > + > + NSAPI::NSArrayMethodKind MK = *MKOpt; > + > + switch (MK) { > + case NSAPI::NSMutableArr_addObject: > + case NSAPI::NSMutableArr_insertObjectAtIndex: > + case NSAPI::NSMutableArr_setObjectAtIndexedSubscript: > + return 0; > + case NSAPI::NSMutableArr_replaceObjectAtIndex: > + return 1; > + > + default: > + return None; > + } > + > + return None; > +} > + > +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()) { > + return None; > + } > + > + Selector Sel = Message->getSelector(); > + > + Optional<NSAPI::NSDictionaryMethodKind> MKOpt = > + S.NSAPIObj->getNSDictionaryMethodKind(Sel); > + if (!MKOpt) { > + return None; > + } > + > + NSAPI::NSDictionaryMethodKind MK = *MKOpt; > + > + switch (MK) { > + case NSAPI::NSMutableDict_setObjectForKey: > + case NSAPI::NSMutableDict_setValueForKey: > + case NSAPI::NSMutableDict_setObjectForKeyedSubscript: > + return 0; > + > + default: > + return None; > + } > + > + return None; > +} > + > +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) { > + return None; > + } > + > + Selector Sel = Message->getSelector(); > + > + Optional<NSAPI::NSSetMethodKind> MKOpt = > S.NSAPIObj->getNSSetMethodKind(Sel); > + if (!MKOpt) { > + return None; > + } > + > + NSAPI::NSSetMethodKind MK = *MKOpt; > + > + switch (MK) { > + case NSAPI::NSMutableSet_addObject: > + case NSAPI::NSOrderedSet_setObjectAtIndex: > + case NSAPI::NSOrderedSet_setObjectAtIndexedSubscript: > + case NSAPI::NSOrderedSet_insertObjectAtIndex: > + return 0; > + case NSAPI::NSOrderedSet_replaceObjectAtIndexWithObject: > + return 1; > + } > + > + return None; > +} > + > +void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { > + if (!Message->isInstanceMessage()) { > + return; > + } > + > + Optional<int> ArgOpt; > + > + if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) && > + !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) && > + !(ArgOpt = GetNSSetArgumentIndex(*this, Message))) { > + return; > + } > + > + 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 (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(); > + 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(); > + Diag(Decl->getLocation(), > + diag::note_objc_circular_container_declared_here) > + << Decl->getName(); > + } > + } > + } > + > +} > + > /// Check a message send to see if it's likely to cause a retain cycle. > void Sema::checkRetainCycles(ObjCMessageExpr *msg) { > // Only check instance methods whose selector looks like a setter. > > Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=231265&r1=231264&r2=231265&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Wed Mar 4 11:55:52 2015 > @@ -2799,7 +2799,9 @@ ExprResult Sema::BuildInstanceMessage(Ex > } > } > } > - > + > + CheckObjCCircularContainer(Result); > + > return MaybeBindToTemporary(Result); > } > > > Added: cfe/trunk/test/SemaObjC/circular-container.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/circular-container.m?rev=231265&view=auto > ============================================================================== > --- cfe/trunk/test/SemaObjC/circular-container.m (added) > +++ cfe/trunk/test/SemaObjC/circular-container.m Wed Mar 4 11:55:52 2015 > @@ -0,0 +1,146 @@ > +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc > -verify -Wno-objc-root-class %s > + > +typedef long int NSUInteger; > +#define nil 0 > +@class NSString; > + > +@interface NSMutableArray > + > +- (void)addObject:(id)object; > +- (void)insertObject:(id)object atIndex:(NSUInteger)index; > +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object; > +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index; > + > +@end > + > +@interface NSMutableDictionary > + > +- (void)setObject:(id)object forKey:(id)key; > +- (void)setObject:(id)object forKeyedSubscript:(id)key; > +- (void)setValue:(id)value forKey:(NSString *)key; > + > +@end > + > +@interface NSMutableSet > + > +- (void)addObject:(id)object; > + > +@end > + > +@interface NSCountedSet : NSMutableSet > + > +@end > + > +@interface NSMutableOrderedSet > + > +- (void)addObject:(id)object; > +- (void)insertObject:(id)object atIndex:(NSUInteger)index; > +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index; > +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object; > +- (void)setObject:(id)object atIndex:(NSUInteger)index; > + > +@end > + > +@interface SelfRefClass > +{ > + NSMutableArray *_array; // expected-note {{'_array' declared here}} > + NSMutableDictionary *_dictionary; // expected-note {{'_dictionary' > declared here}} > + NSMutableSet *_set; // expected-note {{'_set' declared here}} > + NSCountedSet *_countedSet; // expected-note {{'_countedSet' declared here}} > + NSMutableOrderedSet *_orderedSet; // expected-note {{'_orderedSet' > declared here}} > +} > +@end > + > +@implementation SelfRefClass > + > +- (void)check { > + [_array addObject:_array]; // expected-warning {{adding '_array' to > '_array' might cause circular dependency in container}} > + [_dictionary setObject:_dictionary forKey:@"key"]; // expected-warning > {{adding '_dictionary' to '_dictionary' might cause circular dependency in > container}} > + [_set addObject:_set]; // expected-warning {{adding '_set' to '_set' might > cause circular dependency in container}} > + [_countedSet addObject:_countedSet]; // expected-warning {{adding > '_countedSet' to '_countedSet' might cause circular dependency in container}} > + [_orderedSet addObject:_orderedSet]; // expected-warning {{adding > '_orderedSet' to '_orderedSet' might cause circular dependency in container}} > +} > + > +- (void)checkNSMutableArray:(NSMutableArray *)a { // expected-note {{'a' > declared here}} > + [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause > circular dependency in container}} > +} > + > +- (void)checkNSMutableDictionary:(NSMutableDictionary *)d { // expected-note > {{'d' declared here}} > + [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' > might cause circular dependency in container}} > +} > + > +- (void)checkNSMutableSet:(NSMutableSet *)s { // expected-note {{'s' > declared here}} > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +- (void)checkNSCountedSet:(NSCountedSet *)s { // expected-note {{'s' > declared here}} > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +- (void)checkNSMutableOrderedSet:(NSMutableOrderedSet *)s { // expected-note > {{'s' declared here}} > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +@end > + > +void checkNSMutableArrayParam(NSMutableArray *a) { // expected-note {{'a' > declared here}} > + [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause > circular dependency in container}} > +} > + > +void checkNSMutableDictionaryParam(NSMutableDictionary *d) { // > expected-note {{'d' declared here}} > + [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' > might cause circular dependency in container}} > +} > + > +void checkNSMutableSetParam(NSMutableSet *s) { // expected-note {{'s' > declared here}} > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +void checkNSCountedSetParam(NSCountedSet *s) { // expected-note {{'s' > declared here}} > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +void checkNSMutableOrderedSetParam(NSMutableOrderedSet *s) { // > expected-note {{'s' declared here}} > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +void checkNSMutableArray() { > + NSMutableArray *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 checkNSMutableDictionary() { > + NSMutableDictionary *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 checkNSMutableSet() { > + NSMutableSet *s = nil; // expected-note {{'s' declared here}} > + > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +void checkNSCountedSet() { > + NSCountedSet *s = nil; // expected-note {{'s' declared here}} > + > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > +} > + > +void checkNSMutableOrderedSet() { > + NSMutableOrderedSet *s = nil; // expected-note 5 {{'s' declared here}} > + > + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause > circular dependency in container}} > + [s insertObject:s atIndex:0]; // expected-warning {{adding 's' to 's' > might cause circular dependency in container}} > + [s setObject:s atIndex:0]; // expected-warning {{adding 's' to 's' might > cause circular dependency in container}} > + [s setObject:s atIndexedSubscript:0]; // expected-warning {{adding 's' to > 's' might cause circular dependency in container}} > + [s replaceObjectAtIndex:0 withObject:s]; // expected-warning {{adding 's' > to 's' might cause circular dependency in container}} > +} > + > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
