r231265 - New ObjC warning: circular containers.
Ted Kremenek
kremenek at apple.com
Wed Jul 29 10:24:13 PDT 2015
Neat!
> On Mar 4, 2015, at 9:55 AM, Alex Denisov <1101.debian at gmail.com> 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
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list