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.
43a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramerstatic bool DefaultMethodFilter(const ObjCMethodDecl *M) {
44a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer  if (M->getMethodFamily() == OMF_init || M->getMethodFamily() == OMF_dealloc ||
45a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer      M->getMethodFamily() == OMF_copy ||
46a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer      M->getMethodFamily() == OMF_mutableCopy ||
47a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer      M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
48a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer      M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
49a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer    return true;
50a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer  return false;
51a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer}
5239a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
5388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksclass DirectIvarAssignment :
5488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  public Checker<check::ASTDecl<ObjCImplementationDecl> > {
5588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
5688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  typedef llvm::DenseMap<const ObjCIvarDecl*,
5788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                         const ObjCPropertyDecl*> IvarToPropertyMapTy;
5888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
5988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  /// A helper class, which walks the AST and locates all assignments to ivars
6088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  /// in the given function.
6188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
6288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const IvarToPropertyMapTy &IvarToPropMap;
6388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const ObjCMethodDecl *MD;
6488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const ObjCInterfaceDecl *InterfD;
6588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    BugReporter &BR;
66651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    const CheckerBase *Checker;
6788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    LocationOrAnalysisDeclContext DCtx;
6888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
6988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  public:
7088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD,
71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                  const ObjCInterfaceDecl *InID, BugReporter &InBR,
72651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                  const CheckerBase *Checker, AnalysisDeclContext *InDCtx)
73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR),
74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Checker(Checker), DCtx(InDCtx) {}
7588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
7688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    void VisitStmt(const Stmt *S) { VisitChildren(S); }
7788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
7888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    void VisitBinaryOperator(const BinaryOperator *BO);
7988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
8088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    void VisitChildren(const Stmt *S) {
81a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      for (const Stmt *Child : S->children())
82a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        if (Child)
83a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          this->Visit(Child);
8488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    }
8588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  };
8688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
8788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zakspublic:
88a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer  bool (*ShouldSkipMethod)(const ObjCMethodDecl *);
8939a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
9039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  DirectIvarAssignment() : ShouldSkipMethod(&DefaultMethodFilter) {}
9139a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
9288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
9388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                    BugReporter &BR) const;
9488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks};
9588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
9688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksstatic const ObjCIvarDecl *findPropertyBackingIvar(const ObjCPropertyDecl *PD,
97bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                               const ObjCInterfaceDecl *InterD,
98bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                               ASTContext &Ctx) {
9988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Check for synthesized ivars.
10088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  ObjCIvarDecl *ID = PD->getPropertyIvarDecl();
10188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (ID)
10288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return ID;
10388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
104bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  ObjCInterfaceDecl *NonConstInterD = const_cast<ObjCInterfaceDecl*>(InterD);
105bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks
10688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Check for existing "_PropName".
107bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  ID = NonConstInterD->lookupInstanceVariable(PD->getDefaultSynthIvarName(Ctx));
10888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (ID)
10988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return ID;
11088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
11188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Check for existing "PropName".
11288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  IdentifierInfo *PropIdent = PD->getIdentifier();
113bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  ID = NonConstInterD->lookupInstanceVariable(PropIdent);
11488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
11588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  return ID;
11688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
11788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
11888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksvoid DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
11988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                                       AnalysisManager& Mgr,
12088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                                       BugReporter &BR) const {
12188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  const ObjCInterfaceDecl *InterD = D->getClassInterface();
12288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
12388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
12488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  IvarToPropertyMapTy IvarToPropMap;
12588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
12688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  // Find all properties for this class.
127651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (const auto *PD : InterD->properties()) {
12888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    // Find the corresponding IVar.
129bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks    const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD,
130bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks                                                     Mgr.getASTContext());
13188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
13288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    if (!ID)
13388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      continue;
13488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
13588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    // Store the IVar to property mapping.
13688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    IvarToPropMap[ID] = PD;
13788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  }
13888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
13988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (IvarToPropMap.empty())
14088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return;
14188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
142651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (const auto *M : D->instance_methods()) {
14388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M);
14488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
14539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    if ((*ShouldSkipMethod)(M))
14688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      continue;
14788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
14888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    const Stmt *Body = M->getBody();
149bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks    assert(Body);
15088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
151651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this,
152651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                     DCtx);
15388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    MC.VisitStmt(Body);
15488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  }
15588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
15688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
157fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaksstatic bool isAnnotatedToAllowDirectAssignment(const Decl *D) {
158651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (const auto *Ann : D->specific_attrs<AnnotateAttr>())
159d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks    if (Ann->getAnnotation() ==
160d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks        "objc_allow_direct_instance_variable_assignment")
161d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks      return true;
162d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks  return false;
163d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks}
164d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks
16588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksvoid DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
16688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks                                                    const BinaryOperator *BO) {
16788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (!BO->isAssignmentOp())
16888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return;
16988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
170bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks  const ObjCIvarRefExpr *IvarRef =
171bf24792e00a47fd9d74ff21e21d2cbffc6d62818Anna Zaks          dyn_cast<ObjCIvarRefExpr>(BO->getLHS()->IgnoreParenCasts());
17288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
17388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (!IvarRef)
17488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    return;
17588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
17688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  if (const ObjCIvarDecl *D = IvarRef->getDecl()) {
17788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D);
178d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks
17988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    if (I != IvarToPropMap.end()) {
18088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      const ObjCPropertyDecl *PD = I->second;
181fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      // Skip warnings on Ivars, annotated with
182d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks      // objc_allow_direct_instance_variable_assignment. This annotation serves
183fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      // as a false positive suppression mechanism for the checker. The
184fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      // annotation is allowed on properties and ivars.
185fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks      if (isAnnotatedToAllowDirectAssignment(PD) ||
186fa2b53c5780a8a6f38803a26e3c6f9f0a9ba8b4dAnna Zaks          isAnnotatedToAllowDirectAssignment(D))
187d7b1d2467d8bf01be5068dbbad1a6324cee8bf4aAnna Zaks        return;
18888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
18988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      ObjCMethodDecl *GetterMethod =
19088a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          InterfD->getInstanceMethod(PD->getGetterName());
19188a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      ObjCMethodDecl *SetterMethod =
19288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          InterfD->getInstanceMethod(PD->getSetterName());
19388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
19488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      if (SetterMethod && SetterMethod->getCanonicalDecl() == MD)
19588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        return;
19688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
19788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks      if (GetterMethod && GetterMethod->getCanonicalDecl() == MD)
19888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks        return;
19988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
200651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      BR.EmitBasicReport(
201651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          MD, Checker, "Property access", categories::CoreFoundationObjectiveC,
20288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks          "Direct assignment to an instance variable backing a property; "
203651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          "use the setter instead",
204651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          PathDiagnosticLocation(IvarRef, BR.getSourceManager(), DCtx));
20588a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks    }
20688a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  }
20788a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
20888a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
20988a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks
21039a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks// Register the checker that checks for direct accesses in all functions,
21139a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks// except for the initialization and copy routines.
21288a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaksvoid ento::registerDirectIvarAssignment(CheckerManager &mgr) {
21388a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks  mgr.registerChecker<DirectIvarAssignment>();
21488a83e3f3bade5497ff371ed5a570b83d9373e3aAnna Zaks}
21539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
21639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks// Register the checker that checks for direct accesses in functions annotated
217a05d2741c40c71b59cf6d2f8bbc5d433a5d0e6deTed Kremenek// with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))).
218a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramerstatic bool AttrFilter(const ObjCMethodDecl *M) {
219651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (const auto *Ann : M->specific_attrs<AnnotateAttr>())
220a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer    if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
221a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer      return false;
222a79a20e054312bc6673d4ddb8254d8d2681bed9cBenjamin Kramer  return true;
22339a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks}
22439a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks
22539a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaksvoid ento::registerDirectIvarAssignmentForAnnotatedFunctions(
22639a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks    CheckerManager &mgr) {
22739a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks  mgr.registerChecker<DirectIvarAssignment>()->ShouldSkipMethod = &AttrFilter;
22839a62fcd3003785d9cc913ab2820be2f6f27bb40Anna Zaks}
229