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