IvarInvalidationChecker.cpp revision 79ccd5635495fb4588d0ec47c0bf05764441a14c
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 36using namespace clang; 37using namespace ento; 38 39namespace { 40class 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); 194public: 195 void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr, 196 BugReporter &BR) const; 197}; 198 199static 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 210void 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 (const ObjCCategoryDecl *I = InterfD->getFirstClassExtension(); I; 242 I = I->getNextClassExtension()) { 243 containsInvalidationMethod(I, OutInfo); 244 } 245 246 containsInvalidationMethod(InterfD->getSuperClass(), OutInfo); 247 return; 248 } 249 250 // If protocol, check all parent protocols. 251 if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) { 252 for (ObjCInterfaceDecl::protocol_iterator 253 I = ProtD->protocol_begin(), 254 E = ProtD->protocol_end(); I != E; ++I) { 255 containsInvalidationMethod((*I)->getDefinition(), OutInfo); 256 } 257 return; 258 } 259 260 return; 261} 262 263bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv, 264 IvarSet &TrackedIvars, 265 const ObjCIvarDecl **FirstIvarDecl) { 266 QualType IvQTy = Iv->getType(); 267 const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); 268 if (!IvTy) 269 return false; 270 const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); 271 272 InvalidationInfo Info; 273 containsInvalidationMethod(IvInterf, Info); 274 if (Info.needsInvalidation()) { 275 const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl()); 276 TrackedIvars[I] = Info; 277 if (!*FirstIvarDecl) 278 *FirstIvarDecl = I; 279 return true; 280 } 281 return false; 282} 283 284const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar( 285 const ObjCPropertyDecl *Prop, 286 const ObjCInterfaceDecl *InterfaceD, 287 IvarSet &TrackedIvars, 288 const ObjCIvarDecl **FirstIvarDecl) { 289 const ObjCIvarDecl *IvarD = 0; 290 291 // Lookup for the synthesized case. 292 IvarD = Prop->getPropertyIvarDecl(); 293 // We only track the ivars/properties that are defined in the current 294 // class (not the parent). 295 if (IvarD && IvarD->getContainingInterface() == InterfaceD) { 296 if (TrackedIvars.count(IvarD)) { 297 return IvarD; 298 } 299 // If the ivar is synthesized we still want to track it. 300 if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl)) 301 return IvarD; 302 } 303 304 // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars. 305 StringRef PropName = Prop->getIdentifier()->getName(); 306 for (IvarSet::const_iterator I = TrackedIvars.begin(), 307 E = TrackedIvars.end(); I != E; ++I) { 308 const ObjCIvarDecl *Iv = I->first; 309 StringRef IvarName = Iv->getName(); 310 311 if (IvarName == PropName) 312 return Iv; 313 314 SmallString<128> PropNameWithUnderscore; 315 { 316 llvm::raw_svector_ostream os(PropNameWithUnderscore); 317 os << '_' << PropName; 318 } 319 if (IvarName == PropNameWithUnderscore.str()) 320 return Iv; 321 } 322 323 // Note, this is a possible source of false positives. We could look at the 324 // getter implementation to find the ivar when its name is not derived from 325 // the property name. 326 return 0; 327} 328 329void IvarInvalidationChecker::printIvar(llvm::raw_svector_ostream &os, 330 const ObjCIvarDecl *IvarDecl, 331 IvarToPropMapTy &IvarToPopertyMap) { 332 if (IvarDecl->getSynthesize()) { 333 const ObjCPropertyDecl *PD = IvarToPopertyMap[IvarDecl]; 334 assert(PD &&"Do we synthesize ivars for something other than properties?"); 335 os << "Property "<< PD->getName() << " "; 336 } else { 337 os << "Instance variable "<< IvarDecl->getName() << " "; 338 } 339} 340 341// Check that the invalidatable interfaces with ivars/properties implement the 342// invalidation methods. 343void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD, 344 AnalysisManager& Mgr, 345 BugReporter &BR) const { 346 // Collect all ivars that need cleanup. 347 IvarSet Ivars; 348 // Record the first Ivar needing invalidation; used in reporting when only 349 // one ivar is sufficient. Cannot grab the first on the Ivars set to ensure 350 // deterministic output. 351 const ObjCIvarDecl *FirstIvarDecl = 0; 352 const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface(); 353 354 // Collect ivars declared in this class, its extensions and its implementation 355 ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD); 356 for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; 357 Iv= Iv->getNextIvar()) 358 trackIvar(Iv, Ivars, &FirstIvarDecl); 359 360 // Construct Property/Property Accessor to Ivar maps to assist checking if an 361 // ivar which is backing a property has been reset. 362 MethToIvarMapTy PropSetterToIvarMap; 363 MethToIvarMapTy PropGetterToIvarMap; 364 PropToIvarMapTy PropertyToIvarMap; 365 IvarToPropMapTy IvarToPopertyMap; 366 367 ObjCInterfaceDecl::PropertyMap PropMap; 368 InterfaceD->collectPropertiesToImplement(PropMap); 369 370 for (ObjCInterfaceDecl::PropertyMap::iterator 371 I = PropMap.begin(), E = PropMap.end(); I != E; ++I) { 372 const ObjCPropertyDecl *PD = I->second; 373 374 const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars, 375 &FirstIvarDecl); 376 if (!ID) { 377 continue; 378 } 379 380 // Store the mappings. 381 PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); 382 PropertyToIvarMap[PD] = ID; 383 IvarToPopertyMap[ID] = PD; 384 385 // Find the setter and the getter. 386 const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); 387 if (SetterD) { 388 SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl()); 389 PropSetterToIvarMap[SetterD] = ID; 390 } 391 392 const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl(); 393 if (GetterD) { 394 GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl()); 395 PropGetterToIvarMap[GetterD] = ID; 396 } 397 } 398 399 // If no ivars need invalidation, there is nothing to check here. 400 if (Ivars.empty()) 401 return; 402 403 // Find all invalidation methods in this @interface declaration and parents. 404 InvalidationInfo Info; 405 containsInvalidationMethod(InterfaceD, Info); 406 407 // Report an error in case none of the invalidation methods are declared. 408 if (!Info.needsInvalidation()) { 409 SmallString<128> sbuf; 410 llvm::raw_svector_ostream os(sbuf); 411 assert(FirstIvarDecl); 412 printIvar(os, FirstIvarDecl, IvarToPopertyMap); 413 os << "needs to be invalidated; "; 414 os << "no invalidation method is declared for " << InterfaceD->getName(); 415 416 PathDiagnosticLocation IvarDecLocation = 417 PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager()); 418 419 BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation", 420 categories::CoreFoundationObjectiveC, os.str(), 421 IvarDecLocation); 422 return; 423 } 424 425 // Check that all ivars are invalidated by the invalidation methods. 426 bool AtImplementationContainsAtLeastOneInvalidationMethod = false; 427 for (MethodSet::iterator I = Info.InvalidationMethods.begin(), 428 E = Info.InvalidationMethods.end(); I != E; ++I) { 429 const ObjCMethodDecl *InterfD = *I; 430 431 // Get the corresponding method in the @implementation. 432 const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(), 433 InterfD->isInstanceMethod()); 434 if (D && D->hasBody()) { 435 AtImplementationContainsAtLeastOneInvalidationMethod = true; 436 437 // Get a copy of ivars needing invalidation. 438 IvarSet IvarsI = Ivars; 439 440 bool CalledAnotherInvalidationMethod = false; 441 MethodCrawler(IvarsI, 442 CalledAnotherInvalidationMethod, 443 PropSetterToIvarMap, 444 PropGetterToIvarMap, 445 PropertyToIvarMap, 446 BR.getContext()).VisitStmt(D->getBody()); 447 // If another invalidation method was called, trust that full invalidation 448 // has occurred. 449 if (CalledAnotherInvalidationMethod) 450 continue; 451 452 // Warn on the ivars that were not invalidated by the method. 453 for (IvarSet::const_iterator I = IvarsI.begin(), 454 E = IvarsI.end(); I != E; ++I) 455 if (!I->second.isInvalidated()) { 456 SmallString<128> sbuf; 457 llvm::raw_svector_ostream os(sbuf); 458 printIvar(os, I->first, IvarToPopertyMap); 459 os << "needs to be invalidated or set to nil"; 460 PathDiagnosticLocation MethodDecLocation = 461 PathDiagnosticLocation::createEnd(D->getBody(), 462 BR.getSourceManager(), 463 Mgr.getAnalysisDeclContext(D)); 464 BR.EmitBasicReport(D, "Incomplete invalidation", 465 categories::CoreFoundationObjectiveC, os.str(), 466 MethodDecLocation); 467 } 468 } 469 } 470 471 // Report an error in case none of the invalidation methods are implemented. 472 if (!AtImplementationContainsAtLeastOneInvalidationMethod) { 473 SmallString<128> sbuf; 474 llvm::raw_svector_ostream os(sbuf); 475 assert(FirstIvarDecl); 476 printIvar(os, FirstIvarDecl, IvarToPopertyMap); 477 os << "needs to be invalidated; "; 478 os << "no invalidation method is defined in the @implementation for " 479 << InterfaceD->getName(); 480 481 PathDiagnosticLocation IvarDecLocation = 482 PathDiagnosticLocation::createBegin(FirstIvarDecl, 483 BR.getSourceManager()); 484 BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation", 485 categories::CoreFoundationObjectiveC, os.str(), 486 IvarDecLocation); 487 } 488} 489 490void IvarInvalidationChecker::MethodCrawler::markInvalidated( 491 const ObjCIvarDecl *Iv) { 492 IvarSet::iterator I = IVars.find(Iv); 493 if (I != IVars.end()) { 494 // If InvalidationMethod is present, we are processing the message send and 495 // should ensure we are invalidating with the appropriate method, 496 // otherwise, we are processing setting to 'nil'. 497 if (InvalidationMethod) 498 I->second.markInvalidated(InvalidationMethod); 499 else 500 I->second.markInvalidated(); 501 } 502} 503 504const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const { 505 E = E->IgnoreParenCasts(); 506 if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) 507 E = POE->getSyntacticForm()->IgnoreParenCasts(); 508 if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) 509 E = OVE->getSourceExpr()->IgnoreParenCasts(); 510 return E; 511} 512 513void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr( 514 const ObjCIvarRefExpr *IvarRef) { 515 if (const Decl *D = IvarRef->getDecl()) 516 markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl())); 517} 518 519void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr( 520 const ObjCMessageExpr *ME) { 521 const ObjCMethodDecl *MD = ME->getMethodDecl(); 522 if (MD) { 523 MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 524 MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD); 525 if (IvI != PropertyGetterToIvarMap.end()) 526 markInvalidated(IvI->second); 527 } 528} 529 530void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr( 531 const ObjCPropertyRefExpr *PA) { 532 533 if (PA->isExplicitProperty()) { 534 const ObjCPropertyDecl *PD = PA->getExplicitProperty(); 535 if (PD) { 536 PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); 537 PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD); 538 if (IvI != PropertyToIvarMap.end()) 539 markInvalidated(IvI->second); 540 return; 541 } 542 } 543 544 if (PA->isImplicitProperty()) { 545 const ObjCMethodDecl *MD = PA->getImplicitPropertySetter(); 546 if (MD) { 547 MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 548 MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD); 549 if (IvI != PropertyGetterToIvarMap.end()) 550 markInvalidated(IvI->second); 551 return; 552 } 553 } 554} 555 556bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const { 557 E = peel(E); 558 559 return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull) 560 != Expr::NPCK_NotNull); 561} 562 563void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) { 564 E = peel(E); 565 566 if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { 567 checkObjCIvarRefExpr(IvarRef); 568 return; 569 } 570 571 if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) { 572 checkObjCPropertyRefExpr(PropRef); 573 return; 574 } 575 576 if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) { 577 checkObjCMessageExpr(MsgExpr); 578 return; 579 } 580} 581 582void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator( 583 const BinaryOperator *BO) { 584 VisitStmt(BO); 585 586 // Do we assign/compare against zero? If yes, check the variable we are 587 // assigning to. 588 BinaryOperatorKind Opcode = BO->getOpcode(); 589 if (Opcode != BO_Assign && 590 Opcode != BO_EQ && 591 Opcode != BO_NE) 592 return; 593 594 if (isZero(BO->getRHS())) { 595 check(BO->getLHS()); 596 return; 597 } 598 599 if (Opcode != BO_Assign && isZero(BO->getLHS())) { 600 check(BO->getRHS()); 601 return; 602 } 603} 604 605void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr( 606 const ObjCMessageExpr *ME) { 607 const ObjCMethodDecl *MD = ME->getMethodDecl(); 608 const Expr *Receiver = ME->getInstanceReceiver(); 609 610 // Stop if we are calling '[self invalidate]'. 611 if (Receiver && isInvalidationMethod(MD)) 612 if (Receiver->isObjCSelfExpr()) { 613 CalledAnotherInvalidationMethod = true; 614 return; 615 } 616 617 // Check if we call a setter and set the property to 'nil'. 618 if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) { 619 MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 620 MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD); 621 if (IvI != PropertySetterToIvarMap.end()) { 622 markInvalidated(IvI->second); 623 return; 624 } 625 } 626 627 // Check if we call the 'invalidation' routine on the ivar. 628 if (Receiver) { 629 InvalidationMethod = MD; 630 check(Receiver->IgnoreParenCasts()); 631 InvalidationMethod = 0; 632 } 633 634 VisitStmt(ME); 635} 636} 637 638// Register the checker. 639void ento::registerIvarInvalidationChecker(CheckerManager &mgr) { 640 mgr.registerChecker<IvarInvalidationChecker>(); 641} 642