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
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index d158067..f6b4224 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 @@
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 @@
return new BasicObjCFoundationChecks(Ctx, VMgr);
}
+static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
+ Expr* Receiver = ME->getReceiver();
+
+ if (!Receiver)
+ 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;
+}
bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
ObjCMessageExpr* ME =
cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
-
- Expr* Receiver = ME->getReceiver();
-
- if (!Receiver)
- return false;
-
- assert (Receiver->getType()->isPointerType());
- const PointerType* T = Receiver->getType()->getAsPointerType();
-
- ObjCInterfaceType* ReceiverType =
- dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+ 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 @@
//===----------------------------------------------------------------------===//
-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::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 @@
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;