aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/BasicObjCFoundationChecks.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-03-27 22:05:32 +0000
committerTed Kremenek <kremenek@apple.com>2008-03-27 22:05:32 +0000
commit4ba6283f9c7db4513ca2d9cbde7df3a58ba941f7 (patch)
treeaa9e15e0e72dc9ba89112bdd237042b28df960d1 /lib/Analysis/BasicObjCFoundationChecks.cpp
parent9b3fdeaca3660789d89e3980dc7d41e8676cd901 (diff)
Expanded NSString checking to check for nil for a few more methods.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48898 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/BasicObjCFoundationChecks.cpp')
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp123
1 files changed, 92 insertions, 31 deletions
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index d158067e56..f6b4224f05 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -25,6 +25,7 @@
#include "llvm/Support/Compiler.h"
#include <vector>
+#include <sstream>
using namespace clang;
@@ -43,7 +44,10 @@ class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
bool isNSString(ObjCInterfaceType* T, const char* suffix);
bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
- void Warn(NodeTy* N, Expr* E, const char *msg);
+ void Warn(NodeTy* N, Expr* E, const std::string& s);
+ void WarnNilArg(NodeTy* N, Expr* E);
+
+ bool CheckNilArg(NodeTy* N, unsigned Arg);
public:
BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr)
@@ -67,28 +71,39 @@ clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
return new BasicObjCFoundationChecks(Ctx, VMgr);
}
-
-bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
-
- ObjCMessageExpr* ME =
- cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
-
+static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
Expr* Receiver = ME->getReceiver();
if (!Receiver)
- return false;
+ return NULL;
assert (Receiver->getType()->isPointerType());
-
+
const PointerType* T = Receiver->getType()->getAsPointerType();
+
+ return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+}
+
+static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
+ ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+ return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
+ : NULL;
+}
- ObjCInterfaceType* ReceiverType =
- dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
+
+ ObjCMessageExpr* ME =
+ cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
if (!ReceiverType)
- return false;
+ return NULL;
+
+ const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
- const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
+ if (!name)
+ return false;
if (name[0] != 'N' || name[1] != 'S')
return false;
@@ -112,11 +127,9 @@ static inline bool isNil(RVal X) {
//===----------------------------------------------------------------------===//
-void BasicObjCFoundationChecks::Warn(NodeTy* N,
- Expr* E, const char *msg) {
-
+void BasicObjCFoundationChecks::Warn(NodeTy* N, Expr* E, const std::string& s) {
Errors.push_back(AnnotatedPath<ValueState>());
- Errors.back().push_back(N, msg, E);
+ Errors.back().push_back(N, s, E);
}
void BasicObjCFoundationChecks::ReportResults(Diagnostic& D) {
@@ -139,6 +152,34 @@ void BasicObjCFoundationChecks::ReportResults(Diagnostic& D) {
}
}
+void BasicObjCFoundationChecks::WarnNilArg(NodeTy* N, Expr* E) {
+
+ ObjCMessageExpr* ME =
+ cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ std::ostringstream os;
+
+ os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
+ << ME->getSelector().getName()
+ << "' cannot be nil.";
+
+ Warn(N, E, os.str());
+}
+
+bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
+ ObjCMessageExpr* ME =
+ cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ Expr * E = ME->getArg(Arg);
+
+ if (isNil(GetRVal(N->getState(), E))) {
+ WarnNilArg(N, E);
+ return true;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// NSString checking.
//===----------------------------------------------------------------------===//
@@ -164,27 +205,47 @@ bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
assert (!name.empty());
const char* cstr = &name[0];
unsigned len = name.size();
-
-
- ValueState* St = N->getState();
-
+
switch (len) {
default:
break;
case 8:
- if (!strcmp(cstr, "compare:")) {
- // Check if the compared NSString is nil.
- Expr * E = ME->getArg(0);
+
+ if (!strcmp(cstr, "compare:"))
+ return CheckNilArg(N, 0);
+
+ break;
- if (isNil(GetRVal(St, E))) {
- Warn(N, E, "Argument to NSString method 'compare:' cannot be nil.");
- return false;
- }
-
- break;
- }
+ case 16:
+ if (!strcmp(cstr, "compare:options:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 22:
+ if (!strcmp(cstr, "compare:options:range:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 23:
+
+ if (!strcmp(cstr, "caseInsensitiveCompare:"))
+ return CheckNilArg(N, 0);
break;
+
+ case 29:
+ if (!strcmp(cstr, "compare:options:range:locale:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 37:
+ if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
+ return CheckNilArg(N, 0);
+
+ break;
}
return false;