Please let me know when this gets fixed. It's probably something we should merge to 3.7.
On Wed, Jul 29, 2015 at 9:53 AM, Alexey Denisov <[email protected]> wrote: > Sure, I will. > Thank you for report, I didn't cover this case. > > > On Wednesday, July 29, 2015, Argyrios Kyrtzidis <[email protected]> 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}} >> } >> >> +@interface Test1 : NSCountedSet >> +@end >> + >> +@implementation Test1 >> +-(void)meth { >> + [super addObject:0]; >> +} >> +@end >> >> >> > On Mar 4, 2015, at 9:55 AM, Alex Denisov <[email protected]> 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 >> > +@class NSString; >> > + >> > +@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; >> > + >> > +@end >> > + >> > +@interface NSMutableDictionary >> > + >> > +- (void)setObject:(id)object forKey:(id)key; >> > +- (void)setObject:(id)object forKeyedSubscript:(id)key; >> > +- (void)setValue:(id)value forKey:(NSString *)key; >> > + >> > +@end >> > + >> > +@interface NSMutableSet >> > + >> > +- (void)addObject:(id)object; >> > + >> > +@end >> > + >> > +@interface NSCountedSet : NSMutableSet >> > + >> > +@end >> > + >> > +@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; >> > + >> > +@end >> > + >> > +@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}} >> > +} >> > +@end >> > + >> > +@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}} >> > +} >> > + >> > +@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 >> > [email protected] >> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >> > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
