131f69cc770888ec0f0f7012212e5df7979aba4f3Anna 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 1631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks// a class which contains an invalidation method. There could be multiple 1731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks// methods annotated with such annotations per class, either one can be used 1831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks// to invalidate the ivar. An ivar or property are considered to be 1931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks// invalidated if they are being assigned 'nil' or an invalidation method has 2031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks// been called on them. An invalidation method should either invalidate all 2131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks// the ivars or call another invalidation method (on self). 225bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks// 2326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks// Partial invalidor annotation allows to addess cases when ivars are 2426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks// invalidated by other methods, which might or might not be called from 2526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks// the invalidation method. The checker checks that each invalidation 2626db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks// method and all the partial methods cumulatively invalidate all ivars. 2726db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks// __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 2826db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks// 295bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks//===----------------------------------------------------------------------===// 305bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 315bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "ClangSACheckers.h" 322fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Attr.h" 335bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/AST/DeclObjC.h" 345bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "clang/AST/StmtVisitor.h" 3555fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 3655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h" 3755fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 385bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "llvm/ADT/DenseMap.h" 39b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks#include "llvm/ADT/SetVector.h" 405bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks#include "llvm/ADT/SmallString.h" 415bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 425bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksusing namespace clang; 435bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksusing namespace ento; 445bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 455bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaksnamespace { 46722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 47722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksstruct ChecksFilter { 48722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks /// Check for missing invalidation method declarations. 49722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks DefaultBool check_MissingInvalidationMethod; 50722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks /// Check that all ivars are invalidated. 51722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks DefaultBool check_InstanceVariableInvalidation; 52651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 53651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines CheckName checkName_MissingInvalidationMethod; 54651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines CheckName checkName_InstanceVariableInvalidation; 55722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks}; 56722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 57d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaksclass IvarInvalidationCheckerImpl { 585bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 59b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks typedef llvm::SmallSetVector<const ObjCMethodDecl*, 2> MethodSet; 605bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks typedef llvm::DenseMap<const ObjCMethodDecl*, 615bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl*> MethToIvarMapTy; 625bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks typedef llvm::DenseMap<const ObjCPropertyDecl*, 635bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl*> PropToIvarMapTy; 64377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks typedef llvm::DenseMap<const ObjCIvarDecl*, 65377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks const ObjCPropertyDecl*> IvarToPropMapTy; 665bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 6731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 68b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks struct InvalidationInfo { 6931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Has the ivar been invalidated? 7031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks bool IsInvalidated; 7131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 7231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// The methods which can be used to invalidate the ivar. 7331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MethodSet InvalidationMethods; 7431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 75b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks InvalidationInfo() : IsInvalidated(false) {} 7631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void addInvalidationMethod(const ObjCMethodDecl *MD) { 7731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks InvalidationMethods.insert(MD); 7831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 7931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 8031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks bool needsInvalidation() const { 8131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return !InvalidationMethods.empty(); 8231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 8331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 8426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks bool hasMethod(const ObjCMethodDecl *MD) { 8531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (IsInvalidated) 8631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return true; 8731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks for (MethodSet::iterator I = InvalidationMethods.begin(), 8831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks E = InvalidationMethods.end(); I != E; ++I) { 8931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (*I == MD) { 9031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks IsInvalidated = true; 9131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return true; 9231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 9331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 9431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return false; 9531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 9631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks }; 9731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 98b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks typedef llvm::DenseMap<const ObjCIvarDecl*, InvalidationInfo> IvarSet; 9931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 1005bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Statement visitor, which walks the method body and flags the ivars 1015bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// referenced in it (either directly or via property). 1025bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks class MethodCrawler : public ConstStmtVisitor<MethodCrawler> { 1035bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// The set of Ivars which need to be invalidated. 1045bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet &IVars; 1055bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 10631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Flag is set as the result of a message send to another 10731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// invalidation method. 10831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks bool &CalledAnotherInvalidationMethod; 10931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 11031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Property setter to ivar mapping. 11131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const MethToIvarMapTy &PropertySetterToIvarMap; 11231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 11331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Property getter to ivar mapping. 11431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const MethToIvarMapTy &PropertyGetterToIvarMap; 11531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 11631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Property to ivar mapping. 11731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const PropToIvarMapTy &PropertyToIvarMap; 11831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 11931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// The invalidation method being currently processed. 12031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const ObjCMethodDecl *InvalidationMethod; 12131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 122b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks ASTContext &Ctx; 123b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks 124b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks /// Peel off parens, casts, OpaqueValueExpr, and PseudoObjectExpr. 12531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const Expr *peel(const Expr *E) const; 1265bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 12731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Does this expression represent zero: '0'? 12831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks bool isZero(const Expr *E) const; 12931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 13031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Mark the given ivar as invalidated. 13131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void markInvalidated(const ObjCIvarDecl *Iv); 13231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 13331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Checks if IvarRef refers to the tracked IVar, if yes, marks it as 13431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// invalidated. 13531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void checkObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef); 13631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 13731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Checks if ObjCPropertyRefExpr refers to the tracked IVar, if yes, marks 13831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// it as invalidated. 13931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void checkObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA); 14031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 14131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Checks if ObjCMessageExpr refers to (is a getter for) the tracked IVar, 14231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// if yes, marks it as invalidated. 14331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void checkObjCMessageExpr(const ObjCMessageExpr *ME); 14431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 14531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// Checks if the Expr refers to an ivar, if yes, marks it as invalidated. 14631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void check(const Expr *E); 1475bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1485bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks public: 149bbff82f302a1dd67589f65912351978905f0c5a7Anna Zaks MethodCrawler(IvarSet &InIVars, 15031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks bool &InCalledAnotherInvalidationMethod, 15131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const MethToIvarMapTy &InPropertySetterToIvarMap, 15231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const MethToIvarMapTy &InPropertyGetterToIvarMap, 153b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks const PropToIvarMapTy &InPropertyToIvarMap, 154b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks ASTContext &InCtx) 155bbff82f302a1dd67589f65912351978905f0c5a7Anna Zaks : IVars(InIVars), 15631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks CalledAnotherInvalidationMethod(InCalledAnotherInvalidationMethod), 15731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks PropertySetterToIvarMap(InPropertySetterToIvarMap), 15831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks PropertyGetterToIvarMap(InPropertyGetterToIvarMap), 15931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks PropertyToIvarMap(InPropertyToIvarMap), 1606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines InvalidationMethod(nullptr), 161b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks Ctx(InCtx) {} 1625bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1635bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitStmt(const Stmt *S) { VisitChildren(S); } 1645bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 16531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks void VisitBinaryOperator(const BinaryOperator *BO); 1665bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1675bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitObjCMessageExpr(const ObjCMessageExpr *ME); 1685bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1695bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks void VisitChildren(const Stmt *S) { 17031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks for (Stmt::const_child_range I = S->children(); I; ++I) { 1715bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (*I) 172b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks this->Visit(*I); 17331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (CalledAnotherInvalidationMethod) 17431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 17531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 1765bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 1775bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks }; 1785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1795bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Check if the any of the methods inside the interface are annotated with 18031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks /// the invalidation annotation, update the IvarInfo accordingly. 18126db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks /// \param LookForPartial is set when we are searching for partial 18226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks /// invalidators. 18331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks static void containsInvalidationMethod(const ObjCContainerDecl *D, 18426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks InvalidationInfo &Out, 18526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks bool LookForPartial); 186377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks 187377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks /// Check if ivar should be tracked and add to TrackedIvars if positive. 188377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks /// Returns true if ivar should be tracked. 189664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars, 190664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCIvarDecl **FirstIvarDecl); 1915bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 1925bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// Given the property declaration, and the list of tracked ivars, finds 1935bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// the ivar backing the property when possible. Returns '0' when no such 1945bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks /// ivar could be found. 1955bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks static const ObjCIvarDecl *findPropertyBackingIvar( 1965bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *Prop, 1975bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCInterfaceDecl *InterfaceD, 198664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks IvarSet &TrackedIvars, 199664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCIvarDecl **FirstIvarDecl); 2005bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 201b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks /// Print ivar name or the property if the given ivar backs a property. 202b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks static void printIvar(llvm::raw_svector_ostream &os, 203b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks const ObjCIvarDecl *IvarDecl, 2042b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks const IvarToPropMapTy &IvarToPopertyMap); 2052b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks 206651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines void reportNoInvalidationMethod(CheckName CheckName, 207651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const ObjCIvarDecl *FirstIvarDecl, 208722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks const IvarToPropMapTy &IvarToPopertyMap, 209722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks const ObjCInterfaceDecl *InterfaceD, 210722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks bool MissingDeclaration) const; 211722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks void reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, 212722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks const IvarToPropMapTy &IvarToPopertyMap, 213722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks const ObjCMethodDecl *MethodD) const; 2142b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks 215722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks AnalysisManager& Mgr; 216722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks BugReporter &BR; 217722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks /// Filter on the checks performed. 218722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks const ChecksFilter &Filter; 21926db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks 2205bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zakspublic: 221722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks IvarInvalidationCheckerImpl(AnalysisManager& InMgr, 222722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks BugReporter &InBR, 223722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks const ChecksFilter &InFilter) : 224722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks Mgr (InMgr), BR(InBR), Filter(InFilter) {} 225722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 226722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks void visit(const ObjCImplementationDecl *D) const; 2275bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks}; 2285bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 22926db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaksstatic bool isInvalidationMethod(const ObjCMethodDecl *M, bool LookForPartial) { 230651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *Ann : M->specific_attrs<AnnotateAttr>()) { 23126db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (!LookForPartial && 23226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks Ann->getAnnotation() == "objc_instance_variable_invalidator") 23326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks return true; 23426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (LookForPartial && 23526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks Ann->getAnnotation() == "objc_instance_variable_invalidator_partial") 236b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks return true; 237b087bbf3cf44a56d60ad1ed6fd5abb48dab0e0b3Anna Zaks } 2385bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return false; 2395bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 2405bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 241722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::containsInvalidationMethod( 24226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks const ObjCContainerDecl *D, InvalidationInfo &OutInfo, bool Partial) { 2435bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2445bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (!D) 24531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 2465bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 247b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks assert(!isa<ObjCImplementationDecl>(D)); 248b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // TODO: Cache the results. 249b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 2505bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Check all methods. 251651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *MDI : D->methods()) 252651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (isInvalidationMethod(MDI, Partial)) 253651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines OutInfo.addInvalidationMethod( 254651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines cast<ObjCMethodDecl>(MDI->getCanonicalDecl())); 2555bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2565bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // If interface, check all parent protocols and super. 257ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks if (const ObjCInterfaceDecl *InterfD = dyn_cast<ObjCInterfaceDecl>(D)) { 258ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks 259ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks // Visit all protocols. 260651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *I : InterfD->protocols()) 261651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines containsInvalidationMethod(I->getDefinition(), OutInfo, Partial); 262ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks 263ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks // Visit all categories in case the invalidation method is declared in 264ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks // a category. 265651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *Ext : InterfD->visible_extensions()) 266651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines containsInvalidationMethod(Ext, OutInfo, Partial); 267ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks 26826db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks containsInvalidationMethod(InterfD->getSuperClass(), OutInfo, Partial); 26931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 2705bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2715bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 2725bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // If protocol, check all parent protocols. 2735bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) { 274651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *I : ProtD->protocols()) { 275651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines containsInvalidationMethod(I->getDefinition(), OutInfo, Partial); 2765bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 27731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 2785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 2795bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 280ae81e172e93b75594c7053f3226a16b9d8daa6fdAnna Zaks return; 2815bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 2825bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 283722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksbool IvarInvalidationCheckerImpl::trackIvar(const ObjCIvarDecl *Iv, 284664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks IvarSet &TrackedIvars, 285664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCIvarDecl **FirstIvarDecl) { 286377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks QualType IvQTy = Iv->getType(); 287377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); 288377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks if (!IvTy) 289377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks return false; 290377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); 29131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 292b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks InvalidationInfo Info; 29326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks containsInvalidationMethod(IvInterf, Info, /*LookForPartial*/ false); 29431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (Info.needsInvalidation()) { 295664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl()); 296664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks TrackedIvars[I] = Info; 297664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks if (!*FirstIvarDecl) 298664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks *FirstIvarDecl = I; 299377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks return true; 300377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks } 301377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks return false; 302377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks} 303377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks 304722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksconst ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar( 3055bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *Prop, 3065bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCInterfaceDecl *InterfaceD, 307664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks IvarSet &TrackedIvars, 308664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCIvarDecl **FirstIvarDecl) { 3096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines const ObjCIvarDecl *IvarD = nullptr; 3105bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Lookup for the synthesized case. 3125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarD = Prop->getPropertyIvarDecl(); 3135879fb3f6d559863c18df7132ee3d5fdb62b6ae5Anna Zaks // We only track the ivars/properties that are defined in the current 3145879fb3f6d559863c18df7132ee3d5fdb62b6ae5Anna Zaks // class (not the parent). 3155879fb3f6d559863c18df7132ee3d5fdb62b6ae5Anna Zaks if (IvarD && IvarD->getContainingInterface() == InterfaceD) { 316377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks if (TrackedIvars.count(IvarD)) { 317377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks return IvarD; 318377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks } 319377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks // If the ivar is synthesized we still want to track it. 320664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl)) 321377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks return IvarD; 322377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks } 3235bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3245bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars. 3255bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks StringRef PropName = Prop->getIdentifier()->getName(); 3265bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks for (IvarSet::const_iterator I = TrackedIvars.begin(), 3275bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks E = TrackedIvars.end(); I != E; ++I) { 3285bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCIvarDecl *Iv = I->first; 3295bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks StringRef IvarName = Iv->getName(); 3305bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3315bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (IvarName == PropName) 3325bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return Iv; 3335bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3345bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks SmallString<128> PropNameWithUnderscore; 3355bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks { 3365bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks llvm::raw_svector_ostream os(PropNameWithUnderscore); 3375bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks os << '_' << PropName; 3385bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 3395bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (IvarName == PropNameWithUnderscore.str()) 3405bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return Iv; 3415bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 3425bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3435bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Note, this is a possible source of false positives. We could look at the 3445bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // getter implementation to find the ivar when its name is not derived from 3455bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // the property name. 3466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return nullptr; 3475bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 3485bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 349722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os, 3502b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks const ObjCIvarDecl *IvarDecl, 3512b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks const IvarToPropMapTy &IvarToPopertyMap) { 352b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks if (IvarDecl->getSynthesize()) { 3532b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks const ObjCPropertyDecl *PD = IvarToPopertyMap.lookup(IvarDecl); 354b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks assert(PD &&"Do we synthesize ivars for something other than properties?"); 355b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks os << "Property "<< PD->getName() << " "; 356b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks } else { 357b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks os << "Instance variable "<< IvarDecl->getName() << " "; 358b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks } 359b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks} 360b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 361b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks// Check that the invalidatable interfaces with ivars/properties implement the 362b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks// invalidation methods. 363722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl:: 364722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvisit(const ObjCImplementationDecl *ImplD) const { 3655bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Collect all ivars that need cleanup. 3665bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks IvarSet Ivars; 367664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks // Record the first Ivar needing invalidation; used in reporting when only 368664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks // one ivar is sufficient. Cannot grab the first on the Ivars set to ensure 369664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks // deterministic output. 3706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines const ObjCIvarDecl *FirstIvarDecl = nullptr; 371b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface(); 372e0c50fa01d59749e9392ccff50ee6fb90a61725bAnna Zaks 373e0c50fa01d59749e9392ccff50ee6fb90a61725bAnna Zaks // Collect ivars declared in this class, its extensions and its implementation 374e0c50fa01d59749e9392ccff50ee6fb90a61725bAnna Zaks ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD); 375e0c50fa01d59749e9392ccff50ee6fb90a61725bAnna Zaks for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; 376e0c50fa01d59749e9392ccff50ee6fb90a61725bAnna Zaks Iv= Iv->getNextIvar()) 377664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks trackIvar(Iv, Ivars, &FirstIvarDecl); 3785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 379377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks // Construct Property/Property Accessor to Ivar maps to assist checking if an 3805bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // ivar which is backing a property has been reset. 38131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MethToIvarMapTy PropSetterToIvarMap; 38231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MethToIvarMapTy PropGetterToIvarMap; 3835bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropToIvarMapTy PropertyToIvarMap; 384377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks IvarToPropMapTy IvarToPopertyMap; 385c3c26b7390bc4ac3ad122f557a10ba17ab871216Anna Zaks 386c3c26b7390bc4ac3ad122f557a10ba17ab871216Anna Zaks ObjCInterfaceDecl::PropertyMap PropMap; 387cfaed8d399a34e79fbab9f70eb4ea1bbeb81a02bFariborz Jahanian ObjCInterfaceDecl::PropertyDeclOrder PropOrder; 388cfaed8d399a34e79fbab9f70eb4ea1bbeb81a02bFariborz Jahanian InterfaceD->collectPropertiesToImplement(PropMap, PropOrder); 389c3c26b7390bc4ac3ad122f557a10ba17ab871216Anna Zaks 390c3c26b7390bc4ac3ad122f557a10ba17ab871216Anna Zaks for (ObjCInterfaceDecl::PropertyMap::iterator 391c3c26b7390bc4ac3ad122f557a10ba17ab871216Anna Zaks I = PropMap.begin(), E = PropMap.end(); I != E; ++I) { 392c3c26b7390bc4ac3ad122f557a10ba17ab871216Anna Zaks const ObjCPropertyDecl *PD = I->second; 3935bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 394664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars, 395664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks &FirstIvarDecl); 3962b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks if (!ID) 3975bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks continue; 3985bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 3995bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks // Store the mappings. 4005bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); 4015bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PropertyToIvarMap[PD] = ID; 402377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks IvarToPopertyMap[ID] = PD; 403377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks 404377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks // Find the setter and the getter. 405377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); 406377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks if (SetterD) { 407377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl()); 40831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks PropSetterToIvarMap[SetterD] = ID; 409377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks } 410377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks 411377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl(); 412377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks if (GetterD) { 413377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl()); 41431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks PropGetterToIvarMap[GetterD] = ID; 415377945cc9e4f23cdbb01ade2a664acd5ff95a888Anna Zaks } 4165bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 4175bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 418b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // If no ivars need invalidation, there is nothing to check here. 419b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks if (Ivars.empty()) 42031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 4215bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 42226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // Find all partial invalidation methods. 42326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks InvalidationInfo PartialInfo; 42426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks containsInvalidationMethod(InterfaceD, PartialInfo, /*LookForPartial*/ true); 42526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks 42626db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // Remove ivars invalidated by the partial invalidation methods. They do not 42726db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // need to be invalidated in the regular invalidation methods. 428caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks bool AtImplementationContainsAtLeastOnePartialInvalidationMethod = false; 42926db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks for (MethodSet::iterator 43026db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks I = PartialInfo.InvalidationMethods.begin(), 43126db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks E = PartialInfo.InvalidationMethods.end(); I != E; ++I) { 43226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks const ObjCMethodDecl *InterfD = *I; 43326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks 43426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // Get the corresponding method in the @implementation. 43526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(), 43626db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks InterfD->isInstanceMethod()); 43726db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (D && D->hasBody()) { 438caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks AtImplementationContainsAtLeastOnePartialInvalidationMethod = true; 439caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks 44026db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks bool CalledAnotherInvalidationMethod = false; 44126db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // The MethodCrowler is going to remove the invalidated ivars. 44226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks MethodCrawler(Ivars, 44326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks CalledAnotherInvalidationMethod, 44426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks PropSetterToIvarMap, 44526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks PropGetterToIvarMap, 44626db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks PropertyToIvarMap, 44726db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks BR.getContext()).VisitStmt(D->getBody()); 44826db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // If another invalidation method was called, trust that full invalidation 44926db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // has occurred. 45026db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (CalledAnotherInvalidationMethod) 45126db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks Ivars.clear(); 45226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks } 45326db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks } 45426db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks 45526db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // If all ivars have been invalidated by partial invalidators, there is 45626db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks // nothing to check here. 45726db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (Ivars.empty()) 45826db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks return; 45926db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks 460b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Find all invalidation methods in this @interface declaration and parents. 461b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks InvalidationInfo Info; 46226db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false); 463b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 464b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Report an error in case none of the invalidation methods are declared. 465caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) { 466d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks if (Filter.check_MissingInvalidationMethod) 467651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines reportNoInvalidationMethod(Filter.checkName_MissingInvalidationMethod, 468651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines FirstIvarDecl, IvarToPopertyMap, InterfaceD, 469d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks /*MissingDeclaration*/ true); 470d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks // If there are no invalidation methods, there is no ivar validation work 471d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks // to be done. 472b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks return; 473b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks } 4745bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 475d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks // Only check if Ivars are invalidated when InstanceVariableInvalidation 476d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks // has been requested. 477d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks if (!Filter.check_InstanceVariableInvalidation) 478d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks return; 479d523df6a143a97eea46916c6e31c8f2a0728bf28Anna Zaks 480b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Check that all ivars are invalidated by the invalidation methods. 481b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks bool AtImplementationContainsAtLeastOneInvalidationMethod = false; 482b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks for (MethodSet::iterator I = Info.InvalidationMethods.begin(), 483b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks E = Info.InvalidationMethods.end(); I != E; ++I) { 484b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks const ObjCMethodDecl *InterfD = *I; 485b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 486b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Get the corresponding method in the @implementation. 487b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(), 488b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks InterfD->isInstanceMethod()); 489b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks if (D && D->hasBody()) { 490b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks AtImplementationContainsAtLeastOneInvalidationMethod = true; 491b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 492b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Get a copy of ivars needing invalidation. 493b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks IvarSet IvarsI = Ivars; 494b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 495b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks bool CalledAnotherInvalidationMethod = false; 496b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks MethodCrawler(IvarsI, 497b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks CalledAnotherInvalidationMethod, 498b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks PropSetterToIvarMap, 499b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks PropGetterToIvarMap, 500b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks PropertyToIvarMap, 501b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks BR.getContext()).VisitStmt(D->getBody()); 502b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // If another invalidation method was called, trust that full invalidation 503b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // has occurred. 504b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks if (CalledAnotherInvalidationMethod) 505b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks continue; 506b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 507b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Warn on the ivars that were not invalidated by the method. 5082b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks for (IvarSet::const_iterator 5092b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks I = IvarsI.begin(), E = IvarsI.end(); I != E; ++I) 510722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, D); 5115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 5125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 513b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks 514b1fc673783dd0215a1426b2c411779cd05a16a07Anna Zaks // Report an error in case none of the invalidation methods are implemented. 515caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks if (!AtImplementationContainsAtLeastOneInvalidationMethod) { 516caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks if (AtImplementationContainsAtLeastOnePartialInvalidationMethod) { 517caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks // Warn on the ivars that were not invalidated by the prrtial 518caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks // invalidation methods. 519caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks for (IvarSet::const_iterator 520caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks I = Ivars.begin(), E = Ivars.end(); I != E; ++I) 5216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, nullptr); 522caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks } else { 523caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks // Otherwise, no invalidation methods were implemented. 524651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines reportNoInvalidationMethod(Filter.checkName_InstanceVariableInvalidation, 525651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines FirstIvarDecl, IvarToPopertyMap, InterfaceD, 526caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks /*MissingDeclaration*/ false); 527caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks } 528caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks } 5292b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks} 5302b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks 531651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid IvarInvalidationCheckerImpl::reportNoInvalidationMethod( 532651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines CheckName CheckName, const ObjCIvarDecl *FirstIvarDecl, 533651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const IvarToPropMapTy &IvarToPopertyMap, 534651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const ObjCInterfaceDecl *InterfaceD, bool MissingDeclaration) const { 5352b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks SmallString<128> sbuf; 5362b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks llvm::raw_svector_ostream os(sbuf); 5372b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks assert(FirstIvarDecl); 5382b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks printIvar(os, FirstIvarDecl, IvarToPopertyMap); 5392b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks os << "needs to be invalidated; "; 5402b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks if (MissingDeclaration) 5412b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks os << "no invalidation method is declared for "; 5422b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks else 5432b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks os << "no invalidation method is defined in the @implementation for "; 5442b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks os << InterfaceD->getName(); 5452b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks 5462b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks PathDiagnosticLocation IvarDecLocation = 5472b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager()); 5482b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks 549651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BR.EmitBasicReport(FirstIvarDecl, CheckName, "Incomplete invalidation", 5502b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks categories::CoreFoundationObjectiveC, os.str(), 5512b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks IvarDecLocation); 5522b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks} 5532b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks 554722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl:: 5552b174c37ae174063d70494e9b4fd91f4eff26463Anna ZaksreportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, 556caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks const IvarToPropMapTy &IvarToPopertyMap, 557caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks const ObjCMethodDecl *MethodD) const { 5582b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks SmallString<128> sbuf; 5592b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks llvm::raw_svector_ostream os(sbuf); 5602b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks printIvar(os, IvarD, IvarToPopertyMap); 5612b174c37ae174063d70494e9b4fd91f4eff26463Anna Zaks os << "needs to be invalidated or set to nil"; 562caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks if (MethodD) { 563caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks PathDiagnosticLocation MethodDecLocation = 564caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks PathDiagnosticLocation::createEnd(MethodD->getBody(), 565caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks BR.getSourceManager(), 566caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks Mgr.getAnalysisDeclContext(MethodD)); 567651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BR.EmitBasicReport(MethodD, Filter.checkName_InstanceVariableInvalidation, 568651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Incomplete invalidation", 569caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks categories::CoreFoundationObjectiveC, os.str(), 570caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks MethodDecLocation); 571caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks } else { 572651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BR.EmitBasicReport( 573651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines IvarD, Filter.checkName_InstanceVariableInvalidation, 574651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Incomplete invalidation", categories::CoreFoundationObjectiveC, 575651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines os.str(), 576651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines PathDiagnosticLocation::createBegin(IvarD, BR.getSourceManager())); 577caadc413a88e864e058a3bea832f42debd8ddef2Anna Zaks } 5785bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 5795bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 580722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated( 58131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const ObjCIvarDecl *Iv) { 58231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks IvarSet::iterator I = IVars.find(Iv); 58331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (I != IVars.end()) { 58431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks // If InvalidationMethod is present, we are processing the message send and 58531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks // should ensure we are invalidating with the appropriate method, 58631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks // otherwise, we are processing setting to 'nil'. 58726db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (!InvalidationMethod || 58826db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks (InvalidationMethod && I->second.hasMethod(InvalidationMethod))) 58926db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks IVars.erase(I); 59031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 5915bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 5925bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 593722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksconst Expr *IvarInvalidationCheckerImpl::MethodCrawler::peel(const Expr *E) const { 59431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks E = E->IgnoreParenCasts(); 59531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) 59631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks E = POE->getSyntacticForm()->IgnoreParenCasts(); 59731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) 59831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks E = OVE->getSourceExpr()->IgnoreParenCasts(); 59931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return E; 60031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks} 6015bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 602722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::checkObjCIvarRefExpr( 60331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const ObjCIvarRefExpr *IvarRef) { 60431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (const Decl *D = IvarRef->getDecl()) 60531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl())); 60631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks} 60731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 608722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::checkObjCMessageExpr( 6095bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMessageExpr *ME) { 6105bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMethodDecl *MD = ME->getMethodDecl(); 6115bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (MD) { 6125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 61331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD); 61431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (IvI != PropertyGetterToIvarMap.end()) 61531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks markInvalidated(IvI->second); 6165bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 6175bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 6185bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 619722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::checkObjCPropertyRefExpr( 6205bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyRefExpr *PA) { 6215bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 6225bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (PA->isExplicitProperty()) { 6235bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCPropertyDecl *PD = PA->getExplicitProperty(); 6245bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (PD) { 6255bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); 62631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD); 62731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (IvI != PropertyToIvarMap.end()) 62831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks markInvalidated(IvI->second); 6295bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return; 6305bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 6315bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 6325bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 6335bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (PA->isImplicitProperty()) { 6345bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks const ObjCMethodDecl *MD = PA->getImplicitPropertySetter(); 6355bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks if (MD) { 6365bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 63731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD); 63831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (IvI != PropertyGetterToIvarMap.end()) 63931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks markInvalidated(IvI->second); 64031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 64131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 64231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 64331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks} 64431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 645722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksbool IvarInvalidationCheckerImpl::MethodCrawler::isZero(const Expr *E) const { 64631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks E = peel(E); 64731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 648b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull) 649b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks != Expr::NPCK_NotNull); 65031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks} 65131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 652722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::check(const Expr *E) { 65331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks E = peel(E); 65431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 65531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { 65631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks checkObjCIvarRefExpr(IvarRef); 65731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 65831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 65931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 66031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) { 66131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks checkObjCPropertyRefExpr(PropRef); 66231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 66331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 66431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 66531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) { 66631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks checkObjCMessageExpr(MsgExpr); 66731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 66831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 66931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks} 67031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 671722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::VisitBinaryOperator( 67231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const BinaryOperator *BO) { 673b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks VisitStmt(BO); 674b9733ac1a2012c3e909ac262073a6deb8533d2c7Anna Zaks 6756503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks // Do we assign/compare against zero? If yes, check the variable we are 6766503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks // assigning to. 6776503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks BinaryOperatorKind Opcode = BO->getOpcode(); 6786503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks if (Opcode != BO_Assign && 6796503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks Opcode != BO_EQ && 6806503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks Opcode != BO_NE) 68131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks return; 68231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 6836503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks if (isZero(BO->getRHS())) { 6846503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks check(BO->getLHS()); 6856503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks return; 6866503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks } 68731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 6886503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks if (Opcode != BO_Assign && isZero(BO->getLHS())) { 6896503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks check(BO->getRHS()); 6906503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks return; 6916503255e4fa0689f427b3b798180fceac29c98c2Anna Zaks } 69231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks} 69331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 694722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksvoid IvarInvalidationCheckerImpl::MethodCrawler::VisitObjCMessageExpr( 695664566c37f81d70226df22c12aa05d1603b620f3Anna Zaks const ObjCMessageExpr *ME) { 69631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const ObjCMethodDecl *MD = ME->getMethodDecl(); 69731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks const Expr *Receiver = ME->getInstanceReceiver(); 69831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 69931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks // Stop if we are calling '[self invalidate]'. 70026db7dbf67b1532b2d617b3a85428699a1ffc997Anna Zaks if (Receiver && isInvalidationMethod(MD, /*LookForPartial*/ false)) 701bbff82f302a1dd67589f65912351978905f0c5a7Anna Zaks if (Receiver->isObjCSelfExpr()) { 702bbff82f302a1dd67589f65912351978905f0c5a7Anna Zaks CalledAnotherInvalidationMethod = true; 703bbff82f302a1dd67589f65912351978905f0c5a7Anna Zaks return; 70431f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 70531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 70631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks // Check if we call a setter and set the property to 'nil'. 70731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) { 70831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); 70931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD); 71031f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (IvI != PropertySetterToIvarMap.end()) { 71131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks markInvalidated(IvI->second); 7125bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks return; 7135bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 7145bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks } 71531f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 71631f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks // Check if we call the 'invalidation' routine on the ivar. 71731f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks if (Receiver) { 71831f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks InvalidationMethod = MD; 71931f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks check(Receiver->IgnoreParenCasts()); 7206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines InvalidationMethod = nullptr; 72131f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks } 72231f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks 72331f69cc770888ec0f0f7012212e5df7979aba4f3Anna Zaks VisitStmt(ME); 7245bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 7255bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks} 7265bf5c2ec54ede5352293e5739e9b44bea2f6b01bAnna Zaks 727722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks// Register the checkers. 728722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksnamespace { 729722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 730722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaksclass IvarInvalidationChecker : 731722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks public Checker<check::ASTDecl<ObjCImplementationDecl> > { 732722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zakspublic: 733722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks ChecksFilter Filter; 734722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zakspublic: 735722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr, 736722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks BugReporter &BR) const { 737722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks IvarInvalidationCheckerImpl Walker(Mgr, BR, Filter); 738722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks Walker.visit(D); 739722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks } 740722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks}; 741722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks} 742722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 743651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#define REGISTER_CHECKER(name) \ 744651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines void ento::register##name(CheckerManager &mgr) { \ 745651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines IvarInvalidationChecker *checker = \ 746651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mgr.registerChecker<IvarInvalidationChecker>(); \ 747651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines checker->Filter.check_##name = true; \ 748651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines checker->Filter.checkName_##name = mgr.getCurrentCheckName(); \ 749651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines } 750722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 751722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna ZaksREGISTER_CHECKER(InstanceVariableInvalidation) 752722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna ZaksREGISTER_CHECKER(MissingInvalidationMethod) 753722cd9e3c0142948b9eb3190211dbc0dd4da4105Anna Zaks 754