1e5dd7070Spatrick //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines a NSAutoreleasePoolChecker, a small checker that warns
10e5dd7070Spatrick // about subpar uses of NSAutoreleasePool. Note that while the check itself
11e5dd7070Spatrick // (in its current form) could be written as a flow-insensitive check, in
12e5dd7070Spatrick // can be potentially enhanced in the future with flow-sensitive information.
13e5dd7070Spatrick // It is also a good example of the CheckerVisitor interface.
14e5dd7070Spatrick //
15e5dd7070Spatrick //===----------------------------------------------------------------------===//
16e5dd7070Spatrick
17e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18e5dd7070Spatrick #include "clang/AST/Decl.h"
19e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
20e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
23e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
24e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
25e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
27e5dd7070Spatrick
28e5dd7070Spatrick using namespace clang;
29e5dd7070Spatrick using namespace ento;
30e5dd7070Spatrick
31e5dd7070Spatrick namespace {
32e5dd7070Spatrick class NSAutoreleasePoolChecker
33e5dd7070Spatrick : public Checker<check::PreObjCMessage> {
34e5dd7070Spatrick mutable std::unique_ptr<BugType> BT;
35e5dd7070Spatrick mutable Selector releaseS;
36e5dd7070Spatrick
37e5dd7070Spatrick public:
38e5dd7070Spatrick void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
39e5dd7070Spatrick };
40e5dd7070Spatrick
41e5dd7070Spatrick } // end anonymous namespace
42e5dd7070Spatrick
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const43e5dd7070Spatrick void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
44e5dd7070Spatrick CheckerContext &C) const {
45e5dd7070Spatrick if (!msg.isInstanceMessage())
46e5dd7070Spatrick return;
47e5dd7070Spatrick
48e5dd7070Spatrick const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
49e5dd7070Spatrick if (!OD)
50e5dd7070Spatrick return;
51e5dd7070Spatrick if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
52e5dd7070Spatrick return;
53e5dd7070Spatrick
54e5dd7070Spatrick if (releaseS.isNull())
55e5dd7070Spatrick releaseS = GetNullarySelector("release", C.getASTContext());
56e5dd7070Spatrick // Sending 'release' message?
57e5dd7070Spatrick if (msg.getSelector() != releaseS)
58e5dd7070Spatrick return;
59e5dd7070Spatrick
60e5dd7070Spatrick if (!BT)
61e5dd7070Spatrick BT.reset(new BugType(this, "Use -drain instead of -release",
62e5dd7070Spatrick "API Upgrade (Apple)"));
63e5dd7070Spatrick
64e5dd7070Spatrick ExplodedNode *N = C.generateNonFatalErrorNode();
65e5dd7070Spatrick if (!N) {
66e5dd7070Spatrick assert(0);
67e5dd7070Spatrick return;
68e5dd7070Spatrick }
69e5dd7070Spatrick
70e5dd7070Spatrick auto Report = std::make_unique<PathSensitiveBugReport>(
71e5dd7070Spatrick *BT,
72e5dd7070Spatrick "Use -drain instead of -release when using NSAutoreleasePool and "
73e5dd7070Spatrick "garbage collection",
74e5dd7070Spatrick N);
75e5dd7070Spatrick Report->addRange(msg.getSourceRange());
76e5dd7070Spatrick C.emitReport(std::move(Report));
77e5dd7070Spatrick }
78e5dd7070Spatrick
registerNSAutoreleasePoolChecker(CheckerManager & mgr)79e5dd7070Spatrick void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
80e5dd7070Spatrick mgr.registerChecker<NSAutoreleasePoolChecker>();
81e5dd7070Spatrick }
82e5dd7070Spatrick
shouldRegisterNSAutoreleasePoolChecker(const CheckerManager & mgr)83*ec727ea7Spatrick bool ento::shouldRegisterNSAutoreleasePoolChecker(const CheckerManager &mgr) {
84*ec727ea7Spatrick const LangOptions &LO = mgr.getLangOpts();
85e5dd7070Spatrick return LO.getGC() != LangOptions::NonGC;
86e5dd7070Spatrick }
87