diff options
Diffstat (limited to 'lib/Analysis/BasicObjCFoundationChecks.cpp')
-rw-r--r-- | lib/Analysis/BasicObjCFoundationChecks.cpp | 73 |
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)); } |