xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp (revision 507ff53e39e345e43cea08ab9abf803acba639b3)
1 //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines a NSAutoreleasePoolChecker, a small checker that warns
11 //  about subpar uses of NSAutoreleasePool.  Note that while the check itself
12 //  (in it's current form) could be written as a flow-insensitive check, in
13 //  can be potentially enhanced in the future with flow-sensitive information.
14 //  It is also a good example of the CheckerVisitor interface.
15 //
16 //===----------------------------------------------------------------------===//
17 
18 #include "ClangSACheckers.h"
19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
23 #include "clang/AST/DeclObjC.h"
24 #include "clang/AST/Decl.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 class NSAutoreleasePoolChecker
31   : public CheckerVisitor<NSAutoreleasePoolChecker> {
32 
33   Selector releaseS;
34 
35 public:
36     NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
37 
38   static void *getTag() {
39     static int x = 0;
40     return &x;
41   }
42 
43   void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
44 };
45 
46 } // end anonymous namespace
47 
48 
49 static void RegisterNSAutoreleasePoolChecker(ExprEngine &Eng) {
50   ASTContext &Ctx = Eng.getContext();
51   if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
52     Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
53                                                                       Ctx)));
54   }
55 }
56 
57 void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
58   mgr.addCheckerRegisterFunction(RegisterNSAutoreleasePoolChecker);
59 }
60 
61 void
62 NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
63                                               ObjCMessage msg) {
64 
65   const Expr *receiver = msg.getInstanceReceiver();
66   if (!receiver)
67     return;
68 
69   // FIXME: Enhance with value-tracking information instead of consulting
70   // the type of the expression.
71   const ObjCObjectPointerType* PT =
72     receiver->getType()->getAs<ObjCObjectPointerType>();
73 
74   if (!PT)
75     return;
76   const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
77   if (!OD)
78     return;
79   if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
80     return;
81 
82   // Sending 'release' message?
83   if (msg.getSelector() != releaseS)
84     return;
85 
86   SourceRange R = msg.getSourceRange();
87 
88   C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
89     "API Upgrade (Apple)",
90     "Use -drain instead of -release when using NSAutoreleasePool "
91     "and garbage collection", R.getBegin(), &R, 1);
92 }
93