r244193 - [ObjC] Circular containers: add support of subclasses

AlexDenisov 1101.debian at gmail.com
Wed Aug 5 21:54:27 PDT 2015


Hi, Hans.
The patch fixes crash reported by Argyrios.
Might be a candidate for release_37.
--
AlexDenisov
Software Engineer, http://lowlevelbits.org

> On 06 Aug 2015, at 06:51, Alex Denisov <1101.debian at gmail.com> wrote:
> 
> Author: alexdenisov
> Date: Wed Aug  5 23:51:14 2015
> New Revision: 244193
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=244193&view=rev
> Log:
> [ObjC] Circular containers: add support of subclasses
> 
> 
> 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/test/SemaObjC/circular-container.m
> 
> Modified: cfe/trunk/include/clang/AST/NSAPI.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NSAPI.h?rev=244193&r1=244192&r2=244193&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/NSAPI.h (original)
> +++ cfe/trunk/include/clang/AST/NSAPI.h Wed Aug  5 23:51:14 2015
> @@ -16,6 +16,7 @@
> 
> namespace clang {
>   class ASTContext;
> +  class ObjCInterfaceDecl;
>   class QualType;
>   class Expr;
> 
> @@ -35,11 +36,10 @@ public:
>     ClassId_NSMutableDictionary,
>     ClassId_NSNumber,
>     ClassId_NSMutableSet,
> -    ClassId_NSCountedSet,
>     ClassId_NSMutableOrderedSet,
>     ClassId_NSValue
>   };
> -  static const unsigned NumClassIds = 11;
> +  static const unsigned NumClassIds = 10;
> 
>   enum NSStringMethodKind {
>     NSStr_stringWithString,
> @@ -220,6 +220,10 @@ public:
>   /// \brief Returns \c true if \p Id is currently defined as a macro.
>   bool isMacroDefined(StringRef Id) const;
> 
> +  /// \brief Returns \c true if \p InterfaceDecl is subclass of \p NSClassKind
> +  bool isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl,
> +                           NSClassIdKindKind NSClassKind) const;
> +
> private:
>   bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const;
>   bool isObjCEnumerator(const Expr *E,
> 
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=244193&r1=244192&r2=244193&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Aug  5 23:51:14 2015
> @@ -5370,7 +5370,7 @@ def err_objc_object_catch : Error<
> 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">,
> +  "adding '%0' to '%1' might cause circular dependency in container">,
>   InGroup<DiagGroup<"objc-circular-container">>;
> def note_objc_circular_container_declared_here : Note<"'%0' declared here">;
> 
> 
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=244193&r1=244192&r2=244193&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Wed Aug  5 23:51:14 2015
> @@ -729,27 +729,12 @@ 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;
> 
> 
> Modified: cfe/trunk/lib/AST/NSAPI.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?rev=244193&r1=244192&r2=244193&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/NSAPI.cpp (original)
> +++ cfe/trunk/lib/AST/NSAPI.cpp Wed Aug  5 23:51:14 2015
> @@ -9,6 +9,7 @@
> 
> #include "clang/AST/NSAPI.h"
> #include "clang/AST/ASTContext.h"
> +#include "clang/AST/DeclObjC.h"
> #include "clang/AST/Expr.h"
> #include "llvm/ADT/StringSwitch.h"
> 
> @@ -29,7 +30,6 @@ IdentifierInfo *NSAPI::getNSClassId(NSCl
>     "NSMutableDictionary",
>     "NSNumber",
>     "NSMutableSet",
> -    "NSCountedSet",
>     "NSMutableOrderedSet",
>     "NSValue"
>   };
> @@ -511,6 +511,26 @@ bool NSAPI::isMacroDefined(StringRef Id)
>   return Ctx.Idents.get(Id).hasMacroDefinition();
> }
> 
> +bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl,
> +                                NSClassIdKindKind NSClassKind) const {
> +  if (!InterfaceDecl) {
> +    return false;
> +  }
> +
> +  IdentifierInfo *NSClassID = getNSClassId(NSClassKind);
> +
> +  bool IsSubclass = false;
> +  do {
> +    IsSubclass = NSClassID == InterfaceDecl->getIdentifier();
> +
> +    if (IsSubclass) {
> +      break;
> +    }
> +  } while ((InterfaceDecl = InterfaceDecl->getSuperClass()));
> +
> +  return IsSubclass;
> +}
> +
> bool NSAPI::isObjCTypedef(QualType T,
>                           StringRef name, IdentifierInfo *&II) const {
>   if (!Ctx.getLangOpts().ObjC1)
> 
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=244193&r1=244192&r2=244193&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Aug  5 23:51:14 2015
> @@ -8727,23 +8727,10 @@ static bool isSetterLikeSelector(Selecto
> 
> static 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()) {
> +  bool IsMutableArray = S.NSAPIObj->isSubclassOfNSClass(
> +                                                Message->getReceiverInterface(),
> +                                                NSAPI::ClassId_NSMutableArray);
> +  if (!IsMutableArray) {
>     return None;
>   }
> 
> @@ -8775,24 +8762,10 @@ static Optional<int> GetNSMutableArrayAr
> 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()) {
> +  bool IsMutableDictionary = S.NSAPIObj->isSubclassOfNSClass(
> +                                            Message->getReceiverInterface(),
> +                                            NSAPI::ClassId_NSMutableDictionary);
> +  if (!IsMutableDictionary) {
>     return None;
>   }
> 
> @@ -8820,63 +8793,14 @@ Optional<int> GetNSMutableDictionaryArgu
> }
> 
> 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) {
> +  bool IsMutableSet = S.NSAPIObj->isSubclassOfNSClass(
> +                                                Message->getReceiverInterface(),
> +                                                NSAPI::ClassId_NSMutableSet);
> +
> +  bool IsMutableOrderedSet = S.NSAPIObj->isSubclassOfNSClass(
> +                                            Message->getReceiverInterface(),
> +                                            NSAPI::ClassId_NSMutableOrderedSet);
> +  if (!IsMutableSet && !IsMutableOrderedSet) {
>     return None;
>   }
> 
> @@ -8917,38 +8841,51 @@ void Sema::CheckObjCCircularContainer(Ob
> 
>   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 (Message->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
>     if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) {
> -      if (ReceiverRE->getDecl() == ArgRE->getDecl()) {
> -        ValueDecl *Decl = ReceiverRE->getDecl();
> +      if (ArgRE->isObjCSelfExpr()) {
>         Diag(Message->getSourceRange().getBegin(),
>              diag::warn_objc_circular_container)
> -          << Decl->getName();
> -        Diag(Decl->getLocation(),
> -             diag::note_objc_circular_container_declared_here)
> -          << Decl->getName();
> +          << ArgRE->getDecl()->getName() << StringRef("super");
>       }
>     }
> -  } 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();
> +  } else {
> +    Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts();
> +
> +    if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) {
> +      Receiver = 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() << Decl->getName();
> +          if (!ArgRE->isObjCSelfExpr()) {
> +            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() << Decl->getName();
> +          Diag(Decl->getLocation(),
> +               diag::note_objc_circular_container_declared_here)
> +            << Decl->getName();
> +        }
>       }
>     }
>   }
> 
> Modified: cfe/trunk/test/SemaObjC/circular-container.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/circular-container.m?rev=244193&r1=244192&r2=244193&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaObjC/circular-container.m (original)
> +++ cfe/trunk/test/SemaObjC/circular-container.m Wed Aug  5 23:51:14 2015
> @@ -144,3 +144,64 @@ void checkNSMutableOrderedSet() {
>   [s replaceObjectAtIndex:0 withObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}
> }
> 
> +// Test subclassing
> +
> + at interface FootableSet : NSMutableSet
> + at end
> +
> + at implementation FootableSet
> +- (void)meth {
> +  [super addObject:self]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}}
> +  [super addObject:nil]; // no-warning
> +  [self addObject:self]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}}
> +}
> + at end
> +
> + at interface FootableArray : NSMutableArray
> + at end
> +
> + at implementation FootableArray
> +- (void)meth {
> +  [super addObject:self]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}}
> +  [super addObject:nil]; // no-warning
> +  [self addObject:self]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}}
> +}
> + at end
> +
> + at interface FootableDictionary : NSMutableDictionary
> + at end
> +
> + at implementation FootableDictionary
> +- (void)meth {
> +  [super setObject:self forKey:@"key"]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}}
> +  [super setObject:nil forKey:@"key"]; // no-warning
> +  [self setObject:self forKey:@"key"]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}}
> +}
> + at end
> +
> +
> +void subclassingNSMutableArray() {
> +  FootableArray *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 subclassingNSMutableDictionary() {
> +  FootableDictionary *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 subclassingNSMutableSet() {
> +  FootableSet *s = nil; // expected-note {{'s' declared here}}
> +
> +  [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}
> +}
> +
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 496 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150806/89024de5/attachment-0001.sig>


More information about the cfe-commits mailing list