1311118Sdim//==- ObjCPropertyChecker.cpp - Check ObjC properties ------------*- C++ -*-==//
2311118Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6311118Sdim//
7311118Sdim//===----------------------------------------------------------------------===//
8311118Sdim//
9311118Sdim//  This checker finds issues with Objective-C properties.
10311118Sdim//  Currently finds only one kind of issue:
11311118Sdim//  - Find synthesized properties with copy attribute of mutable NS collection
12311118Sdim//    types. Calling -copy on such collections produces an immutable copy,
13311118Sdim//    which contradicts the type of the property.
14311118Sdim//
15311118Sdim//===----------------------------------------------------------------------===//
16311118Sdim
17344779Sdim#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18311118Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19311118Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
20311118Sdim
21311118Sdimusing namespace clang;
22311118Sdimusing namespace ento;
23311118Sdim
24311118Sdimnamespace {
25311118Sdimclass ObjCPropertyChecker
26311118Sdim    : public Checker<check::ASTDecl<ObjCPropertyDecl>> {
27311118Sdim  void checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const;
28311118Sdim
29311118Sdimpublic:
30311118Sdim  void checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr,
31311118Sdim                    BugReporter &BR) const;
32311118Sdim};
33311118Sdim} // end anonymous namespace.
34311118Sdim
35311118Sdimvoid ObjCPropertyChecker::checkASTDecl(const ObjCPropertyDecl *D,
36311118Sdim                                       AnalysisManager &Mgr,
37311118Sdim                                       BugReporter &BR) const {
38311118Sdim  checkCopyMutable(D, BR);
39311118Sdim}
40311118Sdim
41311118Sdimvoid ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,
42311118Sdim                                           BugReporter &BR) const {
43311118Sdim  if (D->isReadOnly() || D->getSetterKind() != ObjCPropertyDecl::Copy)
44311118Sdim    return;
45311118Sdim
46311118Sdim  QualType T = D->getType();
47311118Sdim  if (!T->isObjCObjectPointerType())
48311118Sdim    return;
49311118Sdim
50311118Sdim  const std::string &PropTypeName(T->getPointeeType().getCanonicalType()
51311118Sdim                                                     .getUnqualifiedType()
52311118Sdim                                                     .getAsString());
53311118Sdim  if (!StringRef(PropTypeName).startswith("NSMutable"))
54311118Sdim    return;
55311118Sdim
56311118Sdim  const ObjCImplDecl *ImplD = nullptr;
57311118Sdim  if (const ObjCInterfaceDecl *IntD =
58311118Sdim          dyn_cast<ObjCInterfaceDecl>(D->getDeclContext())) {
59311118Sdim    ImplD = IntD->getImplementation();
60321369Sdim  } else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) {
61311118Sdim    ImplD = CatD->getClassInterface()->getImplementation();
62311118Sdim  }
63311118Sdim
64311118Sdim  if (!ImplD || ImplD->HasUserDeclaredSetterMethod(D))
65311118Sdim    return;
66311118Sdim
67311118Sdim  SmallString<128> Str;
68311118Sdim  llvm::raw_svector_ostream OS(Str);
69311118Sdim  OS << "Property of mutable type '" << PropTypeName
70311118Sdim     << "' has 'copy' attribute; an immutable object will be stored instead";
71311118Sdim
72311118Sdim  BR.EmitBasicReport(
73311118Sdim      D, this, "Objective-C property misuse", "Logic error", OS.str(),
74311118Sdim      PathDiagnosticLocation::createBegin(D, BR.getSourceManager()),
75311118Sdim      D->getSourceRange());
76311118Sdim}
77311118Sdim
78311118Sdimvoid ento::registerObjCPropertyChecker(CheckerManager &Mgr) {
79311118Sdim  Mgr.registerChecker<ObjCPropertyChecker>();
80311118Sdim}
81353358Sdim
82353358Sdimbool ento::shouldRegisterObjCPropertyChecker(const LangOptions &LO) {
83353358Sdim  return true;
84353358Sdim}
85