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