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