188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//=- DirectIvarAssignment.cpp - Check rules on ObjC properties -*- C++ ----*-==//
288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//
388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//                     The LLVM Compiler Infrastructure
488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//
588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks// This file is distributed under the University of Illinois Open Source
688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks// License. See LICENSE.TXT for details.
788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//
888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//===----------------------------------------------------------------------===//
988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//
10fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//  Check that Objective C properties are set with the setter, not though a
11fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//      direct assignment.
12fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//
13fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//  Two versions of a checker exist: one that checks all methods and the other
14fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//      that only checks the methods annotated with
15fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//      __attribute__((annotate("objc_no_direct_instance_variable_assignment")))
16fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//
17fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//  The checker does not warn about assignments to Ivars, annotated with
18fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//       __attribute__((objc_allow_direct_instance_variable_assignment"))). This
19fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//      annotation serves as a false positive suppression mechanism for the
20fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks//      checker. The annotation is allowed on properties and Ivars.
2188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//
2288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks//===----------------------------------------------------------------------===//
2388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
2488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks#include "ClangSACheckers.h"
2539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks#include "clang/AST/Attr.h"
2688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks#include "clang/AST/DeclObjC.h"
2788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks#include "clang/AST/StmtVisitor.h"
2855fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
2955fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h"
3055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
3188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks#include "llvm/ADT/DenseMap.h"
3288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
3388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksusing namespace clang;
3488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksusing namespace ento;
3588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
3688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksnamespace {
3788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
3839a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks/// The default method filter, which is used to filter out the methods on which
3939a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks/// the check should not be performed.
4039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks///
4139a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks/// Checks for the init, dealloc, and any other functions that might be allowed
4239a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks/// to perform direct instance variable assignment based on their name.
4339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaksstruct MethodFilter {
44aacadfea7a7174116dbde09937098763a3211396Daniel Jasper  virtual ~MethodFilter() {}
4539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  virtual bool operator()(ObjCMethodDecl *M) {
4639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    if (M->getMethodFamily() == OMF_init ||
4739a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks        M->getMethodFamily() == OMF_dealloc ||
4839a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks        M->getMethodFamily() == OMF_copy ||
4939a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks        M->getMethodFamily() == OMF_mutableCopy ||
5039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks        M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
5139a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks        M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
5239a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks      return true;
5339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    return false;
5439a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  }
5539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks};
5639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
5739a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaksstatic MethodFilter DefaultMethodFilter;
5839a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
5988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksclass DirectIvarAssignment :
6088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  public Checker<check::ASTDecl<ObjCImplementationDecl> > {
6188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
6288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  typedef llvm::DenseMap<const ObjCIvarDecl*,
6388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                         const ObjCPropertyDecl*> IvarToPropertyMapTy;
6488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
6588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  /// A helper class, which walks the AST and locates all assignments to ivars
6688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  /// in the given function.
6788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
6888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const IvarToPropertyMapTy &IvarToPropMap;
6988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const ObjCMethodDecl *MD;
7088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const ObjCInterfaceDecl *InterfD;
7188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    BugReporter &BR;
7288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    LocationOrAnalysisDeclContext DCtx;
7388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
7488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  public:
7588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD,
7688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        const ObjCInterfaceDecl *InID,
7788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        BugReporter &InBR, AnalysisDeclContext *InDCtx)
7888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), DCtx(InDCtx) {}
7988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
8088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    void VisitStmt(const Stmt *S) { VisitChildren(S); }
8188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
8288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    void VisitBinaryOperator(const BinaryOperator *BO);
8388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
8488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    void VisitChildren(const Stmt *S) {
8588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      for (Stmt::const_child_range I = S->children(); I; ++I)
8688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        if (*I)
8788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks         this->Visit(*I);
8888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    }
8988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  };
9088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
9188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zakspublic:
9239a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  MethodFilter *ShouldSkipMethod;
9339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
9439a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  DirectIvarAssignment() : ShouldSkipMethod(&DefaultMethodFilter) {}
9539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
9688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
9788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                    BugReporter &BR) const;
9888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks};
9988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
10088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksstatic const ObjCIvarDecl *findPropertyBackingIvar(const ObjCPropertyDecl *PD,
101bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                               const ObjCInterfaceDecl *InterD,
102bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                               ASTContext &Ctx) {
10388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Check for synthesized ivars.
10488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  ObjCIvarDecl *ID = PD->getPropertyIvarDecl();
10588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (ID)
10688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return ID;
10788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
108bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  ObjCInterfaceDecl *NonConstInterD = const_cast<ObjCInterfaceDecl*>(InterD);
109bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks
11088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Check for existing "_PropName".
111bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  ID = NonConstInterD->lookupInstanceVariable(PD->getDefaultSynthIvarName(Ctx));
11288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (ID)
11388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return ID;
11488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
11588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Check for existing "PropName".
11688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  IdentifierInfo *PropIdent = PD->getIdentifier();
117bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  ID = NonConstInterD->lookupInstanceVariable(PropIdent);
11888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
11988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  return ID;
12088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
12188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
12288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksvoid DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
12388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                                       AnalysisManager& Mgr,
12488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                                       BugReporter &BR) const {
12588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  const ObjCInterfaceDecl *InterD = D->getClassInterface();
12688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
12788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
12888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  IvarToPropertyMapTy IvarToPropMap;
12988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
13088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Find all properties for this class.
13188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  for (ObjCInterfaceDecl::prop_iterator I = InterD->prop_begin(),
13288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      E = InterD->prop_end(); I != E; ++I) {
13388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    ObjCPropertyDecl *PD = *I;
13488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
13588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    // Find the corresponding IVar.
136bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks    const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD,
137bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                                     Mgr.getASTContext());
13888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
13988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    if (!ID)
14088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      continue;
14188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
14288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    // Store the IVar to property mapping.
14388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    IvarToPropMap[ID] = PD;
14488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  }
14588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
14688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (IvarToPropMap.empty())
14788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return;
14888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
14988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
15088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      E = D->instmeth_end(); I != E; ++I) {
15188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
15288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    ObjCMethodDecl *M = *I;
15388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M);
15488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
15539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    if ((*ShouldSkipMethod)(M))
15688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      continue;
15788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
15888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const Stmt *Body = M->getBody();
159bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks    assert(Body);
16088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
16188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, DCtx);
16288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    MC.VisitStmt(Body);
16388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  }
16488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
16588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
166fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaksstatic bool isAnnotatedToAllowDirectAssignment(const Decl *D) {
167d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks  for (specific_attr_iterator<AnnotateAttr>
168d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks       AI = D->specific_attr_begin<AnnotateAttr>(),
169d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks       AE = D->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
170d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks    const AnnotateAttr *Ann = *AI;
171d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks    if (Ann->getAnnotation() ==
172d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks        "objc_allow_direct_instance_variable_assignment")
173d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks      return true;
174d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks  }
175d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks  return false;
176d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks}
177d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks
17888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksvoid DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
17988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                                                    const BinaryOperator *BO) {
18088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (!BO->isAssignmentOp())
18188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return;
18288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
183bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  const ObjCIvarRefExpr *IvarRef =
184bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks          dyn_cast<ObjCIvarRefExpr>(BO->getLHS()->IgnoreParenCasts());
18588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
18688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (!IvarRef)
18788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return;
18888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
18988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (const ObjCIvarDecl *D = IvarRef->getDecl()) {
19088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D);
191d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks
19288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    if (I != IvarToPropMap.end()) {
19388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      const ObjCPropertyDecl *PD = I->second;
194fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      // Skip warnings on Ivars, annotated with
195d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks      // objc_allow_direct_instance_variable_assignment. This annotation serves
196fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      // as a false positive suppression mechanism for the checker. The
197fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      // annotation is allowed on properties and ivars.
198fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      if (isAnnotatedToAllowDirectAssignment(PD) ||
199fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks          isAnnotatedToAllowDirectAssignment(D))
200d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks        return;
20188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
20288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      ObjCMethodDecl *GetterMethod =
20388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          InterfD->getInstanceMethod(PD->getGetterName());
20488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      ObjCMethodDecl *SetterMethod =
20588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          InterfD->getInstanceMethod(PD->getSetterName());
20688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
20788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      if (SetterMethod && SetterMethod->getCanonicalDecl() == MD)
20888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        return;
20988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
21088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      if (GetterMethod && GetterMethod->getCanonicalDecl() == MD)
21188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        return;
21288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
21388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      BR.EmitBasicReport(MD,
21488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          "Property access",
21588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          categories::CoreFoundationObjectiveC,
21688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          "Direct assignment to an instance variable backing a property; "
217bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks          "use the setter instead", PathDiagnosticLocation(IvarRef,
218bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                                          BR.getSourceManager(),
219bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                                          DCtx));
22088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    }
22188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  }
22288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
22388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
22488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
22539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks// Register the checker that checks for direct accesses in all functions,
22639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks// except for the initialization and copy routines.
22788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksvoid ento::registerDirectIvarAssignment(CheckerManager &mgr) {
22888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  mgr.registerChecker<DirectIvarAssignment>();
22988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
23039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
23139a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks// Register the checker that checks for direct accesses in functions annotated
232a05d2741c40c71b59cf6d2f8bbc5d433a5d0e6deTed Kremenek// with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))).
23339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaksnamespace {
23439a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaksstruct InvalidatorMethodFilter : MethodFilter {
235aacadfea7a7174116dbde09937098763a3211396Daniel Jasper  virtual ~InvalidatorMethodFilter() {}
23639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  virtual bool operator()(ObjCMethodDecl *M) {
23739a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    for (specific_attr_iterator<AnnotateAttr>
23839a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks         AI = M->specific_attr_begin<AnnotateAttr>(),
23939a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks         AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
24039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks      const AnnotateAttr *Ann = *AI;
241a05d2741c40c71b59cf6d2f8bbc5d433a5d0e6deTed Kremenek      if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
24239a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks        return false;
24339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    }
24439a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    return true;
24539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  }
24639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks};
24739a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
24839a62fcd3003785d9cc913ab2820be2f6f27bb40Anna ZaksInvalidatorMethodFilter AttrFilter;
24939a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks}
25039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
25139a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaksvoid ento::registerDirectIvarAssignmentForAnnotatedFunctions(
25239a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    CheckerManager &mgr) {
25339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  mgr.registerChecker<DirectIvarAssignment>()->ShouldSkipMethod = &AttrFilter;
25439a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks}
255