//===- 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/Core/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(MsgOrPropE)) return msgE->getType(); const ObjCPropertyRefExpr *propE = cast(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(MsgOrPropE)) return msgE->getSelector(); const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); if (isPropertySetter()) return propE->getSetterSelector(); return propE->getGetterSelector(); } ObjCMethodFamily ObjCMessage::getMethodFamily() const { assert(isValid() && "This ObjCMessage is uninitialized!"); // Case 1. Explicit message send. if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) return msgE->getMethodFamily(); const ObjCPropertyRefExpr *propE = cast(MsgOrPropE); // Case 2. Reference to implicit property. if (propE->isImplicitProperty()) { if (isPropertySetter()) return propE->getImplicitPropertySetter()->getMethodFamily(); else return propE->getImplicitPropertyGetter()->getMethodFamily(); } // Case 3. Reference to explicit property. const ObjCPropertyDecl *prop = propE->getExplicitProperty(); if (isPropertySetter()) { if (prop->getSetterMethodDecl()) return prop->getSetterMethodDecl()->getMethodFamily(); return prop->getSetterName().getMethodFamily(); } else { if (prop->getGetterMethodDecl()) return prop->getGetterMethodDecl()->getMethodFamily(); return prop->getGetterName().getMethodFamily(); } } const ObjCMethodDecl *ObjCMessage::getMethodDecl() const { assert(isValid() && "This ObjCMessage is uninitialized!"); if (const ObjCMessageExpr *msgE = dyn_cast(MsgOrPropE)) return msgE->getMethodDecl(); const ObjCPropertyRefExpr *propE = cast(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(MsgOrPropE)) return msgE->getReceiverInterface(); const ObjCPropertyRefExpr *propE = cast(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()) 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(MsgOrPropE)) return msgE->getArg(i); assert(isPropertySetter()); if (const BinaryOperator *bop = dyn_cast(OriginE)) if (bop->isAssignmentOp()) return bop->getRHS(); return 0; } QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { QualType resultTy; bool isLVal = false; if (isObjCMessage()) { isLVal = isa(Msg.getOriginExpr()) && Msg.getOriginExpr()->isLValue(); resultTy = Msg.getResultType(ctx); } else if (const CXXConstructExpr *Ctor = CallE.dyn_cast()) { resultTy = Ctor->getType(); } else { const CallExpr *FunctionCall = CallE.get(); isLVal = FunctionCall->isLValue(); const Expr *Callee = FunctionCall->getCallee(); if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) resultTy = FD->getResultType(); else resultTy = FunctionCall->getType(); } if (isLVal) resultTy = ctx.getPointerType(resultTy); return resultTy; } SVal CallOrObjCMessage::getFunctionCallee() const { assert(isFunctionCall()); assert(!isCXXCall()); const Expr *Fun = CallE.get()->getCallee()->IgnoreParens(); return State->getSVal(Fun); } SVal CallOrObjCMessage::getCXXCallee() const { assert(isCXXCall()); const CallExpr *ActualCall = CallE.get(); const Expr *callee = cast(ActualCall)->getImplicitObjectArgument(); // FIXME: Will eventually need to cope with member pointers. This is // a limitation in getImplicitObjectArgument(). if (!callee) return UnknownVal(); return State->getSVal(callee); } SVal CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const { assert(isObjCMessage()); return Msg.getInstanceReceiverSVal(State, LC); }