NSAutoreleasePoolChecker.cpp revision 226633
1218887Sdim//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim//  This file defines a NSAutoreleasePoolChecker, a small checker that warns
11218887Sdim//  about subpar uses of NSAutoreleasePool.  Note that while the check itself
12226633Sdim//  (in its current form) could be written as a flow-insensitive check, in
13218887Sdim//  can be potentially enhanced in the future with flow-sensitive information.
14218887Sdim//  It is also a good example of the CheckerVisitor interface.
15218887Sdim//
16218887Sdim//===----------------------------------------------------------------------===//
17218887Sdim
18218887Sdim#include "ClangSACheckers.h"
19221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
20218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
21226633Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
22219077Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
24226633Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
25218887Sdim#include "clang/AST/DeclObjC.h"
26218887Sdim#include "clang/AST/Decl.h"
27218887Sdim
28218887Sdimusing namespace clang;
29218887Sdimusing namespace ento;
30218887Sdim
31218887Sdimnamespace {
32218887Sdimclass NSAutoreleasePoolChecker
33221345Sdim  : public Checker<check::PreObjCMessage> {
34218887Sdim
35219077Sdim  mutable Selector releaseS;
36218887Sdim
37218887Sdimpublic:
38219077Sdim  void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
39218887Sdim};
40218887Sdim
41218887Sdim} // end anonymous namespace
42218887Sdim
43219077Sdimvoid NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg,
44219077Sdim                                                   CheckerContext &C) const {
45218887Sdim
46218887Sdim  const Expr *receiver = msg.getInstanceReceiver();
47218887Sdim  if (!receiver)
48218887Sdim    return;
49218887Sdim
50218887Sdim  // FIXME: Enhance with value-tracking information instead of consulting
51218887Sdim  // the type of the expression.
52218887Sdim  const ObjCObjectPointerType* PT =
53218887Sdim    receiver->getType()->getAs<ObjCObjectPointerType>();
54218887Sdim
55218887Sdim  if (!PT)
56218887Sdim    return;
57226633Sdim  const ObjCInterfaceDecl *OD = PT->getInterfaceDecl();
58218887Sdim  if (!OD)
59218887Sdim    return;
60218887Sdim  if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
61218887Sdim    return;
62219077Sdim
63219077Sdim  if (releaseS.isNull())
64219077Sdim    releaseS = GetNullarySelector("release", C.getASTContext());
65218887Sdim  // Sending 'release' message?
66218887Sdim  if (msg.getSelector() != releaseS)
67218887Sdim    return;
68218887Sdim
69218887Sdim  SourceRange R = msg.getSourceRange();
70226633Sdim  BugReporter &BR = C.getBugReporter();
71226633Sdim  const LocationContext *LC = C.getPredecessor()->getLocationContext();
72226633Sdim  const SourceManager &SM = BR.getSourceManager();
73226633Sdim  const Expr *E = msg.getMsgOrPropExpr();
74226633Sdim  PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(E, SM, LC);
75218887Sdim  C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
76218887Sdim    "API Upgrade (Apple)",
77218887Sdim    "Use -drain instead of -release when using NSAutoreleasePool "
78226633Sdim    "and garbage collection", L, &R, 1);
79218887Sdim}
80219077Sdim
81219077Sdimvoid ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
82226633Sdim  if (mgr.getLangOptions().getGC() != LangOptions::NonGC)
83219077Sdim    mgr.registerChecker<NSAutoreleasePoolChecker>();
84219077Sdim}
85