summaryrefslogtreecommitdiffstats
path: root/lib/Analysis/BasicObjCFoundationChecks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/BasicObjCFoundationChecks.cpp')
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp73
1 files changed, 66 insertions, 7 deletions
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index c2ecfa1..c913779 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -22,12 +22,12 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -52,12 +52,12 @@ static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
namespace {
-class VISIBILITY_HIDDEN APIMisuse : public BugType {
+class APIMisuse : public BugType {
public:
APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
};
-class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
+class BasicObjCFoundationChecks : public GRSimpleAPICheck {
APIMisuse *BT;
BugReporter& BR;
ASTContext &Ctx;
@@ -87,7 +87,7 @@ private:
// by the BugReporter object 'BR' once we call BR.EmitWarning.
if (!BT) BT = new APIMisuse("nil argument");
- RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
+ RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
R->addRange(ME->getArg(Arg)->getSourceRange());
BR.EmitReport(R);
}
@@ -228,7 +228,7 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
namespace {
-class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
+class AuditCFNumberCreate : public GRSimpleAPICheck {
APIMisuse* BT;
// FIXME: Either this should be refactored into GRSimpleAPICheck, or
@@ -435,7 +435,7 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex,
// Lazily create the BugType object. This will be owned
// by the BugReporter object 'BR' once we call BR.EmitWarning.
if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
- RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
report->addRange(Ex->getSourceRange());
BR.EmitReport(report);
}
@@ -450,7 +450,7 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck {
+class AuditCFRetainRelease : public GRSimpleAPICheck {
APIMisuse *BT;
// FIXME: Either this should be refactored into GRSimpleAPICheck, or
@@ -522,6 +522,64 @@ clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) {
}
//===----------------------------------------------------------------------===//
+// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ClassReleaseChecker :
+ public CheckerVisitor<ClassReleaseChecker> {
+ Selector releaseS;
+ Selector retainS;
+ Selector autoreleaseS;
+ Selector drainS;
+ BugType *BT;
+public:
+ ClassReleaseChecker(ASTContext &Ctx)
+ : releaseS(GetNullarySelector("release", Ctx)),
+ retainS(GetNullarySelector("retain", Ctx)),
+ autoreleaseS(GetNullarySelector("autorelease", Ctx)),
+ drainS(GetNullarySelector("drain", Ctx)),
+ BT(0) {}
+
+ static void *getTag() { static int x = 0; return &x; }
+
+ void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+};
+}
+
+void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+
+ const IdentifierInfo *ClsName = ME->getClassName();
+ if (!ClsName)
+ return;
+
+ Selector S = ME->getSelector();
+ if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
+ return;
+
+ if (!BT)
+ BT = new APIMisuse("message incorrectly sent to class instead of class "
+ "instance");
+
+ ExplodedNode *N = C.GenerateNode();
+
+ if (!N)
+ return;
+
+ llvm::SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "The '" << S.getAsString() << "' message should be sent to instances "
+ "of class '" << ClsName->getName()
+ << "' and not the class directly";
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(ME->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//
@@ -536,4 +594,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
RegisterNSErrorChecks(BR, Eng, D);
RegisterNSAutoreleasePoolChecks(Eng);
+ Eng.registerCheck(new ClassReleaseChecker(Ctx));
}
OpenPOWER on IntegriCloud