diff options
Diffstat (limited to 'clang')
13 files changed, 530 insertions, 187 deletions
diff --git a/clang/include/clang/StaticAnalyzer/PathSensitive/Checker.h b/clang/include/clang/StaticAnalyzer/PathSensitive/Checker.h index f363fcc8525..a009932ca36 100644 --- a/clang/include/clang/StaticAnalyzer/PathSensitive/Checker.h +++ b/clang/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/clang/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def b/clang/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def index 840aaa76fd7..9b3c263e7d5 100644 --- a/clang/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def +++ b/clang/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/clang/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h index 747c8ebb2a3..5617bf1c3b4 100644 --- a/clang/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h +++ b/clang/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/clang/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h b/clang/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h new file mode 100644 index 00000000000..4e5ce09d7ae --- /dev/null +++ b/clang/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/clang/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h b/clang/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h index 950143d91da..92598fcdd6c 100644 --- a/clang/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h +++ b/clang/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/clang/lib/StaticAnalyzer/CFRefCount.cpp b/clang/lib/StaticAnalyzer/CFRefCount.cpp index d4bed35317e..5cc4a3c3ee3 100644 --- a/clang/lib/StaticAnalyzer/CFRefCount.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/CMakeLists.txt b/clang/lib/StaticAnalyzer/CMakeLists.txt index cf81e1d5ad8..352138599ec 100644 --- a/clang/lib/StaticAnalyzer/CMakeLists.txt +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 3910196265b..8fa7e24cab0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 2998406da05..e6a40bb5975 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/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, BugType *&BT) { - const SVal &V = C.getState()->getSVal(Ex); - if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { LazyInit_BT(BT_desc, BT); // Generate a report for this bug. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); - R->addRange(Ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + R->addRange(argRange); + if (argEx) + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx); C.EmitReport(R); } return true; @@ -172,7 +185,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, // Generate a report for this bug. EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); - R->addRange(Ex->getSourceRange()); + R->addRange(argRange); // FIXME: enhance track back for uninitialized value for arbitrary // memregions @@ -206,21 +219,18 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, EmitBadCall(BT_call_null, C, CE); } - for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) - if (PreVisitProcessArg(C, *I, - "Function call argument is an uninitialized value", - BT_call_arg)) - return; + PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()), + "Function call argument is an uninitialized value", + BT_call_arg); } -void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *ME) { +void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { const GRState *state = C.getState(); // FIXME: Handle 'super'? - if (const Expr *receiver = ME->getInstanceReceiver()) + if (const Expr *receiver = msg.getInstanceReceiver()) if (state->getSVal(receiver).isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_msg_undef) @@ -237,22 +247,19 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, } // Check for any arguments that are uninitialized/undefined. - for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), - E = ME->arg_end(); I != E; ++I) - if (PreVisitProcessArg(C, *I, - "Argument in message expression " - "is an uninitialized value", BT_msg_arg)) - return; + PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), + "Argument in message expression " + "is an uninitialized value", BT_msg_arg); } bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C, - const ObjCMessageExpr *ME) { - HandleNilReceiver(C, C.getState(), ME); + ObjCMessage msg) { + HandleNilReceiver(C, C.getState(), msg); return true; // Nil receiver is not handled elsewhere. } void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, - const ObjCMessageExpr *ME, + const ObjCMessage &msg, ExplodedNode *N) { if (!BT_msg_ret) @@ -262,12 +269,12 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "The receiver of message '" << ME->getSelector().getAsString() + os << "The receiver of message '" << msg.getSelector().getAsString() << "' is nil and returns a value of type '" - << ME->getType().getAsString() << "' that will be garbage"; + << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage"; EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); - if (const Expr *receiver = ME->getInstanceReceiver()) { + if (const Expr *receiver = msg.getInstanceReceiver()) { report->addRange(receiver->getSourceRange()); report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, receiver); @@ -284,22 +291,22 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) { void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const GRState *state, - const ObjCMessageExpr *ME) { + ObjCMessage msg) { + ASTContext &Ctx = C.getASTContext(); // Check the return type of the message expression. A message to nil will // return different values depending on the return type and the architecture. - QualType RetTy = ME->getType(); + QualType RetTy = msg.getType(Ctx); - ASTContext &Ctx = C.getASTContext(); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); if (CanRetTy->isStructureOrClassType()) { // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead // have the "use of undefined value" be smarter about where the // undefined value came from. - if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){ if (ExplodedNode* N = C.generateSink(state)) - emitNilReceiverBug(C, ME, N); + emitNilReceiverBug(C, msg, N); return; } @@ -311,7 +318,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, // Other cases: check if the return type is smaller than void*. if (CanRetTy != Ctx.VoidTy && - C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) { // Compute: sizeof(void *) and sizeof(return type) const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); @@ -324,7 +331,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, Ctx.LongLongTy == CanRetTy || Ctx.UnsignedLongLongTy == CanRetTy))) { if (ExplodedNode* N = C.generateSink(state)) - emitNilReceiverBug(C, ME, N); + emitNilReceiverBug(C, msg, N); return; } @@ -341,8 +348,8 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, // it most likely isn't nil. We should assume the semantics // of this case unless we have *a lot* more knowledge. // - SVal V = C.getSValBuilder().makeZeroVal(ME->getType()); - C.generateNode(state->BindExpr(ME, V)); + SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx)); + C.generateNode(state->BindExpr(msg.getOriginExpr(), V)); return; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index a022562a129..6932f4a7172 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -145,10 +145,49 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, // automatically. } -void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred) { +void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg, + ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, + bool isPrevisit) { + + if (Checkers.empty()) { + Dst.insert(Src); + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } + + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg, + *NI, tag, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} + +void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred) { bool evaluated = false; ExplodedNodeSet DstTmp; @@ -156,7 +195,7 @@ void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, void *tag = I->first; Checker *checker = I->second; - if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state, + if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state, tag)) { evaluated = true; break; @@ -2263,7 +2302,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, // Now that the arguments are processed, handle the previsits checks. ExplodedNodeSet DstPrevisit; - CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback); + CheckerVisitObjCMessage(ME, DstPrevisit, ArgsEvaluated, /*isPreVisit=*/true); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; @@ -2305,7 +2344,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - evalObjCMessageExpr(dstEval, ME, Pred, notNilState); + evalObjCMessage(dstEval, ME, Pred, notNilState); } else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { IdentifierInfo* ClsName = Iface->getIdentifier(); @@ -2353,7 +2392,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred)); + evalObjCMessage(dstEval, ME, Pred, Builder->GetState(Pred)); } // Handle the case where no nodes where generated. Auto-generate that @@ -2365,7 +2404,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. - CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback); + CheckerVisitObjCMessage(ME, Dst, dstEval, /*isPreVisit=*/false); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index 6ef242ba427..b1b4773aee5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -39,7 +39,7 @@ public: return &x; } - void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); }; } // end anonymous namespace @@ -54,10 +54,10 @@ void ento::RegisterNSAutoreleasePoolChecks(ExprEngine &Eng) { } void -NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *ME) { +NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { - const Expr *receiver = ME->getInstanceReceiver(); + const Expr *receiver = msg.getInstanceReceiver(); if (!receiver) return; @@ -75,13 +75,13 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, return; // Sending 'release' message? - if (ME->getSelector() != releaseS) + if (msg.getSelector() != releaseS) return; - SourceRange R = ME->getSourceRange(); + SourceRange R = msg.getSourceRange(); C.getBugReporter().EmitBasicReport("Use -drain instead of -release", "API Upgrade (Apple)", "Use -drain instead of -release when using NSAutoreleasePool " - "and garbage collection", ME->getLocStart(), &R, 1); + "and garbage collection", R.getBegin(), &R, 1); } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 9eb6b19ec71..c887ac86ef5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -58,7 +58,7 @@ using namespace ento; static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND); static bool isInitializationMethod(const ObjCMethodDecl *MD); -static bool isInitMessage(const ObjCMessageExpr *E); +static bool isInitMessage(const ObjCMessage &msg); static bool isSelfVar(SVal location, CheckerContext &C); namespace { @@ -82,7 +82,7 @@ class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> { public: static void *getTag() { static int tag = 0; return &tag; } - void PostVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *E); + void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg); void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE); @@ -176,8 +176,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, C.EmitReport(report); } -void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C, - const ObjCMessageExpr *E) { +void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C, + ObjCMessage msg) { // When encountering a message that does initialization (init rule), // tag the return value so that we know later on that if self has this value // then it is properly initialized. @@ -187,10 +187,10 @@ void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C, C.getCurrentAnalysisContext()->getDecl()))) return; - if (isInitMessage(E)) { + if (isInitMessage(msg)) { // Tag the return value as the result of an initializer. const GRState *state = C.getState(); - SVal V = state->getSVal(E); + SVal V = state->getSVal(msg.getOriginExpr()); addSelfFlag(V, SelfFlag_InitRes, C); return; } @@ -301,6 +301,6 @@ static bool isInitializationMethod(const ObjCMethodDecl *MD) { /*ignorePrefix=*/false) == cocoa::InitRule; } -static bool isInitMessage(const ObjCMessageExpr *E) { - return cocoa::deriveNamingConvention(E->getSelector()) == cocoa::InitRule; +static bool isInitMessage(const ObjCMessage &msg) { + return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule; } diff --git a/clang/lib/StaticAnalyzer/ObjCMessage.cpp b/clang/lib/StaticAnalyzer/ObjCMessage.cpp new file mode 100644 index 00000000000..53c71750136 --- /dev/null +++ b/clang/lib/StaticAnalyzer/ObjCMessage.cpp @@ -0,0 +1,99 @@ +//===- ObjCMessage.cpp - 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. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/PathSensitive/ObjCMessage.h" + +using namespace clang; +using namespace ento; + +QualType ObjCMessage::getType(ASTContext &ctx) const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getType(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + if (isPropertySetter()) + return ctx.VoidTy; + return propE->getType(); +} + +Selector ObjCMessage::getSelector() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getSelector(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + if (isPropertySetter()) + return propE->getSetterSelector(); + return propE->getGetterSelector(); +} + +const ObjCMethodDecl *ObjCMessage::getMethodDecl() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getMethodDecl(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + if (propE->isImplicitProperty()) + return isPropertySetter() ? propE->getImplicitPropertySetter() + : propE->getImplicitPropertyGetter(); + return 0; +} + +const ObjCInterfaceDecl *ObjCMessage::getReceiverInterface() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getReceiverInterface(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + if (propE->isClassReceiver()) + return propE->getClassReceiver(); + QualType recT; + if (const Expr *recE = getInstanceReceiver()) + recT = recE->getType(); + else { + assert(propE->isSuperReceiver()); + recT = propE->getSuperReceiverType(); + } + if (const ObjCObjectPointerType *Ptr = recT->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + return 0; +} + +const Expr *ObjCMessage::getArgExpr(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); + assert(isPropertySetter()); + if (const BinaryOperator *bop = dyn_cast<BinaryOperator>(OriginE)) + if (bop->isAssignmentOp()) + return bop->getRHS(); + return 0; +} + +QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { + if (CallE) { + const Expr *Callee = CallE->getCallee(); + if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) + return FD->getResultType(); + return CallE->getType(); + } + return Msg.getResultType(ctx); +} + +SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) return State->getSValAsScalarOrLoc(CallE->getArg(i)); + QualType argT = Msg.getArgType(i); + if (Loc::IsLocType(argT) || argT->isIntegerType()) + return Msg.getArgSVal(i, State); + return UnknownVal(); +} |

