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