154cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
254cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//
354cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//                     The LLVM Compiler Infrastructure
454cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//
554cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek// This file is distributed under the University of Illinois Open Source
654cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek// License. See LICENSE.TXT for details.
754cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//
854cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//===----------------------------------------------------------------------===//
954cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//
1054cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//  This file defines a NSAutoreleasePoolChecker, a small checker that warns
1154cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//  about subpar uses of NSAutoreleasePool.  Note that while the check itself
12d1e5a89226da79f7e6f43d40facc46abda9e5245Jordy Rose//  (in its current form) could be written as a flow-insensitive check, in
1354cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//  can be potentially enhanced in the future with flow-sensitive information.
1454cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//  It is also a good example of the CheckerVisitor interface.
1554cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//
1654cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek//===----------------------------------------------------------------------===//
1754cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek
180b1ba6227c67d5e04b589ed8a08afa2345a40666Argyrios Kyrtzidis#include "ClangSACheckers.h"
1955fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/AST/Decl.h"
2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/AST/DeclObjC.h"
219b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
2248468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2355fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h"
2455fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/CheckerManager.h"
25f540c54701e3eeb34cb619a3a4eb18f1ac70ef2dJordan Rose#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
26d1e5a89226da79f7e6f43d40facc46abda9e5245Jordy Rose#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
279b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
2854cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek
2954cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenekusing namespace clang;
309ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
3154cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek
3254cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremeneknamespace {
33ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass NSAutoreleasePoolChecker
34ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis  : public Checker<check::PreObjCMessage> {
35651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  mutable std::unique_ptr<BugType> BT;
3645d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis  mutable Selector releaseS;
3754cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek
3854cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenekpublic:
39de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
4054cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek};
4154cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek
4254cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek} // end anonymous namespace
4354cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek
44de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rosevoid NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
4545d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis                                                   CheckerContext &C) const {
46de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose  if (!msg.isInstanceMessage())
4754cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek    return;
48de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose
49de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose  const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
5054cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek  if (!OD)
5154cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek    return;
52de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose  if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
5354cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek    return;
5445d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis
5545d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis  if (releaseS.isNull())
5645d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis    releaseS = GetNullarySelector("release", C.getASTContext());
5754cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek  // Sending 'release' message?
58432424d67641d609e4990d791baa782fc161027eArgyrios Kyrtzidis  if (msg.getSelector() != releaseS)
5954cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek    return;
6048468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks
6148468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks  if (!BT)
62651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    BT.reset(new BugType(this, "Use -drain instead of -release",
6348468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks                         "API Upgrade (Apple)"));
6448468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks
6548468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks  ExplodedNode *N = C.addTransition();
6648468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks  if (!N) {
6748468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks    assert(0);
6848468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks    return;
6948468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks  }
7048468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks
7148468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks  BugReport *Report = new BugReport(*BT, "Use -drain instead of -release when "
7248468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks    "using NSAutoreleasePool and garbage collection", N);
7348468dfeb3ccf099ed51ff5dcb8ae0fe783692fdAnna Zaks  Report->addRange(msg.getSourceRange());
74785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose  C.emitReport(Report);
7554cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek}
7645d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis
7745d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidisvoid ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
784e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie  if (mgr.getLangOpts().getGC() != LangOptions::NonGC)
7945d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis    mgr.registerChecker<NSAutoreleasePoolChecker>();
8045d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis}
81