aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/PathSensitive/Checker.h24
-rw-r--r--include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def2
-rw-r--r--include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h11
-rw-r--r--include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h207
-rw-r--r--include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h13
-rw-r--r--lib/StaticAnalyzer/CFRefCount.cpp125
-rw-r--r--lib/StaticAnalyzer/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp57
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp91
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprEngine.cpp57
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/ObjCMessage.cpp99
13 files changed, 530 insertions, 187 deletions
diff --git a/include/clang/StaticAnalyzer/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/PathSensitive/Checker.h
index f363fcc852..a009932ca3 100644
--- a/include/clang/StaticAnalyzer/PathSensitive/Checker.h
+++ b/include/clang/StaticAnalyzer/PathSensitive/Checker.h
@@ -203,12 +203,26 @@ private:
_PostVisit(C, S);
}
+ void GR_visitObjCMessage(ExplodedNodeSet &Dst,
+ StmtNodeBuilder &Builder,
+ ExprEngine &Eng,
+ const ObjCMessage &msg,
+ ExplodedNode *Pred, void *tag, bool isPrevisit) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ isPrevisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, 0, msg.getOriginExpr());
+ if (isPrevisit)
+ preVisitObjCMessage(C, msg);
+ else
+ postVisitObjCMessage(C, msg);
+ }
+
bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
- ExprEngine &Eng, const ObjCMessageExpr *ME,
+ ExprEngine &Eng, const ObjCMessage &msg,
ExplodedNode *Pred, const GRState *state, void *tag) {
CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
- 0, ME, state);
- return evalNilReceiver(C, ME);
+ 0, msg.getOriginExpr(), state);
+ return evalNilReceiver(C, msg);
}
bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
@@ -258,6 +272,8 @@ public:
virtual ~Checker();
virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
+ virtual void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {}
+ virtual void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {}
virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
bool isLoad) {}
virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
@@ -272,7 +288,7 @@ public:
ExprEngine &Eng,
const Stmt *Condition, void *tag) {}
- virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
+ virtual bool evalNilReceiver(CheckerContext &C, ObjCMessage msg) {
return false;
}
diff --git a/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def b/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def
index 840aaa76fd..9b3c263e7d 100644
--- a/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def
+++ b/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def
@@ -34,7 +34,6 @@ PREVISIT(CXXStaticCastExpr, CastExpr)
PREVISIT(DeclStmt, Stmt)
PREVISIT(ImplicitCastExpr, CastExpr)
PREVISIT(ObjCAtSynchronizedStmt, Stmt)
-PREVISIT(ObjCMessageExpr, Stmt)
PREVISIT(ReturnStmt, Stmt)
POSTVISIT(BlockExpr, Stmt)
@@ -43,7 +42,6 @@ POSTVISIT(CallExpr, GenericCall)
POSTVISIT(CompoundAssignOperator, BinaryOperator)
POSTVISIT(CXXOperatorCallExpr, GenericCall)
POSTVISIT(CXXMemberCallExpr, GenericCall)
-POSTVISIT(ObjCMessageExpr, Stmt)
POSTVISIT(ObjCIvarRefExpr, Stmt)
#undef PREVISIT
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
index 747c8ebb2a..5617bf1c3b 100644
--- a/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
@@ -282,11 +282,14 @@ public:
void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
CallbackKind Kind);
+ void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src, bool isPrevisit);
+
bool CheckerEvalCall(const CallExpr *CE,
ExplodedNodeSet &Dst,
ExplodedNode *Pred);
- void CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+ void CheckerEvalNilReceiver(const ObjCMessage &msg,
ExplodedNodeSet &Dst,
const GRState *state,
ExplodedNode *Pred);
@@ -490,10 +493,10 @@ public:
}
protected:
- void evalObjCMessageExpr(ExplodedNodeSet& Dst, const ObjCMessageExpr* ME,
- ExplodedNode* Pred, const GRState *state) {
+ void evalObjCMessage(ExplodedNodeSet& Dst, const ObjCMessage &msg,
+ ExplodedNode* Pred, const GRState *state) {
assert (Builder && "StmtNodeBuilder must be defined.");
- getTF().evalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state);
+ getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
}
const GRState* MarkBranch(const GRState* St, const Stmt* Terminator,
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h
new file mode 100644
index 0000000000..4e5ce09d7a
--- /dev/null
+++ b/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h
@@ -0,0 +1,207 @@
+//===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ObjCMessage which serves as a common wrapper for ObjC
+// message expressions or implicit messages for loading/storing ObjC properties.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
+#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
+
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/AST/ExprObjC.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Represents both explicit ObjC message expressions and implicit
+/// messages that are sent for handling properties in dot syntax.
+class ObjCMessage {
+ const Expr *MsgOrPropE;
+ const Expr *OriginE;
+ bool IsPropSetter;
+ SVal SetterArgV;
+
+protected:
+ ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV)
+ : MsgOrPropE(E), OriginE(origE),
+ IsPropSetter(isSetter), SetterArgV(setArgV) { }
+
+public:
+ ObjCMessage() : MsgOrPropE(0), OriginE(0) { }
+
+ ObjCMessage(const ObjCMessageExpr *E)
+ : MsgOrPropE(E), OriginE(E) {
+ assert(E && "should not be initialized with null expression");
+ }
+
+ bool isValid() const { return MsgOrPropE != 0; }
+ bool isInvalid() const { return !isValid(); }
+
+ bool isMessageExpr() const {
+ return isValid() && isa<ObjCMessageExpr>(MsgOrPropE);
+ }
+
+ bool isPropertyGetter() const {
+ return isValid() &&
+ isa<ObjCPropertyRefExpr>(MsgOrPropE) && !IsPropSetter;
+ }
+
+ bool isPropertySetter() const {
+ return isValid() &&
+ isa<ObjCPropertyRefExpr>(MsgOrPropE) && IsPropSetter;
+ }
+
+ const Expr *getOriginExpr() const { return OriginE; }
+
+ QualType getType(ASTContext &ctx) const;
+
+ QualType getResultType(ASTContext &ctx) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ if (const ObjCMethodDecl *MD = msgE->getMethodDecl())
+ return MD->getResultType();
+ return getType(ctx);
+ }
+
+ Selector getSelector() const;
+
+ const Expr *getInstanceReceiver() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getInstanceReceiver();
+ return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getBase();
+ }
+
+ bool isInstanceMessage() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->isInstanceMessage();
+ const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+ // FIXME: 'super' may be super class.
+ return propE->isObjectReceiver() || propE->isSuperReceiver();
+ }
+
+ const ObjCMethodDecl *getMethodDecl() const;
+
+ const ObjCInterfaceDecl *getReceiverInterface() const;
+
+ SourceLocation getSuperLoc() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getSuperLoc();
+ return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
+ }
+
+ SourceRange getSourceRange() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ return MsgOrPropE->getSourceRange();
+ }
+
+ unsigned getNumArgs() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getNumArgs();
+ return isPropertySetter() ? 1 : 0;
+ }
+
+ SVal getArgSVal(unsigned i, const GRState *state) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return state->getSVal(msgE->getArg(i));
+ assert(isPropertySetter());
+ return SetterArgV;
+ }
+
+ QualType getArgType(unsigned i) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getArg(i)->getType();
+ assert(isPropertySetter());
+ return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
+ }
+
+ const Expr *getArgExpr(unsigned i) const;
+
+ SourceRange getArgSourceRange(unsigned i) const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ assert(i < getNumArgs() && "Invalid index for argument");
+ if (const Expr *argE = getArgExpr(i))
+ return argE->getSourceRange();
+ return OriginE->getSourceRange();
+ }
+};
+
+class ObjCPropertyGetter : public ObjCMessage {
+public:
+ ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE)
+ : ObjCMessage(propE, originE, false, SVal()) {
+ assert(propE && originE &&
+ "should not be initialized with null expressions");
+ }
+};
+
+class ObjCPropertySetter : public ObjCMessage {
+public:
+ ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE,
+ SVal argV)
+ : ObjCMessage(propE, storeE, true, argV) {
+ assert(propE && storeE &&"should not be initialized with null expressions");
+ }
+};
+
+/// \brief Common wrapper for a call expression or an ObjC message, mainly to
+/// provide a common interface for handling their arguments.
+class CallOrObjCMessage {
+ const CallExpr *CallE;
+ ObjCMessage Msg;
+ const GRState *State;
+
+public:
+ CallOrObjCMessage(const CallExpr *callE, const GRState *state)
+ : CallE(callE), State(state) { }
+ CallOrObjCMessage(const ObjCMessage &msg, const GRState *state)
+ : CallE(0), Msg(msg), State(state) { }
+
+ QualType getResultType(ASTContext &ctx) const;
+
+ unsigned getNumArgs() const {
+ if (CallE) return CallE->getNumArgs();
+ return Msg.getNumArgs();
+ }
+
+ SVal getArgSVal(unsigned i) const {
+ assert(i < getNumArgs());
+ if (CallE) return State->getSVal(CallE->getArg(i));
+ return Msg.getArgSVal(i, State);
+ }
+
+ SVal getArgSValAsScalarOrLoc(unsigned i) const;
+
+ const Expr *getArg(unsigned i) const {
+ assert(i < getNumArgs());
+ if (CallE) return CallE->getArg(i);
+ return Msg.getArgExpr(i);
+ }
+
+ SourceRange getArgSourceRange(unsigned i) const {
+ assert(i < getNumArgs());
+ if (CallE) return CallE->getArg(i)->getSourceRange();
+ return Msg.getArgSourceRange(i);
+ }
+};
+
+}
+}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h b/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h
index 950143d91d..92598fcdd6 100644
--- a/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h
+++ b/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/ObjCMessage.h"
#include <vector>
namespace clang {
@@ -47,12 +48,12 @@ public:
const CallExpr* CE, SVal L,
ExplodedNode* Pred) {}
- virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- const GRState *state) {}
+ virtual void evalObjCMessage(ExplodedNodeSet& Dst,
+ ExprEngine& Engine,
+ StmtNodeBuilder& Builder,
+ ObjCMessage msg,
+ ExplodedNode* Pred,
+ const GRState *state) {}
// Stores.
diff --git a/lib/StaticAnalyzer/CFRefCount.cpp b/lib/StaticAnalyzer/CFRefCount.cpp
index d4bed35317..5cc4a3c3ee 100644
--- a/lib/StaticAnalyzer/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/CFRefCount.cpp
@@ -40,14 +40,15 @@ using llvm::StrInStrNoCase;
namespace {
class InstanceReceiver {
- const ObjCMessageExpr *ME;
+ ObjCMessage Msg;
const LocationContext *LC;
public:
- InstanceReceiver(const ObjCMessageExpr *me = 0,
- const LocationContext *lc = 0) : ME(me), LC(lc) {}
+ InstanceReceiver() : LC(0) { }
+ InstanceReceiver(const ObjCMessage &msg,
+ const LocationContext *lc = 0) : Msg(msg), LC(lc) {}
bool isValid() const {
- return ME && ME->isInstanceMessage();
+ return Msg.isValid() && Msg.isInstanceMessage();
}
operator bool() const {
return isValid();
@@ -57,7 +58,7 @@ public:
assert(isValid());
// We have an expression for the receiver? Fetch the value
// of that expression.
- if (const Expr *Ex = ME->getInstanceReceiver())
+ if (const Expr *Ex = Msg.getInstanceReceiver())
return state->getSValAsScalarOrLoc(Ex);
// Otherwise we are sending a message to super. In this case the
@@ -70,11 +71,11 @@ public:
SourceRange getSourceRange() const {
assert(isValid());
- if (const Expr *Ex = ME->getInstanceReceiver())
+ if (const Expr *Ex = Msg.getInstanceReceiver())
return Ex->getSourceRange();
// Otherwise we are sending a message to super.
- SourceLocation L = ME->getSuperLoc();
+ SourceLocation L = Msg.getSuperLoc();
assert(L.isValid());
return SourceRange(L, L);
}
@@ -798,14 +799,14 @@ public:
RetainSummary* getSummary(const FunctionDecl* FD);
- RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+ RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
const GRState *state,
const LocationContext *LC);
- RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
+ RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg,
const ObjCInterfaceDecl* ID) {
- return getInstanceMethodSummary(ME->getSelector(), 0,
- ID, ME->getMethodDecl(), ME->getType());
+ return getInstanceMethodSummary(msg.getSelector(), 0,
+ ID, msg.getMethodDecl(), msg.getType(Ctx));
}
RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
@@ -818,23 +819,15 @@ public:
const ObjCMethodDecl *MD,
QualType RetTy);
- RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
- ObjCInterfaceDecl *Class = 0;
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Class:
- case ObjCMessageExpr::SuperClass:
- Class = ME->getReceiverInterface();
- break;
-
- case ObjCMessageExpr::Instance:
- case ObjCMessageExpr::SuperInstance:
- break;
- }
+ RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
+ const ObjCInterfaceDecl *Class = 0;
+ if (!msg.isInstanceMessage())
+ Class = msg.getReceiverInterface();
- return getClassMethodSummary(ME->getSelector(),
+ return getClassMethodSummary(msg.getSelector(),
Class? Class->getIdentifier() : 0,
Class,
- ME->getMethodDecl(), ME->getType());
+ msg.getMethodDecl(), msg.getType(Ctx));
}
/// getMethodSummary - This version of getMethodSummary is used to query
@@ -1310,13 +1303,13 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
}
RetainSummary*
-RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
const GRState *state,
const LocationContext *LC) {
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
- const Expr *Receiver = ME->getInstanceReceiver();
+ const Expr *Receiver = msg.getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
@@ -1344,12 +1337,12 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
}
} else {
// FIXME: Hack for 'super'.
- ID = ME->getReceiverInterface();
+ ID = msg.getReceiverInterface();
}
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
- RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+ RetainSummary *Summ = getInstanceMethodSummary(msg, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
@@ -1693,10 +1686,10 @@ public:
ExprEngine& Eng,
StmtNodeBuilder& Builder,
const Expr* Ex,
+ const CallOrObjCMessage &callOrMsg,
InstanceReceiver Receiver,
const RetainSummary& Summ,
const MemRegion *Callee,
- ConstExprIterator arg_beg, ConstExprIterator arg_end,
ExplodedNode* Pred, const GRState *state);
virtual void evalCall(ExplodedNodeSet& Dst,
@@ -1706,12 +1699,12 @@ public:
ExplodedNode* Pred);
- virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
- ExprEngine& Engine,
- StmtNodeBuilder& Builder,
- const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- const GRState *state);
+ virtual void evalObjCMessage(ExplodedNodeSet& Dst,
+ ExprEngine& Engine,
+ StmtNodeBuilder& Builder,
+ ObjCMessage msg,
+ ExplodedNode* Pred,
+ const GRState *state);
// Stores.
virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val);
@@ -2477,16 +2470,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
ExprEngine& Eng,
StmtNodeBuilder& Builder,
const Expr* Ex,
+ const CallOrObjCMessage &callOrMsg,
InstanceReceiver Receiver,
const RetainSummary& Summ,
const MemRegion *Callee,
- ConstExprIterator arg_beg,
- ConstExprIterator arg_end,
ExplodedNode* Pred, const GRState *state) {
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
- unsigned idx = 0;
SourceRange ErrorRange;
SymbolRef ErrorSym = 0;
@@ -2498,8 +2489,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// done an invalidation pass.
llvm::DenseSet<SymbolRef> WhitelistedSymbols;
- for (ConstExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
- SVal V = state->getSValAsScalarOrLoc(*I);
+ for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
+ SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
SymbolRef Sym = V.getAsLocSymbol();
if (Sym)
@@ -2507,7 +2498,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
WhitelistedSymbols.insert(Sym);
state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
if (hasErr) {
- ErrorRange = (*I)->getSourceRange();
+ ErrorRange = callOrMsg.getArgSourceRange(idx);
ErrorSym = Sym;
break;
}
@@ -2650,19 +2641,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
- QualType T = Ex->getType();
-
- // For CallExpr, use the result type to know if it returns a reference.
- if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) {
- const Expr *Callee = CE->getCallee();
- if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl())
- T = FD->getResultType();
- }
- else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
- if (const ObjCMethodDecl *MD = ME->getMethodDecl())
- T = MD->getResultType();
- }
-
+ QualType T = callOrMsg.getResultType(Eng.getContext());
if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -2675,9 +2654,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
case RetEffect::Alias: {
unsigned idx = RE.getIndex();
- assert (arg_end >= arg_beg);
- assert (idx < (unsigned) (arg_end - arg_beg));
- SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx));
+ assert (idx < callOrMsg.getNumArgs());
+ SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
state = state->BindExpr(Ex, V, false);
break;
}
@@ -2756,25 +2734,28 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst,
}
assert(Summ);
- evalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
- CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
+ evalSummary(Dst, Eng, Builder, CE,
+ CallOrObjCMessage(CE, Builder.GetState(Pred)),
+ InstanceReceiver(), *Summ,L.getAsRegion(),
+ Pred, Builder.GetState(Pred));
}
-void CFRefCount::evalObjCMessageExpr(ExplodedNodeSet& Dst,
- ExprEngine& Eng,
- StmtNodeBuilder& Builder,
- const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- const GRState *state) {
+void CFRefCount::evalObjCMessage(ExplodedNodeSet& Dst,
+ ExprEngine& Eng,
+ StmtNodeBuilder& Builder,
+ ObjCMessage msg,
+ ExplodedNode* Pred,
+ const GRState *state) {
RetainSummary *Summ =
- ME->isInstanceMessage()
- ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
- : Summaries.getClassMethodSummary(ME);
+ msg.isInstanceMessage()
+ ? Summaries.getInstanceMethodSummary(msg, state,Pred->getLocationContext())
+ : Summaries.getClassMethodSummary(msg);
assert(Summ && "RetainSummary is null");
- evalSummary(Dst, Eng, Builder, ME,
- InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL,
- ME->arg_begin(), ME->arg_end(), Pred, state);
+ evalSummary(Dst, Eng, Builder, msg.getOriginExpr(),
+ CallOrObjCMessage(msg, Builder.GetState(Pred)),
+ InstanceReceiver(msg, Pred->getLocationContext()), *Summ, NULL,
+ Pred, state);
}
namespace {
diff --git a/lib/StaticAnalyzer/CMakeLists.txt b/lib/StaticAnalyzer/CMakeLists.txt
index cf81e1d5ad..352138599e 100644
--- a/lib/StaticAnalyzer/CMakeLists.txt
+++ b/lib/StaticAnalyzer/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangStaticAnalyzerCore
HTMLDiagnostics.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ ObjCMessage.cpp
PathDiagnostic.cpp
PlistDiagnostics.cpp
RangeConstraintManager.cpp
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 3910196265..8fa7e24cab 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -42,14 +42,14 @@ public:
// Utility functions.
//===----------------------------------------------------------------------===//
-static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- if (ObjCInterfaceDecl *ID = ME->getReceiverInterface())
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
+ if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
return NULL;
}
-static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
- if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
+static const char* GetReceiverNameType(const ObjCMessage &msg) {
+ if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
return ReceiverType->getDecl()->getIdentifier()->getNameStart();
return NULL;
}
@@ -69,16 +69,16 @@ static inline bool isNil(SVal X) {
namespace {
class NilArgChecker : public CheckerVisitor<NilArgChecker> {
APIMisuse *BT;
- void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
+ void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
public:
NilArgChecker() : BT(0) {}
static void *getTag() { static int x = 0; return &x; }
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
};
}
void NilArgChecker::WarnNilArg(CheckerContext &C,
- const clang::ObjCMessageExpr *ME,
+ const ObjCMessage &msg,
unsigned int Arg)
{
if (!BT)
@@ -87,24 +87,24 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
if (ExplodedNode *N = C.generateSink()) {
llvm::SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
- os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
- << ME->getSelector().getAsString() << "' cannot be nil";
+ os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
+ << msg.getSelector().getAsString() << "' cannot be nil";
RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
- R->addRange(ME->getArg(Arg)->getSourceRange());
+ R->addRange(msg.getArgSourceRange(Arg));
C.EmitReport(R);
}
}
-void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME)
+void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg)
{
- const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
+ const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
if (!ReceiverType)
return;
if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
- Selector S = ME->getSelector();
+ Selector S = msg.getSelector();
if (S.isUnarySelector())
return;
@@ -127,8 +127,8 @@ void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(C.getState()->getSVal(ME->getArg(0))))
- WarnNilArg(C, ME, 0);
+ if (isNil(msg.getArgSVal(0, C.getState())))
+ WarnNilArg(C, msg, 0);
}
}
}
@@ -441,12 +441,12 @@ public:
static void *getTag() { static int x = 0; return &x; }
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
};
}
-void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
+void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
+ ObjCMessage msg) {
if (!BT) {
BT = new APIMisuse("message incorrectly sent to class instead of class "
@@ -459,21 +459,12 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
drainS = GetNullarySelector("drain", Ctx);
}
- ObjCInterfaceDecl *Class = 0;
-
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Class:
- Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
- break;
- case ObjCMessageExpr::SuperClass:
- Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
- break;
- case ObjCMessageExpr::Instance:
- case ObjCMessageExpr::SuperInstance:
+ if (msg.isInstanceMessage())
return;
- }
+ const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
+ assert(Class);
- Selector S = ME->getSelector();
+ Selector S = msg.getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@@ -486,7 +477,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(ME->getSourceRange());
+ report->addRange(msg.getSourceRange());
C.EmitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 2998406da0..e6a40bb597 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -41,19 +41,21 @@ public:
}
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
- bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
+ void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+ bool evalNilReceiver(CheckerContext &C, ObjCMessage msg);
private:
- bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
- const char *BT_desc, BugType *&BT);
+ void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg,
+ const char *BT_desc, BugType *&BT);
+ bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
+ const Expr *argEx, const char *BT_desc, BugType *&BT);
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
- void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+ void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
ExplodedNode *N);
void HandleNilReceiver(CheckerContext &C, const GRState *state,
- const ObjCMessageExpr *ME);
+ ObjCMessage msg);
void LazyInit_BT(const char *desc, BugType *&BT) {
if (!BT)
@@ -78,21 +80,32 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
C.EmitReport(R);
}
+void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
+ CallOrObjCMessage callOrMsg,
+ const char *BT_desc,
+ BugType *&BT) {
+ for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
+ if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
+ callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
+ BT_desc, BT))
+ return;
+}
+
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
- const Expr *Ex,
+ SVal V, SourceRange argRange,
+ const Expr *argEx,
const char *BT_desc,<