void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const { const Expr *receiver = msg.getInstanceReceiver(); if (!receiver) return; // FIXME: Enhance with value-tracking information instead of consulting // the type of the expression. const ObjCObjectPointerType* PT = receiver->getType()->getAs<ObjCObjectPointerType>(); if (!PT) return; const ObjCInterfaceDecl *OD = PT->getInterfaceDecl(); if (!OD) return; if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool")) return; if (releaseS.isNull()) releaseS = GetNullarySelector("release", C.getASTContext()); // Sending 'release' message? if (msg.getSelector() != releaseS) return; SourceRange R = msg.getSourceRange(); C.getBugReporter().EmitBasicReport("Use -drain instead of -release", "API Upgrade (Apple)", "Use -drain instead of -release when using NSAutoreleasePool " "and garbage collection", R.getBegin(), &R, 1); }
void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) { if (!BT) { BT = new APIMisuse("message incorrectly sent to class instead of class " "instance"); ASTContext &Ctx = C.getASTContext(); releaseS = GetNullarySelector("release", Ctx); retainS = GetNullarySelector("retain", Ctx); autoreleaseS = GetNullarySelector("autorelease", Ctx); drainS = GetNullarySelector("drain", Ctx); } if (msg.isInstanceMessage()) return; const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); assert(Class); Selector S = msg.getSelector(); if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; if (ExplodedNode *N = C.generateNode()) { llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); os << "The '" << S.getAsString() << "' message should be sent to instances " "of class '" << Class->getName() << "' and not the class directly"; RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); report->addRange(msg.getSourceRange()); C.EmitReport(report); } }