aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-01-25 00:03:53 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-01-25 00:03:53 +0000
commit432424d67641d609e4990d791baa782fc161027e (patch)
treeaf205502f6f5817ccfa442c19dc24b0bf45c82e3
parentee8a6cafe8b69c316dd4fa5f6ea4838ffe15621c (diff)
[analyzer] Introduce ObjCMessage which represents both explicit ObjC message expressions and implicit
messages that are sent for handling properties in dot syntax. Replace all direct uses of ObjCMessageExpr in the checkers and checker interface with ObjCMessage. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124159 91177308-0d34-0410-b5e6-96231b3b80d8
-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