IvarInvalidationChecker.cpp revision b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3
15bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks//=- IvarInvalidationChecker.cpp - -*- C++ ----*-==// 25bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 35bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// The LLVM Compiler Infrastructure 45bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 55bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// This file is distributed under the University of Illinois Open Source 65bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// License. See LICENSE.TXT for details. 75bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 85bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks//===----------------------------------------------------------------------===// 95bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 105bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// This checker implements annotation driven invalidation checking. If a class 115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// contains a method annotated with 'objc_instance_variable_invalidator', 125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// - (void) foo 135bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// __attribute__((annotate("objc_instance_variable_invalidator"))); 145bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// all the "ivalidatable" instance variables of this class should be 155bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// invalidated. We call an instance variable ivalidatable if it is an object of 165bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// a class which contains an invalidation method. 175bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 185bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// Note, this checker currently only checks if an ivar was accessed by the 195bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// method, we do not currently support any deeper invalidation checking. 205bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 215bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks//===----------------------------------------------------------------------===// 225bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 235bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "ClangSACheckers.h" 245bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/StaticAnalyzer/Core/Checker.h" 255bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 265bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 275bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/AST/DeclObjC.h" 285bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/AST/StmtVisitor.h" 295bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "llvm/ADT/DenseMap.h" 305bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "llvm/ADT/SmallString.h" 315bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 325bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksusing namespace clang; 335bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksusing namespace ento; 345bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 355bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksnamespace { 365bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksclass IvarInvalidationChecker : 375bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks public Checker<check::ASTDecl<ObjCMethodDecl> > { 385bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 395bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks typedef llvm::DenseMap<const ObjCIvarDecl*, bool> IvarSet; 405bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks typedef llvm::DenseMap<const ObjCMethodDecl*, 415bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl*> MethToIvarMapTy; 425bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks typedef llvm::DenseMap<const ObjCPropertyDecl*, 435bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl*> PropToIvarMapTy; 445bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 455bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Statement visitor, which walks the method body and flags the ivars 465bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// referenced in it (either directly or via property). 475bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks class MethodCrawler : public ConstStmtVisitor<MethodCrawler> { 485bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 495bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// The set of Ivars which need to be invalidated. 505bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet &IVars; 515bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 525bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Property setter to ivar mapping. 535bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MethToIvarMapTy &PropertySetterToIvarMap; 545bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 555bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Property to ivar mapping. 565bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropToIvarMapTy &PropertyToIvarMap; 575bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 585bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks public: 595bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MethodCrawler(const ObjCInterfaceDecl *InID, 605bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet &InIVars, MethToIvarMapTy &InPropertySetterToIvarMap, 615bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropToIvarMapTy &InPropertyToIvarMap) 627836011482bc26dfebf15df4fd993d07b607fbcfNAKAMURA Takumi : IVars(InIVars), 635bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropertySetterToIvarMap(InPropertySetterToIvarMap), 645bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropertyToIvarMap(InPropertyToIvarMap) {} 655bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 665bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitStmt(const Stmt *S) { VisitChildren(S); } 675bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 685bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef); 695bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 705bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitObjCMessageExpr(const ObjCMessageExpr *ME); 715bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 725bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA); 735bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 745bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitChildren(const Stmt *S) { 755bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (Stmt::const_child_range I = S->children(); I; ++I) 765bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (*I) 77b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks this->Visit(*I); 785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 795bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks }; 805bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 815bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Check if the any of the methods inside the interface are annotated with 825bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// the invalidation annotation. 835bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks bool containsInvalidationMethod(const ObjCContainerDecl *D) const; 845bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 855bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Given the property declaration, and the list of tracked ivars, finds 865bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// the ivar backing the property when possible. Returns '0' when no such 875bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// ivar could be found. 885bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks static const ObjCIvarDecl *findPropertyBackingIvar( 895bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *Prop, 905bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCInterfaceDecl *InterfaceD, 915bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet TrackedIvars); 925bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 935bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zakspublic: 945bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr, 955bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks BugReporter &BR) const; 965bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 97b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks // TODO: We are currently ignoring the ivars coming from class extensions. 985bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks}; 995bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1005bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksbool isInvalidationMethod(const ObjCMethodDecl *M) { 101b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks for (specific_attr_iterator<AnnotateAttr> 102b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks AI = M->specific_attr_begin<AnnotateAttr>(), 103b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) { 104b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks const AnnotateAttr *Ann = *AI; 105b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks if (Ann->getAnnotation() == "objc_instance_variable_invalidator") 106b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks return true; 107b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks } 1085bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return false; 1095bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 1105bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksbool IvarInvalidationChecker::containsInvalidationMethod ( 1125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCContainerDecl *D) const { 1135bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1145bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // TODO: Cache the results. 1155bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1165bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (!D) 1175bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return false; 1185bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1195bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Check all methods. 1205bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (ObjCContainerDecl::method_iterator 1215bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks I = D->meth_begin(), 1225bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks E = D->meth_end(); I != E; ++I) { 1235bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMethodDecl *MDI = *I; 1245bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (isInvalidationMethod(MDI)) 1255bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return true; 1265bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1275bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1285bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // If interface, check all parent protocols and super. 1295bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // TODO: Visit all categories in case the invalidation method is declared in 1305bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // a category. 1315bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (const ObjCInterfaceDecl *InterfaceD = dyn_cast<ObjCInterfaceDecl>(D)) { 1325bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (ObjCInterfaceDecl::protocol_iterator 1335bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks I = InterfaceD->protocol_begin(), 1345bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks E = InterfaceD->protocol_end(); I != E; ++I) { 1355bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (containsInvalidationMethod(*I)) 1365bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return true; 1375bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1385bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return containsInvalidationMethod(InterfaceD->getSuperClass()); 1395bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1405bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1415bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // If protocol, check all parent protocols. 1425bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) { 1435bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (ObjCInterfaceDecl::protocol_iterator 1445bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks I = ProtD->protocol_begin(), 1455bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks E = ProtD->protocol_end(); I != E; ++I) { 1465bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (containsInvalidationMethod(*I)) 1475bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return true; 1485bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1495bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return false; 1505bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1515bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1525bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks llvm_unreachable("One of the casts above should have succeeded."); 1535bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 1545bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1555bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksconst ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar( 1565bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *Prop, 1575bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCInterfaceDecl *InterfaceD, 1585bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet TrackedIvars) { 1595bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl *IvarD = 0; 1605bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1615bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Lookup for the synthesized case. 1625bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarD = Prop->getPropertyIvarDecl(); 1635bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (IvarD) 1645bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return IvarD; 1655bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1665bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars. 1675bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks StringRef PropName = Prop->getIdentifier()->getName(); 1685bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (IvarSet::const_iterator I = TrackedIvars.begin(), 1695bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks E = TrackedIvars.end(); I != E; ++I) { 1705bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl *Iv = I->first; 1715bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks StringRef IvarName = Iv->getName(); 1725bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1735bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (IvarName == PropName) 1745bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return Iv; 1755bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1765bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks SmallString<128> PropNameWithUnderscore; 1775bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks { 1785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks llvm::raw_svector_ostream os(PropNameWithUnderscore); 1795bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks os << '_' << PropName; 1805bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1815bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (IvarName == PropNameWithUnderscore.str()) 1825bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return Iv; 1835bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1845bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1855bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Note, this is a possible source of false positives. We could look at the 1865bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // getter implementation to find the ivar when its name is not derived from 1875bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // the property name. 1885bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return 0; 1895bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 1905bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1915bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksvoid IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D, 1925bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks AnalysisManager& Mgr, 1935bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks BugReporter &BR) const { 1945bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // We are only interested in checking the cleanup methods. 1955bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (!D->hasBody() || !isInvalidationMethod(D)) 1965bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return; 1975bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1985bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Collect all ivars that need cleanup. 1995bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet Ivars; 2005bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCInterfaceDecl *InterfaceD = D->getClassInterface(); 2015bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (ObjCInterfaceDecl::ivar_iterator 2025bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks II = InterfaceD->ivar_begin(), 2035bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IE = InterfaceD->ivar_end(); II != IE; ++II) { 2045bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl *Iv = *II; 2055bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks QualType IvQTy = Iv->getType(); 2065bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); 2075bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (!IvTy) 2085bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks continue; 209b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); 2105bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (containsInvalidationMethod(IvInterf)) 2115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks Ivars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = false; 2125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2135bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2145bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Construct Property/Property Setter to Ivar maps to assist checking if an 2155bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // ivar which is backing a property has been reset. 2165bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MethToIvarMapTy PropSetterToIvarMap; 2175bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropToIvarMapTy PropertyToIvarMap; 2185bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (ObjCInterfaceDecl::prop_iterator 2195bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks I = InterfaceD->prop_begin(), 2205bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks E = InterfaceD->prop_end(); I != E; ++I) { 2215bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *PD = *I; 2225bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2235bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars); 2245bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (!ID) { 2255bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks continue; 2265bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2275bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Find the setter. 2285bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); 2295bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // If we don't know the setter, do not track this ivar. 230b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks if (!SetterD) 2315bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks continue; 2325bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2335bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Store the mappings. 2345bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); 2355bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl()); 2365bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropertyToIvarMap[PD] = ID; 2375bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropSetterToIvarMap[SetterD] = ID; 2385bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2395bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2405bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2415bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Check which ivars have been accessed by the method. 2425bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // We assume that if ivar was at least accessed, it was not forgotten. 2435bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MethodCrawler(InterfaceD, Ivars, 2445bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropSetterToIvarMap, PropertyToIvarMap).VisitStmt(D->getBody()); 2455bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2465bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Warn on the ivars that were not accessed by the method. 2475bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I){ 2485bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (I->second == false) { 2495bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl *IvarDecl = I->first; 2505bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2515bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PathDiagnosticLocation IvarDecLocation = 252b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks PathDiagnosticLocation::createEnd(D->getBody(), BR.getSourceManager(), 253b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks Mgr.getAnalysisDeclContext(D)); 2545bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2555bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks SmallString<128> sbuf; 2565bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks llvm::raw_svector_ostream os(sbuf); 257b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks os << "Instance variable "<< IvarDecl->getName() 258b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks << " needs to be invalidated"; 2595bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 260b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks BR.EmitBasicReport(D, 2615bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks "Incomplete invalidation", 2625bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks categories::CoreFoundationObjectiveC, os.str(), 2635bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarDecLocation); 2645bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2655bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2665bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 2675bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2685bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks/// Handle the case when an ivar is directly accessed. 2695bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksvoid IvarInvalidationChecker::MethodCrawler::VisitObjCIvarRefExpr( 2705bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarRefExpr *IvarRef) { 2715bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const Decl *D = IvarRef->getDecl(); 2725bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (D) 2735bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IVars[cast<ObjCIvarDecl>(D->getCanonicalDecl())] = true; 2745bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks VisitStmt(IvarRef); 2755bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 2765bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2775bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks/// Handle the case when the property backing ivar is set via a direct call 2795bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks/// to the setter. 2805bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksvoid IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr( 2815bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMessageExpr *ME) { 2825bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMethodDecl *MD = ME->getMethodDecl(); 2835bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (MD) { 2845bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 2855bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IVars[PropertySetterToIvarMap[MD]] = true; 2865bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2875bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks VisitStmt(ME); 2885bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 2895bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2905bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks/// Handle the case when the property backing ivar is set via the dot syntax. 2915bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksvoid IvarInvalidationChecker::MethodCrawler::VisitObjCPropertyRefExpr( 2925bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyRefExpr *PA) { 2935bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2945bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (PA->isExplicitProperty()) { 2955bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *PD = PA->getExplicitProperty(); 2965bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (PD) { 2975bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); 2985bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IVars[PropertyToIvarMap[PD]] = true; 2995bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks VisitStmt(PA); 3005bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return; 3015bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 3025bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 3035bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3045bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (PA->isImplicitProperty()) { 3055bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMethodDecl *MD = PA->getImplicitPropertySetter(); 3065bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (MD) { 3075bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 3085bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IVars[PropertySetterToIvarMap[MD]] = true; 3095bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks VisitStmt(PA); 3105bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return; 3115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 3125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 3135bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks VisitStmt(PA); 3145bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 3155bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 3165bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3175bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// Register the checker. 3185bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksvoid ento::registerIvarInvalidationChecker(CheckerManager &mgr) { 3195bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks mgr.registerChecker<IvarInvalidationChecker>(); 3205bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 321