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,
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,
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;
/// \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,
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;
/// \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"),
/// \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];
"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 - "
/// \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;
/// 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,
"NSMutableArray",
"NSDictionary",
"NSMutableDictionary",
- "NSNumber"
+ "NSNumber",
+ "NSMutableSet",
+ "NSCountedSet",
+ "NSMutableOrderedSet"
};
if (!ClassIds[K])
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);
}
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);
}
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;
+}
+
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
bool Instance) const {
static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
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.
}
}
}
-
+
+ CheckObjCCircularContainer(Result);
+
return MaybeBindToTemporary(Result);
}
--- /dev/null
+// 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}}
+}
+