//===- 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/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/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(MsgOrPropE); } bool isPropertyGetter() const { return isValid() && isa(MsgOrPropE) && !IsPropSetter; } bool isPropertySetter() const { return isValid() && isa(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(MsgOrPropE)) if (const ObjCMethodDecl *MD = msgE->getMethodDecl()) return MD->getResultType(); return getType(ctx); } ObjCMethodFamily getMethodFamily() const; Selector getSelector() const; const Expr *getInstanceReceiver() const { assert(isValid() && "This ObjCMessage is uninitialized!"); if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) return msgE->getInstanceReceiver(); const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); if (propE->isObjectReceiver()) return propE->getBase(); return 0; } bool isInstanceMessage() const { assert(isValid() && "This ObjCMessage is uninitialized!"); if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) return msgE->isInstanceMessage(); const ObjCPropertyRefExpr *propE = cast(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(MsgOrPropE)) return msgE->getSuperLoc(); return cast(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(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(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(MsgOrPropE)) return msgE->getArg(i)->getType(); assert(isPropertySetter()); return cast(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; bool isFunctionCall() const { return (bool) CallE; } bool isCXXCall() const { return CallE && isa(CallE); } SVal getFunctionCallee() const; SVal getCXXCallee() 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