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