1d99bd55aSTed Kremenek //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek //  This file defines a NSAutoreleasePoolChecker, a small checker that warns
10d99bd55aSTed Kremenek //  about subpar uses of NSAutoreleasePool.  Note that while the check itself
11087611edSJordy Rose //  (in its current form) could be written as a flow-insensitive check, in
12d99bd55aSTed Kremenek //  can be potentially enhanced in the future with flow-sensitive information.
13d99bd55aSTed Kremenek //  It is also a good example of the CheckerVisitor interface.
14d99bd55aSTed Kremenek //
15d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
16d99bd55aSTed Kremenek 
1776a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
183a02247dSChandler Carruth #include "clang/AST/Decl.h"
193a02247dSChandler Carruth #include "clang/AST/DeclObjC.h"
20f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
216b1c2126SAnna Zaks #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
223a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/Checker.h"
233a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/CheckerManager.h"
244f7df9beSJordan Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
25087611edSJordy Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
27d99bd55aSTed Kremenek 
28d99bd55aSTed Kremenek using namespace clang;
29d99bd55aSTed Kremenek using namespace ento;
30d99bd55aSTed Kremenek 
31d99bd55aSTed Kremenek namespace {
32d99bd55aSTed Kremenek class NSAutoreleasePoolChecker
336a5674ffSArgyrios Kyrtzidis   : public Checker<check::PreObjCMessage> {
34b8984329SAhmed Charles   mutable std::unique_ptr<BugType> BT;
35aad83725SArgyrios Kyrtzidis   mutable Selector releaseS;
36d99bd55aSTed Kremenek 
37d99bd55aSTed Kremenek public:
38547060b3SJordan Rose   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
39d99bd55aSTed Kremenek };
40d99bd55aSTed Kremenek 
41d99bd55aSTed Kremenek } // end anonymous namespace
42d99bd55aSTed Kremenek 
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const43547060b3SJordan Rose void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
44aad83725SArgyrios Kyrtzidis                                                    CheckerContext &C) const {
45547060b3SJordan Rose   if (!msg.isInstanceMessage())
46d99bd55aSTed Kremenek     return;
47d99bd55aSTed Kremenek 
48547060b3SJordan Rose   const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
49d99bd55aSTed Kremenek   if (!OD)
50d99bd55aSTed Kremenek     return;
51547060b3SJordan Rose   if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
52d99bd55aSTed Kremenek     return;
53d99bd55aSTed Kremenek 
54aad83725SArgyrios Kyrtzidis   if (releaseS.isNull())
55aad83725SArgyrios Kyrtzidis     releaseS = GetNullarySelector("release", C.getASTContext());
56d99bd55aSTed Kremenek   // Sending 'release' message?
5737ab726dSArgyrios Kyrtzidis   if (msg.getSelector() != releaseS)
58d99bd55aSTed Kremenek     return;
59d99bd55aSTed Kremenek 
606b1c2126SAnna Zaks   if (!BT)
614aca9b1cSAlexander Kornienko     BT.reset(new BugType(this, "Use -drain instead of -release",
626b1c2126SAnna Zaks                          "API Upgrade (Apple)"));
636b1c2126SAnna Zaks 
64e39bd407SDevin Coughlin   ExplodedNode *N = C.generateNonFatalErrorNode();
656b1c2126SAnna Zaks   if (!N) {
666b1c2126SAnna Zaks     assert(0);
676b1c2126SAnna Zaks     return;
686b1c2126SAnna Zaks   }
696b1c2126SAnna Zaks 
702f169e7cSArtem Dergachev   auto Report = std::make_unique<PathSensitiveBugReport>(
712f169e7cSArtem Dergachev       *BT,
722f169e7cSArtem Dergachev       "Use -drain instead of -release when using NSAutoreleasePool and "
732f169e7cSArtem Dergachev       "garbage collection",
742f169e7cSArtem Dergachev       N);
756b1c2126SAnna Zaks   Report->addRange(msg.getSourceRange());
768d3a7a56SAaron Ballman   C.emitReport(std::move(Report));
77d99bd55aSTed Kremenek }
78aad83725SArgyrios Kyrtzidis 
registerNSAutoreleasePoolChecker(CheckerManager & mgr)79aad83725SArgyrios Kyrtzidis void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
80aad83725SArgyrios Kyrtzidis   mgr.registerChecker<NSAutoreleasePoolChecker>();
81aad83725SArgyrios Kyrtzidis }
82058a7a45SKristof Umann 
shouldRegisterNSAutoreleasePoolChecker(const CheckerManager & mgr)83*bda3dd0dSKirstóf Umann bool ento::shouldRegisterNSAutoreleasePoolChecker(const CheckerManager &mgr) {
84*bda3dd0dSKirstóf Umann   const LangOptions &LO = mgr.getLangOpts();
85058a7a45SKristof Umann   return LO.getGC() != LangOptions::NonGC;
86058a7a45SKristof Umann }
87