1d99bd55aSTed Kremenek //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==// 2d99bd55aSTed Kremenek // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler 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 43547060b3SJordan 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 708d3a7a56SAaron Ballman auto Report = llvm::make_unique<BugReport>( 718d3a7a56SAaron Ballman *BT, "Use -drain instead of -release when using NSAutoreleasePool and " 728d3a7a56SAaron Ballman "garbage collection", N); 736b1c2126SAnna Zaks Report->addRange(msg.getSourceRange()); 748d3a7a56SAaron Ballman C.emitReport(std::move(Report)); 75d99bd55aSTed Kremenek } 76aad83725SArgyrios Kyrtzidis 77aad83725SArgyrios Kyrtzidis void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) { 78bbafb8a7SDavid Blaikie if (mgr.getLangOpts().getGC() != LangOptions::NonGC) 79aad83725SArgyrios Kyrtzidis mgr.registerChecker<NSAutoreleasePoolChecker>(); 80aad83725SArgyrios Kyrtzidis } 81