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. 

llvm-svn: 231265
This commit is contained in:
Alex Denisov
2015-03-04 17:55:52 +00:00
parent 4d9347993b
commit e1d882c726
7 changed files with 536 additions and 10 deletions

View File

@@ -27,7 +27,10 @@ IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
"NSMutableArray",
"NSDictionary",
"NSMutableDictionary",
"NSNumber"
"NSNumber",
"NSMutableSet",
"NSCountedSet",
"NSMutableOrderedSet"
};
if (!ClassIds[K])
@@ -124,6 +127,25 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
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);
}
@@ -227,6 +265,63 @@ NSAPI::getNSDictionaryMethodKind(Selector 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] = {