#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
namespace {
class NSAutoreleasePoolChecker
: public Checker<check::PreObjCMessage> {
const BugType BT{this, "Use -drain instead of -release",
"API Upgrade (Apple)"};
mutable Selector releaseS;
public:
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
};
}
void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
if (!msg.isInstanceMessage())
return;
const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
if (!OD)
return;
if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
return;
if (releaseS.isNull())
releaseS = GetNullarySelector("release", C.getASTContext());
if (msg.getSelector() != releaseS)
return;
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N) {
assert(0);
return;
}
auto Report = std::make_unique<PathSensitiveBugReport>(
BT,
"Use -drain instead of -release when using NSAutoreleasePool and "
"garbage collection",
N);
Report->addRange(msg.getSourceRange());
C.emitReport(std::move(Report));
}
void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
mgr.registerChecker<NSAutoreleasePoolChecker>();
}
bool ento::shouldRegisterNSAutoreleasePoolChecker(const CheckerManager &mgr) {
const LangOptions &LO = mgr.getLangOpts();
return LO.getGC() != LangOptions::NonGC;
}