//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines a NSAutoreleasePoolChecker, a small checker that warns // about subpar uses of NSAutoreleasePool. Note that while the check itself // (in it's current form) could be written as a flow-insensitive check, in // can be potentially enhanced in the future with flow-sensitive information. // It is also a good example of the CheckerVisitor interface. // //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "BasicObjCFoundationChecks.h" #include "llvm/Support/Compiler.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" using namespace clang; namespace { class VISIBILITY_HIDDEN NSAutoreleasePoolChecker : public CheckerVisitor { Selector releaseS; public: NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {} static void *getTag() { static int x = 0; return &x; } void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); }; } // end anonymous namespace void clang::RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng) { ASTContext &Ctx = Eng.getContext(); if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) { Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release", Ctx))); } } void NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { const Expr *receiver = ME->getReceiver(); if (!receiver) return; // FIXME: Enhance with value-tracking information instead of consulting // the type of the expression. const ObjCObjectPointerType* PT = receiver->getType()->getAs(); const ObjCInterfaceDecl* OD = PT->getInterfaceDecl(); if (!OD) return; if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool")) return; // Sending 'release' message? if (ME->getSelector() != releaseS) return; SourceRange R = ME->getSourceRange(); C.getBugReporter().EmitBasicReport("Use -drain instead of -release", "API Upgrade (Apple)", "Use -drain instead of -release when using NSAutoreleasePool " "and garbage collection", ME->getLocStart(), &R, 1); }