r231265 - New ObjC warning: circular containers.

Alexey Denisov 1101.debian at gmail.com
Wed Jul 29 09:53:21 PDT 2015


Sure, I will.
Thank you for report, I didn't cover this case.

On Wednesday, July 29, 2015, Argyrios Kyrtzidis <kyrtzidis at apple.com> wrote:

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


More information about the cfe-commits mailing list