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
12d99bd55aSTed Kremenek //  (in it's 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"
19*507ff53eSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
23d99bd55aSTed Kremenek #include "clang/AST/DeclObjC.h"
24d99bd55aSTed Kremenek #include "clang/AST/Decl.h"
25d99bd55aSTed Kremenek 
26d99bd55aSTed Kremenek using namespace clang;
27d99bd55aSTed Kremenek using namespace ento;
28d99bd55aSTed Kremenek 
29d99bd55aSTed Kremenek namespace {
30d99bd55aSTed Kremenek class NSAutoreleasePoolChecker
31d99bd55aSTed Kremenek   : public CheckerVisitor<NSAutoreleasePoolChecker> {
32d99bd55aSTed Kremenek 
33d99bd55aSTed Kremenek   Selector releaseS;
34d99bd55aSTed Kremenek 
35d99bd55aSTed Kremenek public:
36d99bd55aSTed Kremenek     NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
37d99bd55aSTed Kremenek 
38d99bd55aSTed Kremenek   static void *getTag() {
39d99bd55aSTed Kremenek     static int x = 0;
40d99bd55aSTed Kremenek     return &x;
41d99bd55aSTed Kremenek   }
42d99bd55aSTed Kremenek 
4337ab726dSArgyrios Kyrtzidis   void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
44d99bd55aSTed Kremenek };
45d99bd55aSTed Kremenek 
46d99bd55aSTed Kremenek } // end anonymous namespace
47d99bd55aSTed Kremenek 
48d99bd55aSTed Kremenek 
49*507ff53eSArgyrios Kyrtzidis static void RegisterNSAutoreleasePoolChecker(ExprEngine &Eng) {
50d99bd55aSTed Kremenek   ASTContext &Ctx = Eng.getContext();
51d99bd55aSTed Kremenek   if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
52d99bd55aSTed Kremenek     Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
53d99bd55aSTed Kremenek                                                                       Ctx)));
54d99bd55aSTed Kremenek   }
55d99bd55aSTed Kremenek }
56d99bd55aSTed Kremenek 
57*507ff53eSArgyrios Kyrtzidis void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
58*507ff53eSArgyrios Kyrtzidis   mgr.addCheckerRegisterFunction(RegisterNSAutoreleasePoolChecker);
59*507ff53eSArgyrios Kyrtzidis }
60*507ff53eSArgyrios Kyrtzidis 
61d99bd55aSTed Kremenek void
6237ab726dSArgyrios Kyrtzidis NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
6337ab726dSArgyrios Kyrtzidis                                               ObjCMessage msg) {
64d99bd55aSTed Kremenek 
6537ab726dSArgyrios Kyrtzidis   const Expr *receiver = msg.getInstanceReceiver();
66d99bd55aSTed Kremenek   if (!receiver)
67d99bd55aSTed Kremenek     return;
68d99bd55aSTed Kremenek 
69d99bd55aSTed Kremenek   // FIXME: Enhance with value-tracking information instead of consulting
70d99bd55aSTed Kremenek   // the type of the expression.
71d99bd55aSTed Kremenek   const ObjCObjectPointerType* PT =
72d99bd55aSTed Kremenek     receiver->getType()->getAs<ObjCObjectPointerType>();
73d99bd55aSTed Kremenek 
74d99bd55aSTed Kremenek   if (!PT)
75d99bd55aSTed Kremenek     return;
76d99bd55aSTed Kremenek   const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
77d99bd55aSTed Kremenek   if (!OD)
78d99bd55aSTed Kremenek     return;
79d99bd55aSTed Kremenek   if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
80d99bd55aSTed Kremenek     return;
81d99bd55aSTed Kremenek 
82d99bd55aSTed Kremenek   // Sending 'release' message?
8337ab726dSArgyrios Kyrtzidis   if (msg.getSelector() != releaseS)
84d99bd55aSTed Kremenek     return;
85d99bd55aSTed Kremenek 
8637ab726dSArgyrios Kyrtzidis   SourceRange R = msg.getSourceRange();
87d99bd55aSTed Kremenek 
88d99bd55aSTed Kremenek   C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
89d99bd55aSTed Kremenek     "API Upgrade (Apple)",
90d99bd55aSTed Kremenek     "Use -drain instead of -release when using NSAutoreleasePool "
9137ab726dSArgyrios Kyrtzidis     "and garbage collection", R.getBegin(), &R, 1);
92d99bd55aSTed Kremenek }
93