NSAutoreleasePoolChecker.cpp revision 695fb502825a53ccd178ec1c85c77929d88acb71
1//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines a NSAutoreleasePoolChecker, a small checker that warns
11//  about subpar uses of NSAutoreleasePool.  Note that while the check itself
12//  (in it's current form) could be written as a flow-insensitive check, in
13//  can be potentially enhanced in the future with flow-sensitive information.
14//  It is also a good example of the CheckerVisitor interface.
15//
16//===----------------------------------------------------------------------===//
17
18#include "ClangSACheckers.h"
19#include "clang/StaticAnalyzer/Core/CheckerManager.h"
20#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
23#include "clang/AST/DeclObjC.h"
24#include "clang/AST/Decl.h"
25
26using namespace clang;
27using namespace ento;
28
29namespace {
30class NSAutoreleasePoolChecker
31  : public CheckerVisitor<NSAutoreleasePoolChecker> {
32
33  Selector releaseS;
34
35public:
36    NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
37
38  static void *getTag() {
39    static int x = 0;
40    return &x;
41  }
42
43  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
44};
45
46} // end anonymous namespace
47
48
49static void RegisterNSAutoreleasePoolChecker(ExprEngine &Eng) {
50  ASTContext &Ctx = Eng.getContext();
51  if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
52    Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
53                                                                      Ctx)));
54  }
55}
56
57void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
58  mgr.addCheckerRegisterFunction(RegisterNSAutoreleasePoolChecker);
59}
60
61void
62NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
63                                              ObjCMessage msg) {
64
65  const Expr *receiver = msg.getInstanceReceiver();
66  if (!receiver)
67    return;
68
69  // FIXME: Enhance with value-tracking information instead of consulting
70  // the type of the expression.
71  const ObjCObjectPointerType* PT =
72    receiver->getType()->getAs<ObjCObjectPointerType>();
73
74  if (!PT)
75    return;
76  const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
77  if (!OD)
78    return;
79  if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
80    return;
81
82  // Sending 'release' message?
83  if (msg.getSelector() != releaseS)
84    return;
85
86  SourceRange R = msg.getSourceRange();
87
88  C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
89    "API Upgrade (Apple)",
90    "Use -drain instead of -release when using NSAutoreleasePool "
91    "and garbage collection", R.getBegin(), &R, 1);
92}
93