xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
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