1d99bd55aSTed Kremenek //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2d99bd55aSTed Kremenek //
3d99bd55aSTed Kremenek //                     The LLVM Compiler Infrastructure
4d99bd55aSTed Kremenek //
5d99bd55aSTed Kremenek // This file is distributed under the University of Illinois Open Source
6d99bd55aSTed Kremenek // License. See LICENSE.TXT for details.
7d99bd55aSTed Kremenek //
8d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
9d99bd55aSTed Kremenek //
10d99bd55aSTed Kremenek //  This file defines a NSAutoreleasePoolChecker, a small checker that warns
11d99bd55aSTed Kremenek //  about subpar uses of NSAutoreleasePool.  Note that while the check itself
12087611edSJordy Rose //  (in its current form) could be written as a flow-insensitive check, in
13d99bd55aSTed Kremenek //  can be potentially enhanced in the future with flow-sensitive information.
14d99bd55aSTed Kremenek //  It is also a good example of the CheckerVisitor interface.
15d99bd55aSTed Kremenek //
16d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
17d99bd55aSTed Kremenek 
189d4d4f91SArgyrios Kyrtzidis #include "ClangSACheckers.h"
196a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
20507ff53eSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
226b1c2126SAnna Zaks #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
23*4f7df9beSJordan Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
24087611edSJordy Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
26d99bd55aSTed Kremenek #include "clang/AST/DeclObjC.h"
27d99bd55aSTed Kremenek #include "clang/AST/Decl.h"
28d99bd55aSTed Kremenek 
29d99bd55aSTed Kremenek using namespace clang;
30d99bd55aSTed Kremenek using namespace ento;
31d99bd55aSTed Kremenek 
32d99bd55aSTed Kremenek namespace {
33d99bd55aSTed Kremenek class NSAutoreleasePoolChecker
346a5674ffSArgyrios Kyrtzidis   : public Checker<check::PreObjCMessage> {
35e2778999SDylan Noblesmith   mutable OwningPtr<BugType> BT;
36aad83725SArgyrios Kyrtzidis   mutable Selector releaseS;
37d99bd55aSTed Kremenek 
38d99bd55aSTed Kremenek public:
39547060b3SJordan Rose   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
40d99bd55aSTed Kremenek };
41d99bd55aSTed Kremenek 
42d99bd55aSTed Kremenek } // end anonymous namespace
43d99bd55aSTed Kremenek 
44547060b3SJordan Rose void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
45aad83725SArgyrios Kyrtzidis                                                    CheckerContext &C) const {
46547060b3SJordan Rose   if (!msg.isInstanceMessage())
47d99bd55aSTed Kremenek     return;
48d99bd55aSTed Kremenek 
49547060b3SJordan Rose   const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
50d99bd55aSTed Kremenek   if (!OD)
51d99bd55aSTed Kremenek     return;
52547060b3SJordan Rose   if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
53d99bd55aSTed Kremenek     return;
54d99bd55aSTed Kremenek 
55aad83725SArgyrios Kyrtzidis   if (releaseS.isNull())
56aad83725SArgyrios Kyrtzidis     releaseS = GetNullarySelector("release", C.getASTContext());
57d99bd55aSTed Kremenek   // Sending 'release' message?
5837ab726dSArgyrios Kyrtzidis   if (msg.getSelector() != releaseS)
59d99bd55aSTed Kremenek     return;
60d99bd55aSTed Kremenek 
616b1c2126SAnna Zaks   if (!BT)
626b1c2126SAnna Zaks     BT.reset(new BugType("Use -drain instead of -release",
636b1c2126SAnna Zaks                          "API Upgrade (Apple)"));
646b1c2126SAnna Zaks 
656b1c2126SAnna Zaks   ExplodedNode *N = C.addTransition();
666b1c2126SAnna Zaks   if (!N) {
676b1c2126SAnna Zaks     assert(0);
686b1c2126SAnna Zaks     return;
696b1c2126SAnna Zaks   }
706b1c2126SAnna Zaks 
716b1c2126SAnna Zaks   BugReport *Report = new BugReport(*BT, "Use -drain instead of -release when "
726b1c2126SAnna Zaks     "using NSAutoreleasePool and garbage collection", N);
736b1c2126SAnna Zaks   Report->addRange(msg.getSourceRange());
746b1c2126SAnna Zaks   C.EmitReport(Report);
75d99bd55aSTed Kremenek }
76aad83725SArgyrios Kyrtzidis 
77aad83725SArgyrios Kyrtzidis void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
78bbafb8a7SDavid Blaikie   if (mgr.getLangOpts().getGC() != LangOptions::NonGC)
79aad83725SArgyrios Kyrtzidis     mgr.registerChecker<NSAutoreleasePoolChecker>();
80aad83725SArgyrios Kyrtzidis }
81