r231265 - New ObjC warning: circular containers.
Hans Wennborg
hans at chromium.org
Wed Jul 29 11:54:37 PDT 2015
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 <1101.debian at gmail.com> wrote:
> 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> 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
>>
>
> _______________________________________________
> 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