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, &#39;cvml&#39;, &#39;1101.debian@gmail.com&#39;)">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, &#39;cvml&#39;, &#39;cfe-commits@cs.uiuc.edu&#39;)">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>