blob: 0974fe877ac20ff21bb63d81c38456e0a78519f6 [file] [log] [blame]
//===- 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<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();
}
ObjCMethodFamily ObjCMessage::getMethodFamily() const {
assert(isValid() && "This ObjCMessage is uninitialized!");
// Case 1. Explicit message send.
if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
return msgE->getMethodFamily();
const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(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<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 {
QualType resultTy;
bool isLVal = false;
if (isObjCMessage()) {
isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
Msg.getOriginExpr()->isLValue();
resultTy = Msg.getResultType(ctx);
} else if (const CXXConstructExpr *Ctor =
CallE.dyn_cast<const CXXConstructExpr *>()) {
resultTy = Ctor->getType();
} else {
const CallExpr *FunctionCall = CallE.get<const CallExpr *>();
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<const CallExpr *>()->getCallee()->IgnoreParens();
return State->getSVal(Fun);
}
SVal CallOrObjCMessage::getCXXCallee() const {
assert(isCXXCall());
const CallExpr *ActualCall = CallE.get<const CallExpr *>();
const Expr *callee =
cast<CXXMemberCallExpr>(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);
}