Sure, I will.<div>Thank you for report, I didn't cover this case.<span></span><br><br>On Wednesday, July 29, 2015, Argyrios Kyrtzidis <<a href="mailto:kyrtzidis@apple.com">kyrtzidis@apple.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Alex,<br>
<br>
This change causes a crash in valid code, you can find the test case below, could you take a look ?<br>
<br>
--- a/test/SemaObjC/circular-container.m<br>
+++ b/test/SemaObjC/circular-container.m<br>
@@ -144,3 +144,11 @@ void checkNSMutableOrderedSet() {<br>
[s replaceObjectAtIndex:0 withObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
}<br>
<br>
+@interface Test1 : NSCountedSet<br>
+@end<br>
+<br>
+@implementation Test1<br>
+-(void)meth {<br>
+ [super addObject:0];<br>
+}<br>
+@end<br>
<br>
<br>
> On Mar 4, 2015, at 9:55 AM, Alex Denisov <<a href="javascript:;" onclick="_e(event, 'cvml', '1101.debian@gmail.com')">1101.debian@gmail.com</a>> wrote:<br>
><br>
> Author: alexdenisov<br>
> Date: Wed Mar 4 11:55:52 2015<br>
> New Revision: 231265<br>
><br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject-3Frev-3D231265-26view-3Drev&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=v4NSSgCl2VkA0wp1tYDWH7VcupZQFildaeFztr0FVbU&e=" target="_blank">http://llvm.org/viewvc/llvm-project?rev=231265&view=rev</a><br>
> Log:<br>
> New ObjC warning: circular containers.<br>
><br>
> This commit adds new warning to prevent user from creating 'circular containers'.<br>
><br>
> Mutable collections from NSFoundation allows user to add collection to itself, e.g.:<br>
><br>
> NSMutableArray *a = [NSMutableArray new];<br>
> [a addObject:a];<br>
><br>
> The code above leads to really weird behaviour (crashes, 'endless' recursion) and<br>
> retain cycles (collection retains itself) if ARC enabled.<br>
><br>
> Patch checks the following collections:<br>
> - NSMutableArray,<br>
> - NSMutableDictionary,<br>
> - NSMutableSet,<br>
> - NSMutableOrderedSet,<br>
> - NSCountedSet.<br>
><br>
><br>
> Added:<br>
> cfe/trunk/test/SemaObjC/circular-container.m<br>
> Modified:<br>
> cfe/trunk/include/clang/AST/NSAPI.h<br>
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> cfe/trunk/include/clang/Sema/Sema.h<br>
> cfe/trunk/lib/AST/NSAPI.cpp<br>
> cfe/trunk/lib/Sema/SemaChecking.cpp<br>
> cfe/trunk/lib/Sema/SemaExprObjC.cpp<br>
><br>
> Modified: cfe/trunk/include/clang/AST/NSAPI.h<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_include_clang_AST_NSAPI.h-3Frev-3D231265-26r1-3D231264-26r2-3D231265-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=lRYixHRhic0C8q7xCi9Yx9xIgEG9DCIBFHvUaRicRf4&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NSAPI.h?rev=231265&r1=231264&r2=231265&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/NSAPI.h (original)<br>
> +++ cfe/trunk/include/clang/AST/NSAPI.h Wed Mar 4 11:55:52 2015<br>
> @@ -33,9 +33,12 @@ public:<br>
> ClassId_NSMutableArray,<br>
> ClassId_NSDictionary,<br>
> ClassId_NSMutableDictionary,<br>
> - ClassId_NSNumber<br>
> + ClassId_NSNumber,<br>
> + ClassId_NSMutableSet,<br>
> + ClassId_NSCountedSet,<br>
> + ClassId_NSMutableOrderedSet,<br>
> };<br>
> - static const unsigned NumClassIds = 7;<br>
> + static const unsigned NumClassIds = 10;<br>
><br>
> enum NSStringMethodKind {<br>
> NSStr_stringWithString,<br>
> @@ -67,7 +70,8 @@ public:<br>
> return isObjCEnumerator(E, "NSASCIIStringEncoding",NSASCIIStringEncodingId);<br>
> }<br>
><br>
> - /// \brief Enumerates the NSArray methods used to generate literals.<br>
> + /// \brief Enumerates the NSArray/NSMutableArray methods used to generate<br>
> + /// literals and to apply some checks.<br>
> enum NSArrayMethodKind {<br>
> NSArr_array,<br>
> NSArr_arrayWithArray,<br>
> @@ -77,9 +81,12 @@ public:<br>
> NSArr_initWithArray,<br>
> NSArr_initWithObjects,<br>
> NSArr_objectAtIndex,<br>
> - NSMutableArr_replaceObjectAtIndex<br>
> + NSMutableArr_replaceObjectAtIndex,<br>
> + NSMutableArr_addObject,<br>
> + NSMutableArr_insertObjectAtIndex,<br>
> + NSMutableArr_setObjectAtIndexedSubscript<br>
> };<br>
> - static const unsigned NumNSArrayMethods = 9;<br>
> + static const unsigned NumNSArrayMethods = 12;<br>
><br>
> /// \brief The Objective-C NSArray selectors.<br>
> Selector getNSArraySelector(NSArrayMethodKind MK) const;<br>
> @@ -87,7 +94,8 @@ public:<br>
> /// \brief Return NSArrayMethodKind if \p Sel is such a selector.<br>
> Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);<br>
><br>
> - /// \brief Enumerates the NSDictionary methods used to generate literals.<br>
> + /// \brief Enumerates the NSDictionary/NSMutableDictionary methods used<br>
> + /// to generate literals and to apply some checks.<br>
> enum NSDictionaryMethodKind {<br>
> NSDict_dictionary,<br>
> NSDict_dictionaryWithDictionary,<br>
> @@ -99,9 +107,11 @@ public:<br>
> NSDict_initWithObjectsAndKeys,<br>
> NSDict_initWithObjectsForKeys,<br>
> NSDict_objectForKey,<br>
> - NSMutableDict_setObjectForKey<br>
> + NSMutableDict_setObjectForKey,<br>
> + NSMutableDict_setObjectForKeyedSubscript,<br>
> + NSMutableDict_setValueForKey<br>
> };<br>
> - static const unsigned NumNSDictionaryMethods = 12;<br>
> + static const unsigned NumNSDictionaryMethods = 14;<br>
><br>
> /// \brief The Objective-C NSDictionary selectors.<br>
> Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;<br>
> @@ -109,6 +119,23 @@ public:<br>
> /// \brief Return NSDictionaryMethodKind if \p Sel is such a selector.<br>
> Optional<NSDictionaryMethodKind> getNSDictionaryMethodKind(Selector Sel);<br>
><br>
> + /// \brief Enumerates the NSMutableSet/NSOrderedSet methods used<br>
> + /// to apply some checks.<br>
> + enum NSSetMethodKind {<br>
> + NSMutableSet_addObject,<br>
> + NSOrderedSet_insertObjectAtIndex,<br>
> + NSOrderedSet_setObjectAtIndex,<br>
> + NSOrderedSet_setObjectAtIndexedSubscript,<br>
> + NSOrderedSet_replaceObjectAtIndexWithObject<br>
> + };<br>
> + static const unsigned NumNSSetMethods = 5;<br>
> +<br>
> + /// \brief The Objective-C NSSet selectors.<br>
> + Selector getNSSetSelector(NSSetMethodKind MK) const;<br>
> +<br>
> + /// \brief Return NSSetMethodKind if \p Sel is such a selector.<br>
> + Optional<NSSetMethodKind> getNSSetMethodKind(Selector Sel);<br>
> +<br>
> /// \brief Returns selector for "objectForKeyedSubscript:".<br>
> Selector getObjectForKeyedSubscriptSelector() const {<br>
> return getOrInitSelector(StringRef("objectForKeyedSubscript"),<br>
> @@ -207,6 +234,9 @@ private:<br>
> /// \brief The selectors for Objective-C NSDictionary methods.<br>
> mutable Selector NSDictionarySelectors[NumNSDictionaryMethods];<br>
><br>
> + /// \brief The selectors for Objective-C NSSet methods.<br>
> + mutable Selector NSSetSelectors[NumNSSetMethods];<br>
> +<br>
> /// \brief The Objective-C NSNumber selectors used to create NSNumber literals.<br>
> mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods];<br>
> mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_include_clang_Basic_DiagnosticSemaKinds.td-3Frev-3D231265-26r1-3D231264-26r2-3D231265-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=VUEK8jAtWryKnnAl8bLrdXGcBKGkR2R8SgC6MWZi6QQ&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=231265&r1=231264&r2=231265&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Mar 4 11:55:52 2015<br>
> @@ -5263,6 +5263,10 @@ def err_objc_object_catch : Error<<br>
> "can't catch an Objective-C object by value">;<br>
> def err_incomplete_type_objc_at_encode : Error<<br>
> "'@encode' of incomplete type %0">;<br>
> +def warn_objc_circular_container : Warning<<br>
> + "adding '%0' to '%0' might cause circular dependency in container">,<br>
> + InGroup<DiagGroup<"objc-circular-container">>;<br>
> +def note_objc_circular_container_declared_here : Note<"'%0' declared here">;<br>
><br>
> def warn_setter_getter_impl_required : Warning<<br>
> "property %0 requires method %1 to be defined - "<br>
><br>
> Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_include_clang_Sema_Sema.h-3Frev-3D231265-26r1-3D231264-26r2-3D231265-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=3tGmQfq61BTdiJ4jX-cgEGrNvDsg_LOO4XENIkWN2kA&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=231265&r1=231264&r2=231265&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar 4 11:55:52 2015<br>
> @@ -683,12 +683,27 @@ public:<br>
> /// \brief The declaration of the Objective-C NSArray class.<br>
> ObjCInterfaceDecl *NSArrayDecl;<br>
><br>
> + /// \brief Pointer to NSMutableArray type (NSMutableArray *).<br>
> + QualType NSMutableArrayPointer;<br>
> +<br>
> /// \brief The declaration of the arrayWithObjects:count: method.<br>
> ObjCMethodDecl *ArrayWithObjectsMethod;<br>
><br>
> /// \brief The declaration of the Objective-C NSDictionary class.<br>
> ObjCInterfaceDecl *NSDictionaryDecl;<br>
><br>
> + /// \brief Pointer to NSMutableDictionary type (NSMutableDictionary *).<br>
> + QualType NSMutableDictionaryPointer;<br>
> +<br>
> + /// \brief Pointer to NSMutableSet type (NSMutableSet *).<br>
> + QualType NSMutableSetPointer;<br>
> +<br>
> + /// \brief Pointer to NSCountedSet type (NSCountedSet *).<br>
> + QualType NSCountedSetPointer;<br>
> +<br>
> + /// \brief Pointer to NSMutableOrderedSet type (NSMutableOrderedSet *).<br>
> + QualType NSMutableOrderedSetPointer;<br>
> +<br>
> /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method.<br>
> ObjCMethodDecl *DictionaryWithObjectsMethod;<br>
><br>
> @@ -8645,6 +8660,10 @@ private:<br>
> /// statement that produces control flow different from GCC.<br>
> void CheckBreakContinueBinding(Expr *E);<br>
><br>
> + /// \brief Check whether receiver is mutable ObjC container which<br>
> + /// attempts to add itself into the container<br>
> + void CheckObjCCircularContainer(ObjCMessageExpr *Message);<br>
> +<br>
> public:<br>
> /// \brief Register a magic integral constant to be used as a type tag.<br>
> void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,<br>
><br>
> Modified: cfe/trunk/lib/AST/NSAPI.cpp<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_lib_AST_NSAPI.cpp-3Frev-3D231265-26r1-3D231264-26r2-3D231265-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=3hqwGkOmRjRiLkaCrqu9Uzw5b_X1VhgMX6wcEGLz6k8&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?rev=231265&r1=231264&r2=231265&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/AST/NSAPI.cpp (original)<br>
> +++ cfe/trunk/lib/AST/NSAPI.cpp Wed Mar 4 11:55:52 2015<br>
> @@ -27,7 +27,10 @@ IdentifierInfo *NSAPI::getNSClassId(NSCl<br>
> "NSMutableArray",<br>
> "NSDictionary",<br>
> "NSMutableDictionary",<br>
> - "NSNumber"<br>
> + "NSNumber",<br>
> + "NSMutableSet",<br>
> + "NSCountedSet",<br>
> + "NSMutableOrderedSet"<br>
> };<br>
><br>
> if (!ClassIds[K])<br>
> @@ -124,6 +127,25 @@ Selector NSAPI::getNSArraySelector(NSArr<br>
> Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> break;<br>
> }<br>
> + case NSMutableArr_addObject:<br>
> + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));<br>
> + break;<br>
> + case NSMutableArr_insertObjectAtIndex: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("insertObject"),<br>
> + &Ctx.Idents.get("atIndex")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> + case NSMutableArr_setObjectAtIndexedSubscript: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("setObject"),<br>
> + &Ctx.Idents.get("atIndexedSubscript")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> }<br>
> return (NSArraySelectors[MK] = Sel);<br>
> }<br>
> @@ -209,6 +231,22 @@ Selector NSAPI::getNSDictionarySelector(<br>
> Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> break;<br>
> }<br>
> + case NSMutableDict_setObjectForKeyedSubscript: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("setObject"),<br>
> + &Ctx.Idents.get("forKeyedSubscript")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> + case NSMutableDict_setValueForKey: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("setValue"),<br>
> + &Ctx.Idents.get("forKey")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> }<br>
> return (NSDictionarySelectors[MK] = Sel);<br>
> }<br>
> @@ -224,6 +262,63 @@ NSAPI::getNSDictionaryMethodKind(Selecto<br>
> return MK;<br>
> }<br>
><br>
> + return None;<br>
> +}<br>
> +<br>
> +Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {<br>
> + if (NSSetSelectors[MK].isNull()) {<br>
> + Selector Sel;<br>
> + switch (MK) {<br>
> + case NSMutableSet_addObject:<br>
> + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));<br>
> + break;<br>
> + case NSOrderedSet_insertObjectAtIndex: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("insertObject"),<br>
> + &Ctx.Idents.get("atIndex")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> + case NSOrderedSet_setObjectAtIndex: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("setObject"),<br>
> + &Ctx.Idents.get("atIndex")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> + case NSOrderedSet_setObjectAtIndexedSubscript: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("setObject"),<br>
> + &Ctx.Idents.get("atIndexedSubscript")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> + case NSOrderedSet_replaceObjectAtIndexWithObject: {<br>
> + IdentifierInfo *KeyIdents[] = {<br>
> + &Ctx.Idents.get("replaceObjectAtIndex"),<br>
> + &Ctx.Idents.get("withObject")<br>
> + };<br>
> + Sel = Ctx.Selectors.getSelector(2, KeyIdents);<br>
> + break;<br>
> + }<br>
> + }<br>
> + return (NSSetSelectors[MK] = Sel);<br>
> + }<br>
> +<br>
> + return NSSetSelectors[MK];<br>
> +}<br>
> +<br>
> +Optional<NSAPI::NSSetMethodKind><br>
> +NSAPI::getNSSetMethodKind(Selector Sel) {<br>
> + for (unsigned i = 0; i != NumNSSetMethods; ++i) {<br>
> + NSSetMethodKind MK = NSSetMethodKind(i);<br>
> + if (Sel == getNSSetSelector(MK))<br>
> + return MK;<br>
> + }<br>
> +<br>
> return None;<br>
> }<br>
><br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_lib_Sema_SemaChecking.cpp-3Frev-3D231265-26r1-3D231264-26r2-3D231265-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=mD8W9e5GzJwhlILXYU05ZH9NE35VLSnyptQbu3HGdVI&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=231265&r1=231264&r2=231265&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Mar 4 11:55:52 2015<br>
> @@ -8187,6 +8187,236 @@ static bool isSetterLikeSelector(Selecto<br>
> return !isLowercase(str.front());<br>
> }<br>
><br>
> +Optional<int> GetNSMutableArrayArgumentIndex(Sema &S, ObjCMessageExpr *Message) {<br>
> +<br>
> + if (S.NSMutableArrayPointer.isNull()) {<br>
> + IdentifierInfo *NSMutableArrayId =<br>
> + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableArray);<br>
> + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableArrayId,<br>
> + Message->getLocStart(),<br>
> + Sema::LookupOrdinaryName);<br>
> + ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);<br>
> + if (!InterfaceDecl) {<br>
> + return None;<br>
> + }<br>
> + QualType NSMutableArrayObject =<br>
> + S.Context.getObjCInterfaceType(InterfaceDecl);<br>
> + S.NSMutableArrayPointer =<br>
> + S.Context.getObjCObjectPointerType(NSMutableArrayObject);<br>
> + }<br>
> +<br>
> + if (S.NSMutableArrayPointer != Message->getReceiverType()) {<br>
> + return None;<br>
> + }<br>
> +<br>
> + Selector Sel = Message->getSelector();<br>
> +<br>
> + Optional<NSAPI::NSArrayMethodKind> MKOpt =<br>
> + S.NSAPIObj->getNSArrayMethodKind(Sel);<br>
> + if (!MKOpt) {<br>
> + return None;<br>
> + }<br>
> +<br>
> + NSAPI::NSArrayMethodKind MK = *MKOpt;<br>
> +<br>
> + switch (MK) {<br>
> + case NSAPI::NSMutableArr_addObject:<br>
> + case NSAPI::NSMutableArr_insertObjectAtIndex:<br>
> + case NSAPI::NSMutableArr_setObjectAtIndexedSubscript:<br>
> + return 0;<br>
> + case NSAPI::NSMutableArr_replaceObjectAtIndex:<br>
> + return 1;<br>
> +<br>
> + default:<br>
> + return None;<br>
> + }<br>
> +<br>
> + return None;<br>
> +}<br>
> +<br>
> +static<br>
> +Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,<br>
> + ObjCMessageExpr *Message) {<br>
> +<br>
> + if (S.NSMutableDictionaryPointer.isNull()) {<br>
> + IdentifierInfo *NSMutableDictionaryId =<br>
> + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableDictionary);<br>
> + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableDictionaryId,<br>
> + Message->getLocStart(),<br>
> + Sema::LookupOrdinaryName);<br>
> + ObjCInterfaceDecl *InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);<br>
> + if (!InterfaceDecl) {<br>
> + return None;<br>
> + }<br>
> + QualType NSMutableDictionaryObject =<br>
> + S.Context.getObjCInterfaceType(InterfaceDecl);<br>
> + S.NSMutableDictionaryPointer =<br>
> + S.Context.getObjCObjectPointerType(NSMutableDictionaryObject);<br>
> + }<br>
> +<br>
> + if (S.NSMutableDictionaryPointer != Message->getReceiverType()) {<br>
> + return None;<br>
> + }<br>
> +<br>
> + Selector Sel = Message->getSelector();<br>
> +<br>
> + Optional<NSAPI::NSDictionaryMethodKind> MKOpt =<br>
> + S.NSAPIObj->getNSDictionaryMethodKind(Sel);<br>
> + if (!MKOpt) {<br>
> + return None;<br>
> + }<br>
> +<br>
> + NSAPI::NSDictionaryMethodKind MK = *MKOpt;<br>
> +<br>
> + switch (MK) {<br>
> + case NSAPI::NSMutableDict_setObjectForKey:<br>
> + case NSAPI::NSMutableDict_setValueForKey:<br>
> + case NSAPI::NSMutableDict_setObjectForKeyedSubscript:<br>
> + return 0;<br>
> +<br>
> + default:<br>
> + return None;<br>
> + }<br>
> +<br>
> + return None;<br>
> +}<br>
> +<br>
> +static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {<br>
> +<br>
> + ObjCInterfaceDecl *InterfaceDecl;<br>
> + if (S.NSMutableSetPointer.isNull()) {<br>
> + IdentifierInfo *NSMutableSetId =<br>
> + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableSet);<br>
> + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSMutableSetId,<br>
> + Message->getLocStart(),<br>
> + Sema::LookupOrdinaryName);<br>
> + InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);<br>
> + if (InterfaceDecl) {<br>
> + QualType NSMutableSetObject =<br>
> + S.Context.getObjCInterfaceType(InterfaceDecl);<br>
> + S.NSMutableSetPointer =<br>
> + S.Context.getObjCObjectPointerType(NSMutableSetObject);<br>
> + }<br>
> + }<br>
> +<br>
> + if (S.NSCountedSetPointer.isNull()) {<br>
> + IdentifierInfo *NSCountedSetId =<br>
> + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSCountedSet);<br>
> + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSCountedSetId,<br>
> + Message->getLocStart(),<br>
> + Sema::LookupOrdinaryName);<br>
> + InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);<br>
> + if (InterfaceDecl) {<br>
> + QualType NSCountedSetObject =<br>
> + S.Context.getObjCInterfaceType(InterfaceDecl);<br>
> + S.NSCountedSetPointer =<br>
> + S.Context.getObjCObjectPointerType(NSCountedSetObject);<br>
> + }<br>
> + }<br>
> +<br>
> + if (S.NSMutableOrderedSetPointer.isNull()) {<br>
> + IdentifierInfo *NSOrderedSetId =<br>
> + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSMutableOrderedSet);<br>
> + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSOrderedSetId,<br>
> + Message->getLocStart(),<br>
> + Sema::LookupOrdinaryName);<br>
> + InterfaceDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);<br>
> + if (InterfaceDecl) {<br>
> + QualType NSOrderedSetObject =<br>
> + S.Context.getObjCInterfaceType(InterfaceDecl);<br>
> + S.NSMutableOrderedSetPointer =<br>
> + S.Context.getObjCObjectPointerType(NSOrderedSetObject);<br>
> + }<br>
> + }<br>
> +<br>
> + QualType ReceiverType = Message->getReceiverType();<br>
> +<br>
> + bool IsMutableSet = !S.NSMutableSetPointer.isNull() &&<br>
> + ReceiverType == S.NSMutableSetPointer;<br>
> + bool IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() &&<br>
> + ReceiverType == S.NSMutableOrderedSetPointer;<br>
> + bool IsCountedSet = !S.NSCountedSetPointer.isNull() &&<br>
> + ReceiverType == S.NSCountedSetPointer;<br>
> +<br>
> + if (!IsMutableSet && !IsMutableOrderedSet && !IsCountedSet) {<br>
> + return None;<br>
> + }<br>
> +<br>
> + Selector Sel = Message->getSelector();<br>
> +<br>
> + Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel);<br>
> + if (!MKOpt) {<br>
> + return None;<br>
> + }<br>
> +<br>
> + NSAPI::NSSetMethodKind MK = *MKOpt;<br>
> +<br>
> + switch (MK) {<br>
> + case NSAPI::NSMutableSet_addObject:<br>
> + case NSAPI::NSOrderedSet_setObjectAtIndex:<br>
> + case NSAPI::NSOrderedSet_setObjectAtIndexedSubscript:<br>
> + case NSAPI::NSOrderedSet_insertObjectAtIndex:<br>
> + return 0;<br>
> + case NSAPI::NSOrderedSet_replaceObjectAtIndexWithObject:<br>
> + return 1;<br>
> + }<br>
> +<br>
> + return None;<br>
> +}<br>
> +<br>
> +void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {<br>
> + if (!Message->isInstanceMessage()) {<br>
> + return;<br>
> + }<br>
> +<br>
> + Optional<int> ArgOpt;<br>
> +<br>
> + if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) &&<br>
> + !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) &&<br>
> + !(ArgOpt = GetNSSetArgumentIndex(*this, Message))) {<br>
> + return;<br>
> + }<br>
> +<br>
> + int ArgIndex = *ArgOpt;<br>
> +<br>
> + Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts();<br>
> + if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) {<br>
> + Receiver = OE->getSourceExpr()->IgnoreImpCasts();<br>
> + }<br>
> +<br>
> + Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts();<br>
> + if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Arg)) {<br>
> + Arg = OE->getSourceExpr()->IgnoreImpCasts();<br>
> + }<br>
> +<br>
> + if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) {<br>
> + if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) {<br>
> + if (ReceiverRE->getDecl() == ArgRE->getDecl()) {<br>
> + ValueDecl *Decl = ReceiverRE->getDecl();<br>
> + Diag(Message->getSourceRange().getBegin(),<br>
> + diag::warn_objc_circular_container)<br>
> + << Decl->getName();<br>
> + Diag(Decl->getLocation(),<br>
> + diag::note_objc_circular_container_declared_here)<br>
> + << Decl->getName();<br>
> + }<br>
> + }<br>
> + } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) {<br>
> + if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) {<br>
> + if (IvarRE->getDecl() == IvarArgRE->getDecl()) {<br>
> + ObjCIvarDecl *Decl = IvarRE->getDecl();<br>
> + Diag(Message->getSourceRange().getBegin(),<br>
> + diag::warn_objc_circular_container)<br>
> + << Decl->getName();<br>
> + Diag(Decl->getLocation(),<br>
> + diag::note_objc_circular_container_declared_here)<br>
> + << Decl->getName();<br>
> + }<br>
> + }<br>
> + }<br>
> +<br>
> +}<br>
> +<br>
> /// Check a message send to see if it's likely to cause a retain cycle.<br>
> void Sema::checkRetainCycles(ObjCMessageExpr *msg) {<br>
> // Only check instance methods whose selector looks like a setter.<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_lib_Sema_SemaExprObjC.cpp-3Frev-3D231265-26r1-3D231264-26r2-3D231265-26view-3Ddiff&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=N1XOz4HJvTcEr-Ul1oQ4HA2foi8SqjyGP6RKj1BpTpI&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=231265&r1=231264&r2=231265&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Wed Mar 4 11:55:52 2015<br>
> @@ -2799,7 +2799,9 @@ ExprResult Sema::BuildInstanceMessage(Ex<br>
> }<br>
> }<br>
> }<br>
> -<br>
> +<br>
> + CheckObjCCircularContainer(Result);<br>
> +<br>
> return MaybeBindToTemporary(Result);<br>
> }<br>
><br>
><br>
> Added: cfe/trunk/test/SemaObjC/circular-container.m<br>
> URL: <a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__llvm.org_viewvc_llvm-2Dproject_cfe_trunk_test_SemaObjC_circular-2Dcontainer.m-3Frev-3D231265-26view-3Dauto&d=AwMFaQ&c=8hUWFZcy2Z-Za5rBPlktOQ&r=BSqEv9KvKMW_Ob8SyngJ70KdZISM_ASROnREeq0cCxk&m=7fkdvLQ3CgJFAlkJquKusERurCGUA3oEIxHbdE1lxLM&s=tPUTlMyyZsrMILaTYCaiW3e_rTDpcrDP4FPjWM6Yuz4&e=" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/circular-container.m?rev=231265&view=auto</a><br>
> ==============================================================================<br>
> --- cfe/trunk/test/SemaObjC/circular-container.m (added)<br>
> +++ cfe/trunk/test/SemaObjC/circular-container.m Wed Mar 4 11:55:52 2015<br>
> @@ -0,0 +1,146 @@<br>
> +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s<br>
> +<br>
> +typedef long int NSUInteger;<br>
> +#define nil 0<br>
> +@class NSString;<br>
> +<br>
> +@interface NSMutableArray<br>
> +<br>
> +- (void)addObject:(id)object;<br>
> +- (void)insertObject:(id)object atIndex:(NSUInteger)index;<br>
> +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object;<br>
> +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index;<br>
> +<br>
> +@end<br>
> +<br>
> +@interface NSMutableDictionary<br>
> +<br>
> +- (void)setObject:(id)object forKey:(id)key;<br>
> +- (void)setObject:(id)object forKeyedSubscript:(id)key;<br>
> +- (void)setValue:(id)value forKey:(NSString *)key;<br>
> +<br>
> +@end<br>
> +<br>
> +@interface NSMutableSet<br>
> +<br>
> +- (void)addObject:(id)object;<br>
> +<br>
> +@end<br>
> +<br>
> +@interface NSCountedSet : NSMutableSet<br>
> +<br>
> +@end<br>
> +<br>
> +@interface NSMutableOrderedSet<br>
> +<br>
> +- (void)addObject:(id)object;<br>
> +- (void)insertObject:(id)object atIndex:(NSUInteger)index;<br>
> +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index;<br>
> +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object;<br>
> +- (void)setObject:(id)object atIndex:(NSUInteger)index;<br>
> +<br>
> +@end<br>
> +<br>
> +@interface SelfRefClass<br>
> +{<br>
> + NSMutableArray *_array; // expected-note {{'_array' declared here}}<br>
> + NSMutableDictionary *_dictionary; // expected-note {{'_dictionary' declared here}}<br>
> + NSMutableSet *_set; // expected-note {{'_set' declared here}}<br>
> + NSCountedSet *_countedSet; // expected-note {{'_countedSet' declared here}}<br>
> + NSMutableOrderedSet *_orderedSet; // expected-note {{'_orderedSet' declared here}}<br>
> +}<br>
> +@end<br>
> +<br>
> +@implementation SelfRefClass<br>
> +<br>
> +- (void)check {<br>
> + [_array addObject:_array]; // expected-warning {{adding '_array' to '_array' might cause circular dependency in container}}<br>
> + [_dictionary setObject:_dictionary forKey:@"key"]; // expected-warning {{adding '_dictionary' to '_dictionary' might cause circular dependency in container}}<br>
> + [_set addObject:_set]; // expected-warning {{adding '_set' to '_set' might cause circular dependency in container}}<br>
> + [_countedSet addObject:_countedSet]; // expected-warning {{adding '_countedSet' to '_countedSet' might cause circular dependency in container}}<br>
> + [_orderedSet addObject:_orderedSet]; // expected-warning {{adding '_orderedSet' to '_orderedSet' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +- (void)checkNSMutableArray:(NSMutableArray *)a { // expected-note {{'a' declared here}}<br>
> + [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +- (void)checkNSMutableDictionary:(NSMutableDictionary *)d { // expected-note {{'d' declared here}}<br>
> + [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +- (void)checkNSMutableSet:(NSMutableSet *)s { // expected-note {{'s' declared here}}<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +- (void)checkNSCountedSet:(NSCountedSet *)s { // expected-note {{'s' declared here}}<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +- (void)checkNSMutableOrderedSet:(NSMutableOrderedSet *)s { // expected-note {{'s' declared here}}<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +@end<br>
> +<br>
> +void checkNSMutableArrayParam(NSMutableArray *a) { // expected-note {{'a' declared here}}<br>
> + [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableDictionaryParam(NSMutableDictionary *d) { // expected-note {{'d' declared here}}<br>
> + [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableSetParam(NSMutableSet *s) { // expected-note {{'s' declared here}}<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSCountedSetParam(NSCountedSet *s) { // expected-note {{'s' declared here}}<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableOrderedSetParam(NSMutableOrderedSet *s) { // expected-note {{'s' declared here}}<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableArray() {<br>
> + NSMutableArray *a = nil; // expected-note 5 {{'a' declared here}} 5<br>
> +<br>
> + [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> + [a insertObject:a atIndex:0]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> + [a replaceObjectAtIndex:0 withObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> + [a setObject:a atIndexedSubscript:0]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> + a[0] = a; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableDictionary() {<br>
> + NSMutableDictionary *d = nil; // expected-note 4 {{'d' declared here}}<br>
> +<br>
> + [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}<br>
> + [d setObject:d forKeyedSubscript:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}<br>
> + [d setValue:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}<br>
> + d[@"key"] = d; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableSet() {<br>
> + NSMutableSet *s = nil; // expected-note {{'s' declared here}}<br>
> +<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSCountedSet() {<br>
> + NSCountedSet *s = nil; // expected-note {{'s' declared here}}<br>
> +<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
> +void checkNSMutableOrderedSet() {<br>
> + NSMutableOrderedSet *s = nil; // expected-note 5 {{'s' declared here}}<br>
> +<br>
> + [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> + [s insertObject:s atIndex:0]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> + [s setObject:s atIndex:0]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> + [s setObject:s atIndexedSubscript:0]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> + [s replaceObjectAtIndex:0 withObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}<br>
> +}<br>
> +<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="javascript:;" onclick="_e(event, 'cvml', 'cfe-commits@cs.uiuc.edu')">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
<br>
</blockquote></div>