Home | History | Annotate | Download | only in Checkers
      1 //=- IvarInvalidationChecker.cpp - -*- C++ -------------------------------*-==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This checker implements annotation driven invalidation checking. If a class
     11 //  contains a method annotated with 'objc_instance_variable_invalidator',
     12 //  - (void) foo
     13 //           __attribute__((annotate("objc_instance_variable_invalidator")));
     14 //  all the "ivalidatable" instance variables of this class should be
     15 //  invalidated. We call an instance variable ivalidatable if it is an object of
     16 //  a class which contains an invalidation method. There could be multiple
     17 //  methods annotated with such annotations per class, either one can be used
     18 //  to invalidate the ivar. An ivar or property are considered to be
     19 //  invalidated if they are being assigned 'nil' or an invalidation method has
     20 //  been called on them. An invalidation method should either invalidate all
     21 //  the ivars or call another invalidation method (on self).
     22 //
     23 //  Partial invalidor annotation allows to addess cases when ivars are
     24 //  invalidated by other methods, which might or might not be called from
     25 //  the invalidation method. The checker checks that each invalidation
     26 //  method and all the partial methods cumulatively invalidate all ivars.
     27 //    __attribute__((annotate("objc_instance_variable_invalidator_partial")));
     28 //
     29 //===----------------------------------------------------------------------===//
     30 
     31 #include "ClangSACheckers.h"
     32 #include "clang/AST/Attr.h"
     33 #include "clang/AST/DeclObjC.h"
     34 #include "clang/AST/StmtVisitor.h"
     35 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
     36 #include "clang/StaticAnalyzer/Core/Checker.h"
     37 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
     38 #include "llvm/ADT/DenseMap.h"
     39 #include "llvm/ADT/SetVector.h"
     40 #include "llvm/ADT/SmallString.h"
     41 
     42 using namespace clang;
     43 using namespace ento;
     44 
     45 namespace {
     46 
     47 struct ChecksFilter {
     48   /// Check for missing invalidation method declarations.
     49   DefaultBool check_MissingInvalidationMethod;
     50   /// Check that all ivars are invalidated.
     51   DefaultBool check_InstanceVariableInvalidation;
     52 };
     53 
     54 class IvarInvalidationCheckerImpl {
     55 
     56   typedef llvm::SmallSetVector<const ObjCMethodDecl*, 2> MethodSet;
     57   typedef llvm::DenseMap<const ObjCMethodDecl*,
     58                          const ObjCIvarDecl*> MethToIvarMapTy;
     59   typedef llvm::DenseMap<const ObjCPropertyDecl*,
     60                          const ObjCIvarDecl*> PropToIvarMapTy;
     61   typedef llvm::DenseMap<const ObjCIvarDecl*,
     62                          const ObjCPropertyDecl*> IvarToPropMapTy;
     63 
     64 
     65   struct InvalidationInfo {
     66     /// Has the ivar been invalidated?
     67     bool IsInvalidated;
     68 
     69     /// The methods which can be used to invalidate the ivar.
     70     MethodSet InvalidationMethods;
     71 
     72     InvalidationInfo() : IsInvalidated(false) {}
     73     void addInvalidationMethod(const ObjCMethodDecl *MD) {
     74       InvalidationMethods.insert(MD);
     75     }
     76 
     77     bool needsInvalidation() const {
     78       return !InvalidationMethods.empty();
     79     }
     80 
     81     bool hasMethod(const ObjCMethodDecl *MD) {
     82       if (IsInvalidated)
     83         return true;
     84       for (MethodSet::iterator I = InvalidationMethods.begin(),
     85           E = InvalidationMethods.end(); I != E; ++I) {
     86         if (*I == MD) {
     87           IsInvalidated = true;
     88           return true;
     89         }
     90       }
     91       return false;
     92     }
     93   };
     94 
     95   typedef llvm::DenseMap<const ObjCIvarDecl*, InvalidationInfo> IvarSet;
     96 
     97   /// Statement visitor, which walks the method body and flags the ivars
     98   /// referenced in it (either directly or via property).
     99   class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
    100     /// The set of Ivars which need to be invalidated.
    101     IvarSet &IVars;
    102 
    103     /// Flag is set as the result of a message send to another
    104     /// invalidation method.
    105     bool &CalledAnotherInvalidationMethod;
    106 
    107     /// Property setter to ivar mapping.
    108     const MethToIvarMapTy &PropertySetterToIvarMap;
    109 
    110     /// Property getter to ivar mapping.
    111     const MethToIvarMapTy &PropertyGetterToIvarMap;
    112 
    113     /// Property to ivar mapping.
    114     const PropToIvarMapTy &PropertyToIvarMap;
    115 
    116     /// The invalidation method being currently processed.
    117     const ObjCMethodDecl *InvalidationMethod;
    118 
    119     ASTContext &Ctx;
    120 
    121     /// Peel off parens, casts, OpaqueValueExpr, and PseudoObjectExpr.
    122     const Expr *peel(const Expr *E) const;
    123 
    124     /// Does this expression represent zero: '0'?
    125     bool isZero(const Expr *E) const;
    126 
    127     /// Mark the given ivar as invalidated.
    128     void markInvalidated(const ObjCIvarDecl *Iv);
    129 
    130     /// Checks if IvarRef refers to the tracked IVar, if yes, marks it as
    131     /// invalidated.
    132     void checkObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef);
    133 
    134     /// Checks if ObjCPropertyRefExpr refers to the tracked IVar, if yes, marks
    135     /// it as invalidated.
    136     void checkObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA);
    137 
    138     /// Checks if ObjCMessageExpr refers to (is a getter for) the tracked IVar,
    139     /// if yes, marks it as invalidated.
    140     void checkObjCMessageExpr(const ObjCMessageExpr *ME);
    141 
    142     /// Checks if the Expr refers to an ivar, if yes, marks it as invalidated.
    143     void check(const Expr *E);
    144 
    145   public:
    146     MethodCrawler(IvarSet &InIVars,
    147                   bool &InCalledAnotherInvalidationMethod,
    148                   const MethToIvarMapTy &InPropertySetterToIvarMap,
    149                   const MethToIvarMapTy &InPropertyGetterToIvarMap,
    150                   const PropToIvarMapTy &InPropertyToIvarMap,
    151                   ASTContext &InCtx)
    152     : IVars(InIVars),
    153       CalledAnotherInvalidationMethod(InCalledAnotherInvalidationMethod),
    154       PropertySetterToIvarMap(InPropertySetterToIvarMap),
    155       PropertyGetterToIvarMap(InPropertyGetterToIvarMap),
    156       PropertyToIvarMap(InPropertyToIvarMap),
    157       InvalidationMethod(0),
    158       Ctx(InCtx) {}
    159 
    160     void VisitStmt(const Stmt *S) { VisitChildren(S); }
    161 
    162     void VisitBinaryOperator(const BinaryOperator *BO);
    163 
    164     void VisitObjCMessageExpr(const ObjCMessageExpr *ME);
    165 
    166     void VisitChildren(const Stmt *S) {
    167       for (Stmt::const_child_range I = S->children(); I; ++I) {
    168         if (*I)
    169           this->Visit(*I);
    170         if (CalledAnotherInvalidationMethod)
    171           return;
    172       }
    173     }
    174   };
    175 
    176   /// Check if the any of the methods inside the interface are annotated with
    177   /// the invalidation annotation, update the IvarInfo accordingly.
    178   /// \param LookForPartial is set when we are searching for partial
    179   ///        invalidators.
    180   static void containsInvalidationMethod(const ObjCContainerDecl *D,
    181                                          InvalidationInfo &Out,
    182                                          bool LookForPartial);
    183 
    184   /// Check if ivar should be tracked and add to TrackedIvars if positive.
    185   /// Returns true if ivar should be tracked.
    186   static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars,
    187                         const ObjCIvarDecl **FirstIvarDecl);
    188 
    189   /// Given the property declaration, and the list of tracked ivars, finds
    190   /// the ivar backing the property when possible. Returns '0' when no such
    191   /// ivar could be found.
    192   static const ObjCIvarDecl *findPropertyBackingIvar(
    193       const ObjCPropertyDecl *Prop,
    194       const ObjCInterfaceDecl *InterfaceD,
    195       IvarSet &TrackedIvars,
    196       const ObjCIvarDecl **FirstIvarDecl);
    197 
    198   /// Print ivar name or the property if the given ivar backs a property.
    199   static void printIvar(llvm::raw_svector_ostream &os,
    200                         const ObjCIvarDecl *IvarDecl,
    201                         const IvarToPropMapTy &IvarToPopertyMap);
    202 
    203   void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
    204                                   const IvarToPropMapTy &IvarToPopertyMap,
    205                                   const ObjCInterfaceDecl *InterfaceD,
    206                                   bool MissingDeclaration) const;
    207   void reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
    208                                    const IvarToPropMapTy &IvarToPopertyMap,
    209                                    const ObjCMethodDecl *MethodD) const;
    210 
    211   AnalysisManager& Mgr;
    212   BugReporter &BR;
    213   /// Filter on the checks performed.
    214   const ChecksFilter &Filter;
    215 
    216 public:
    217   IvarInvalidationCheckerImpl(AnalysisManager& InMgr,
    218                               BugReporter &InBR,
    219                               const ChecksFilter &InFilter) :
    220     Mgr (InMgr), BR(InBR), Filter(InFilter) {}
    221 
    222   void visit(const ObjCImplementationDecl *D) const;
    223 };
    224 
    225 static bool isInvalidationMethod(const ObjCMethodDecl *M, bool LookForPartial) {
    226   for (specific_attr_iterator<AnnotateAttr>
    227        AI = M->specific_attr_begin<AnnotateAttr>(),
    228        AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
    229     const AnnotateAttr *Ann = *AI;
    230     if (!LookForPartial &&
    231         Ann->getAnnotation() == "objc_instance_variable_invalidator")
    232       return true;
    233     if (LookForPartial &&
    234         Ann->getAnnotation() == "objc_instance_variable_invalidator_partial")
    235       return true;
    236   }
    237   return false;
    238 }
    239 
    240 void IvarInvalidationCheckerImpl::containsInvalidationMethod(
    241     const ObjCContainerDecl *D, InvalidationInfo &OutInfo, bool Partial) {
    242 
    243   if (!D)
    244     return;
    245 
    246   assert(!isa<ObjCImplementationDecl>(D));
    247   // TODO: Cache the results.
    248 
    249   // Check all methods.
    250   for (ObjCContainerDecl::method_iterator
    251       I = D->meth_begin(),
    252       E = D->meth_end(); I != E; ++I) {
    253       const ObjCMethodDecl *MDI = *I;
    254       if (isInvalidationMethod(MDI, Partial))
    255         OutInfo.addInvalidationMethod(
    256                                cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
    257   }
    258 
    259   // If interface, check all parent protocols and super.
    260   if (const ObjCInterfaceDecl *InterfD = dyn_cast<ObjCInterfaceDecl>(D)) {
    261 
    262     // Visit all protocols.
    263     for (ObjCInterfaceDecl::protocol_iterator
    264         I = InterfD->protocol_begin(),
    265         E = InterfD->protocol_end(); I != E; ++I) {
    266       containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
    267     }
    268 
    269     // Visit all categories in case the invalidation method is declared in
    270     // a category.
    271     for (ObjCInterfaceDecl::visible_extensions_iterator
    272            Ext = InterfD->visible_extensions_begin(),
    273            ExtEnd = InterfD->visible_extensions_end();
    274          Ext != ExtEnd; ++Ext) {
    275       containsInvalidationMethod(*Ext, OutInfo, Partial);
    276     }
    277 
    278     containsInvalidationMethod(InterfD->getSuperClass(), OutInfo, Partial);
    279     return;
    280   }
    281 
    282   // If protocol, check all parent protocols.
    283   if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) {
    284     for (ObjCInterfaceDecl::protocol_iterator
    285         I = ProtD->protocol_begin(),
    286         E = ProtD->protocol_end(); I != E; ++I) {
    287       containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
    288     }
    289     return;
    290   }
    291 
    292   return;
    293 }
    294 
    295 bool IvarInvalidationCheckerImpl::trackIvar(const ObjCIvarDecl *Iv,
    296                                         IvarSet &TrackedIvars,
    297                                         const ObjCIvarDecl **FirstIvarDecl) {
    298   QualType IvQTy = Iv->getType();
    299   const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
    300   if (!IvTy)
    301     return false;
    302   const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl();
    303 
    304   InvalidationInfo Info;
    305   containsInvalidationMethod(IvInterf, Info, /*LookForPartial*/ false);
    306   if (Info.needsInvalidation()) {
    307     const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl());
    308     TrackedIvars[I] = Info;
    309     if (!*FirstIvarDecl)
    310       *FirstIvarDecl = I;
    311     return true;
    312   }
    313   return false;
    314 }
    315 
    316 const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
    317                         const ObjCPropertyDecl *Prop,
    318                         const ObjCInterfaceDecl *InterfaceD,
    319                         IvarSet &TrackedIvars,
    320                         const ObjCIvarDecl **FirstIvarDecl) {
    321   const ObjCIvarDecl *IvarD = 0;
    322 
    323   // Lookup for the synthesized case.
    324   IvarD = Prop->getPropertyIvarDecl();
    325   // We only track the ivars/properties that are defined in the current
    326   // class (not the parent).
    327   if (IvarD && IvarD->getContainingInterface() == InterfaceD) {
    328     if (TrackedIvars.count(IvarD)) {
    329       return IvarD;
    330     }
    331     // If the ivar is synthesized we still want to track it.
    332     if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl))
    333       return IvarD;
    334   }
    335 
    336   // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars.
    337   StringRef PropName = Prop->getIdentifier()->getName();
    338   for (IvarSet::const_iterator I = TrackedIvars.begin(),
    339                                E = TrackedIvars.end(); I != E; ++I) {
    340     const ObjCIvarDecl *Iv = I->first;
    341     StringRef IvarName = Iv->getName();
    342 
    343     if (IvarName == PropName)
    344       return Iv;
    345 
    346     SmallString<128> PropNameWithUnderscore;
    347     {
    348       llvm::raw_svector_ostream os(PropNameWithUnderscore);
    349       os << '_' << PropName;
    350     }
    351     if (IvarName == PropNameWithUnderscore.str())
    352       return Iv;
    353   }
    354 
    355   // Note, this is a possible source of false positives. We could look at the
    356   // getter implementation to find the ivar when its name is not derived from
    357   // the property name.
    358   return 0;
    359 }
    360 
    361 void IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os,
    362                                       const ObjCIvarDecl *IvarDecl,
    363                                       const IvarToPropMapTy &IvarToPopertyMap) {
    364   if (IvarDecl->getSynthesize()) {
    365     const ObjCPropertyDecl *PD = IvarToPopertyMap.lookup(IvarDecl);
    366     assert(PD &&"Do we synthesize ivars for something other than properties?");
    367     os << "Property "<< PD->getName() << " ";
    368   } else {
    369     os << "Instance variable "<< IvarDecl->getName() << " ";
    370   }
    371 }
    372 
    373 // Check that the invalidatable interfaces with ivars/properties implement the
    374 // invalidation methods.
    375 void IvarInvalidationCheckerImpl::
    376 visit(const ObjCImplementationDecl *ImplD) const {
    377   // Collect all ivars that need cleanup.
    378   IvarSet Ivars;
    379   // Record the first Ivar needing invalidation; used in reporting when only
    380   // one ivar is sufficient. Cannot grab the first on the Ivars set to ensure
    381   // deterministic output.
    382   const ObjCIvarDecl *FirstIvarDecl = 0;
    383   const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface();
    384 
    385   // Collect ivars declared in this class, its extensions and its implementation
    386   ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD);
    387   for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
    388        Iv= Iv->getNextIvar())
    389     trackIvar(Iv, Ivars, &FirstIvarDecl);
    390 
    391   // Construct Property/Property Accessor to Ivar maps to assist checking if an
    392   // ivar which is backing a property has been reset.
    393   MethToIvarMapTy PropSetterToIvarMap;
    394   MethToIvarMapTy PropGetterToIvarMap;
    395   PropToIvarMapTy PropertyToIvarMap;
    396   IvarToPropMapTy IvarToPopertyMap;
    397 
    398   ObjCInterfaceDecl::PropertyMap PropMap;
    399   ObjCInterfaceDecl::PropertyDeclOrder PropOrder;
    400   InterfaceD->collectPropertiesToImplement(PropMap, PropOrder);
    401 
    402   for (ObjCInterfaceDecl::PropertyMap::iterator
    403       I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
    404     const ObjCPropertyDecl *PD = I->second;
    405 
    406     const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars,
    407                                                      &FirstIvarDecl);
    408     if (!ID)
    409       continue;
    410 
    411     // Store the mappings.
    412     PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
    413     PropertyToIvarMap[PD] = ID;
    414     IvarToPopertyMap[ID] = PD;
    415 
    416     // Find the setter and the getter.
    417     const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl();
    418     if (SetterD) {
    419       SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl());
    420       PropSetterToIvarMap[SetterD] = ID;
    421     }
    422 
    423     const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl();
    424     if (GetterD) {
    425       GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl());
    426       PropGetterToIvarMap[GetterD] = ID;
    427     }
    428   }
    429 
    430   // If no ivars need invalidation, there is nothing to check here.
    431   if (Ivars.empty())
    432     return;
    433 
    434   // Find all partial invalidation methods.
    435   InvalidationInfo PartialInfo;
    436   containsInvalidationMethod(InterfaceD, PartialInfo, /*LookForPartial*/ true);
    437 
    438   // Remove ivars invalidated by the partial invalidation methods. They do not
    439   // need to be invalidated in the regular invalidation methods.
    440   for (MethodSet::iterator
    441       I = PartialInfo.InvalidationMethods.begin(),
    442       E = PartialInfo.InvalidationMethods.end(); I != E; ++I) {
    443     const ObjCMethodDecl *InterfD = *I;
    444 
    445     // Get the corresponding method in the @implementation.
    446     const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
    447                                                InterfD->isInstanceMethod());
    448     if (D && D->hasBody()) {
    449       bool CalledAnotherInvalidationMethod = false;
    450       // The MethodCrowler is going to remove the invalidated ivars.
    451       MethodCrawler(Ivars,
    452                     CalledAnotherInvalidationMethod,
    453                     PropSetterToIvarMap,
    454                     PropGetterToIvarMap,
    455                     PropertyToIvarMap,
    456                     BR.getContext()).VisitStmt(D->getBody());
    457       // If another invalidation method was called, trust that full invalidation
    458       // has occurred.
    459       if (CalledAnotherInvalidationMethod)
    460         Ivars.clear();
    461     }
    462   }
    463 
    464   // If all ivars have been invalidated by partial invalidators, there is
    465   // nothing to check here.
    466   if (Ivars.empty())
    467     return;
    468 
    469   // Find all invalidation methods in this @interface declaration and parents.
    470   InvalidationInfo Info;
    471   containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
    472 
    473   // Report an error in case none of the invalidation methods are declared.
    474   if (!Info.needsInvalidation()) {
    475     if (Filter.check_MissingInvalidationMethod)
    476       reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
    477                                  /*MissingDeclaration*/ true);
    478     // If there are no invalidation methods, there is no ivar validation work
    479     // to be done.
    480     return;
    481   }
    482 
    483   // Only check if Ivars are invalidated when InstanceVariableInvalidation
    484   // has been requested.
    485   if (!Filter.check_InstanceVariableInvalidation)
    486     return;
    487 
    488   // Check that all ivars are invalidated by the invalidation methods.
    489   bool AtImplementationContainsAtLeastOneInvalidationMethod = false;
    490   for (MethodSet::iterator I = Info.InvalidationMethods.begin(),
    491                            E = Info.InvalidationMethods.end(); I != E; ++I) {
    492     const ObjCMethodDecl *InterfD = *I;
    493 
    494     // Get the corresponding method in the @implementation.
    495     const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
    496                                                InterfD->isInstanceMethod());
    497     if (D && D->hasBody()) {
    498       AtImplementationContainsAtLeastOneInvalidationMethod = true;
    499 
    500       // Get a copy of ivars needing invalidation.
    501       IvarSet IvarsI = Ivars;
    502 
    503       bool CalledAnotherInvalidationMethod = false;
    504       MethodCrawler(IvarsI,
    505                     CalledAnotherInvalidationMethod,
    506                     PropSetterToIvarMap,
    507                     PropGetterToIvarMap,
    508                     PropertyToIvarMap,
    509                     BR.getContext()).VisitStmt(D->getBody());
    510       // If another invalidation method was called, trust that full invalidation
    511       // has occurred.
    512       if (CalledAnotherInvalidationMethod)
    513         continue;
    514 
    515       // Warn on the ivars that were not invalidated by the method.
    516       for (IvarSet::const_iterator
    517           I = IvarsI.begin(), E = IvarsI.end(); I != E; ++I)
    518         reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, D);
    519     }
    520   }
    521 
    522   // Report an error in case none of the invalidation methods are implemented.
    523   if (!AtImplementationContainsAtLeastOneInvalidationMethod)
    524     reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
    525                                /*MissingDeclaration*/ false);
    526 }
    527 
    528 void IvarInvalidationCheckerImpl::
    529 reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
    530                            const IvarToPropMapTy &IvarToPopertyMap,
    531                            const ObjCInterfaceDecl *InterfaceD,
    532                            bool MissingDeclaration) const {
    533   SmallString<128> sbuf;
    534   llvm::raw_svector_ostream os(sbuf);
    535   assert(FirstIvarDecl);
    536   printIvar(os, FirstIvarDecl, IvarToPopertyMap);
    537   os << "needs to be invalidated; ";
    538   if (MissingDeclaration)
    539     os << "no invalidation method is declared for ";
    540   else
    541     os << "no invalidation method is defined in the @implementation for ";
    542   os << InterfaceD->getName();
    543 
    544   PathDiagnosticLocation IvarDecLocation =
    545     PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager());
    546 
    547   BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
    548                      categories::CoreFoundationObjectiveC, os.str(),
    549                      IvarDecLocation);
    550 }
    551 
    552 void IvarInvalidationCheckerImpl::
    553 reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
    554                                     const IvarToPropMapTy &IvarToPopertyMap,
    555                                     const ObjCMethodDecl *MethodD) const {
    556   SmallString<128> sbuf;
    557   llvm::raw_svector_ostream os(sbuf);
    558   printIvar(os, IvarD, IvarToPopertyMap);
    559   os << "needs to be invalidated or set to nil";
    560   PathDiagnosticLocation MethodDecLocation =
    561                          PathDiagnosticLocation::createEnd(MethodD->getBody(),
    562                          BR.getSourceManager(),
    563                          Mgr.getAnalysisDeclContext(MethodD));
    564   BR.EmitBasicReport(MethodD, "Incomplete invalidation",
    565                      categories::CoreFoundationObjectiveC, os.str(),
    566                      MethodDecLocation);
    567 }
    568 
    569 void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated(
    570     const ObjCIvarDecl *Iv) {
    571   IvarSet::iterator I = IVars.find(Iv);
    572   if (I != IVars.end()) {
    573     // If InvalidationMethod is present, we are processing the message send and
    574     // should ensure we are invalidating with the appropriate method,
    575     // otherwise, we are processing setting to 'nil'.
    576     if (!InvalidationMethod ||
    577         (InvalidationMethod && I->second.hasMethod(InvalidationMethod)))
    578       IVars.erase(I);
    579   }
    580 }
    581 
    582 const Expr *IvarInvalidationCheckerImpl::MethodCrawler::peel(const Expr *E) const {
    583   E = E->IgnoreParenCasts();
    584   if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
    585     E = POE->getSyntacticForm()->IgnoreParenCasts();
    586   if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
    587     E = OVE->getSourceExpr()->IgnoreParenCasts();
    588   return E;
    589 }
    590 
    591 void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCIvarRefExpr(
    592     const ObjCIvarRefExpr *IvarRef) {
    593   if (const Decl *D = IvarRef->getDecl())
    594     markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
    595 }
    596 
    597 void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCMessageExpr(
    598     const ObjCMessageExpr *ME) {
    599   const ObjCMethodDecl *MD = ME->getMethodDecl();
    600   if (MD) {
    601     MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
    602     MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD);
    603     if (IvI != PropertyGetterToIvarMap.end())
    604       markInvalidated(IvI->second);
    605   }
    606 }
    607 
    608 void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCPropertyRefExpr(
    609     const ObjCPropertyRefExpr *PA) {
    610 
    611   if (PA->isExplicitProperty()) {
    612     const ObjCPropertyDecl *PD = PA->getExplicitProperty();
    613     if (PD) {
    614       PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
    615       PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD);
    616       if (IvI != PropertyToIvarMap.end())
    617         markInvalidated(IvI->second);
    618       return;
    619     }
    620   }
    621 
    622   if (PA->isImplicitProperty()) {
    623     const ObjCMethodDecl *MD = PA->getImplicitPropertySetter();
    624     if (MD) {
    625       MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
    626       MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD);
    627       if (IvI != PropertyGetterToIvarMap.end())
    628         markInvalidated(IvI->second);
    629       return;
    630     }
    631   }
    632 }
    633 
    634 bool IvarInvalidationCheckerImpl::MethodCrawler::isZero(const Expr *E) const {
    635   E = peel(E);
    636 
    637   return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)
    638            != Expr::NPCK_NotNull);
    639 }
    640 
    641 void IvarInvalidationCheckerImpl::MethodCrawler::check(const Expr *E) {
    642   E = peel(E);
    643 
    644   if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
    645     checkObjCIvarRefExpr(IvarRef);
    646     return;
    647   }
    648 
    649   if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) {
    650     checkObjCPropertyRefExpr(PropRef);
    651     return;
    652   }
    653 
    654   if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
    655     checkObjCMessageExpr(MsgExpr);
    656     return;
    657   }
    658 }
    659 
    660 void IvarInvalidationCheckerImpl::MethodCrawler::VisitBinaryOperator(
    661     const BinaryOperator *BO) {
    662   VisitStmt(BO);
    663 
    664   // Do we assign/compare against zero? If yes, check the variable we are
    665   // assigning to.
    666   BinaryOperatorKind Opcode = BO->getOpcode();
    667   if (Opcode != BO_Assign &&
    668       Opcode != BO_EQ &&
    669       Opcode != BO_NE)
    670     return;
    671 
    672   if (isZero(BO->getRHS())) {
    673       check(BO->getLHS());
    674       return;
    675   }
    676 
    677   if (Opcode != BO_Assign && isZero(BO->getLHS())) {
    678     check(BO->getRHS());
    679     return;
    680   }
    681 }
    682 
    683 void IvarInvalidationCheckerImpl::MethodCrawler::VisitObjCMessageExpr(
    684   const ObjCMessageExpr *ME) {
    685   const ObjCMethodDecl *MD = ME->getMethodDecl();
    686   const Expr *Receiver = ME->getInstanceReceiver();
    687 
    688   // Stop if we are calling '[self invalidate]'.
    689   if (Receiver && isInvalidationMethod(MD, /*LookForPartial*/ false))
    690     if (Receiver->isObjCSelfExpr()) {
    691       CalledAnotherInvalidationMethod = true;
    692       return;
    693     }
    694 
    695   // Check if we call a setter and set the property to 'nil'.
    696   if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) {
    697     MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
    698     MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD);
    699     if (IvI != PropertySetterToIvarMap.end()) {
    700       markInvalidated(IvI->second);
    701       return;
    702     }
    703   }
    704 
    705   // Check if we call the 'invalidation' routine on the ivar.
    706   if (Receiver) {
    707     InvalidationMethod = MD;
    708     check(Receiver->IgnoreParenCasts());
    709     InvalidationMethod = 0;
    710   }
    711 
    712   VisitStmt(ME);
    713 }
    714 }
    715 
    716 // Register the checkers.
    717 namespace {
    718 
    719 class IvarInvalidationChecker :
    720   public Checker<check::ASTDecl<ObjCImplementationDecl> > {
    721 public:
    722   ChecksFilter Filter;
    723 public:
    724   void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
    725                     BugReporter &BR) const {
    726     IvarInvalidationCheckerImpl Walker(Mgr, BR, Filter);
    727     Walker.visit(D);
    728   }
    729 };
    730 }
    731 
    732 #define REGISTER_CHECKER(name) \
    733 void ento::register##name(CheckerManager &mgr) {\
    734   mgr.registerChecker<IvarInvalidationChecker>()->Filter.check_##name = true;\
    735 }
    736 
    737 REGISTER_CHECKER(InstanceVariableInvalidation)
    738 REGISTER_CHECKER(MissingInvalidationMethod)
    739 
    740