diff options
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h')
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h new file mode 100644 index 0000000..710fc6b --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -0,0 +1,210 @@ +//===- 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<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(); + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + if (propE->isObjectReceiver()) + return propE->getBase(); + return 0; + } + + 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 |