1*67e74705SXin Li //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This file defines a NSAutoreleasePoolChecker, a small checker that warns
11*67e74705SXin Li // about subpar uses of NSAutoreleasePool. Note that while the check itself
12*67e74705SXin Li // (in its current form) could be written as a flow-insensitive check, in
13*67e74705SXin Li // can be potentially enhanced in the future with flow-sensitive information.
14*67e74705SXin Li // It is also a good example of the CheckerVisitor interface.
15*67e74705SXin Li //
16*67e74705SXin Li //===----------------------------------------------------------------------===//
17*67e74705SXin Li
18*67e74705SXin Li #include "ClangSACheckers.h"
19*67e74705SXin Li #include "clang/AST/Decl.h"
20*67e74705SXin Li #include "clang/AST/DeclObjC.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
23*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
24*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerManager.h"
25*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
26*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
27*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
28*67e74705SXin Li
29*67e74705SXin Li using namespace clang;
30*67e74705SXin Li using namespace ento;
31*67e74705SXin Li
32*67e74705SXin Li namespace {
33*67e74705SXin Li class NSAutoreleasePoolChecker
34*67e74705SXin Li : public Checker<check::PreObjCMessage> {
35*67e74705SXin Li mutable std::unique_ptr<BugType> BT;
36*67e74705SXin Li mutable Selector releaseS;
37*67e74705SXin Li
38*67e74705SXin Li public:
39*67e74705SXin Li void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
40*67e74705SXin Li };
41*67e74705SXin Li
42*67e74705SXin Li } // end anonymous namespace
43*67e74705SXin Li
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const44*67e74705SXin Li void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
45*67e74705SXin Li CheckerContext &C) const {
46*67e74705SXin Li if (!msg.isInstanceMessage())
47*67e74705SXin Li return;
48*67e74705SXin Li
49*67e74705SXin Li const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
50*67e74705SXin Li if (!OD)
51*67e74705SXin Li return;
52*67e74705SXin Li if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
53*67e74705SXin Li return;
54*67e74705SXin Li
55*67e74705SXin Li if (releaseS.isNull())
56*67e74705SXin Li releaseS = GetNullarySelector("release", C.getASTContext());
57*67e74705SXin Li // Sending 'release' message?
58*67e74705SXin Li if (msg.getSelector() != releaseS)
59*67e74705SXin Li return;
60*67e74705SXin Li
61*67e74705SXin Li if (!BT)
62*67e74705SXin Li BT.reset(new BugType(this, "Use -drain instead of -release",
63*67e74705SXin Li "API Upgrade (Apple)"));
64*67e74705SXin Li
65*67e74705SXin Li ExplodedNode *N = C.generateNonFatalErrorNode();
66*67e74705SXin Li if (!N) {
67*67e74705SXin Li assert(0);
68*67e74705SXin Li return;
69*67e74705SXin Li }
70*67e74705SXin Li
71*67e74705SXin Li auto Report = llvm::make_unique<BugReport>(
72*67e74705SXin Li *BT, "Use -drain instead of -release when using NSAutoreleasePool and "
73*67e74705SXin Li "garbage collection", N);
74*67e74705SXin Li Report->addRange(msg.getSourceRange());
75*67e74705SXin Li C.emitReport(std::move(Report));
76*67e74705SXin Li }
77*67e74705SXin Li
registerNSAutoreleasePoolChecker(CheckerManager & mgr)78*67e74705SXin Li void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
79*67e74705SXin Li if (mgr.getLangOpts().getGC() != LangOptions::NonGC)
80*67e74705SXin Li mgr.registerChecker<NSAutoreleasePoolChecker>();
81*67e74705SXin Li }
82