diff options
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/Checker.h | 24 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def | 2 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h | 11 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h | 207 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h | 13 | ||||
-rw-r--r-- | lib/StaticAnalyzer/CFRefCount.cpp | 125 | ||||
-rw-r--r-- | lib/StaticAnalyzer/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp | 57 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | 91 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/ExprEngine.cpp | 57 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp | 14 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp | 16 | ||||
-rw-r--r-- | lib/StaticAnalyzer/ObjCMessage.cpp | 99 |
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,< |