2011-01-25 08:03:53 +08:00
|
|
|
//===- 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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-02-10 09:03:03 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
|
2011-12-21 06:35:30 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2011-01-25 08:03:53 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
using namespace ento;
|
|
|
|
|
|
|
|
QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
|
2011-03-31 01:41:19 +08:00
|
|
|
QualType resultTy;
|
|
|
|
bool isLVal = false;
|
2011-04-12 06:22:05 +08:00
|
|
|
|
2011-08-28 06:51:26 +08:00
|
|
|
if (isObjCMessage()) {
|
2011-03-31 01:41:19 +08:00
|
|
|
resultTy = Msg.getResultType(ctx);
|
2011-08-28 06:51:26 +08:00
|
|
|
} 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();
|
2012-01-07 06:09:28 +08:00
|
|
|
if (const FunctionDecl *FD = State->getSVal(Callee, LCtx).getAsFunctionDecl())
|
2011-08-28 06:51:26 +08:00
|
|
|
resultTy = FD->getResultType();
|
|
|
|
else
|
|
|
|
resultTy = FunctionCall->getType();
|
2011-01-25 08:03:53 +08:00
|
|
|
}
|
2011-03-31 01:41:19 +08:00
|
|
|
|
|
|
|
if (isLVal)
|
|
|
|
resultTy = ctx.getPointerType(resultTy);
|
|
|
|
|
|
|
|
return resultTy;
|
2011-01-25 08:03:53 +08:00
|
|
|
}
|
|
|
|
|
2011-05-26 07:57:29 +08:00
|
|
|
SVal CallOrObjCMessage::getFunctionCallee() const {
|
|
|
|
assert(isFunctionCall());
|
|
|
|
assert(!isCXXCall());
|
2011-08-28 06:51:26 +08:00
|
|
|
const Expr *Fun = CallE.get<const CallExpr *>()->getCallee()->IgnoreParens();
|
2012-01-07 06:09:28 +08:00
|
|
|
return State->getSVal(Fun, LCtx);
|
2011-05-26 07:57:29 +08:00
|
|
|
}
|
|
|
|
|
2011-04-12 06:22:05 +08:00
|
|
|
SVal CallOrObjCMessage::getCXXCallee() const {
|
|
|
|
assert(isCXXCall());
|
2011-08-28 06:51:26 +08:00
|
|
|
const CallExpr *ActualCall = CallE.get<const CallExpr *>();
|
2011-04-12 06:22:05 +08:00
|
|
|
const Expr *callee =
|
2011-08-28 06:51:26 +08:00
|
|
|
cast<CXXMemberCallExpr>(ActualCall)->getImplicitObjectArgument();
|
2011-10-07 04:53:28 +08:00
|
|
|
|
|
|
|
// FIXME: Will eventually need to cope with member pointers. This is
|
|
|
|
// a limitation in getImplicitObjectArgument().
|
|
|
|
if (!callee)
|
|
|
|
return UnknownVal();
|
|
|
|
|
2012-01-07 06:09:28 +08:00
|
|
|
return State->getSVal(callee, LCtx);
|
2011-04-12 06:22:05 +08:00
|
|
|
}
|
2011-08-28 13:16:28 +08:00
|
|
|
|
|
|
|
SVal
|
|
|
|
CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const {
|
|
|
|
assert(isObjCMessage());
|
|
|
|
return Msg.getInstanceReceiverSVal(State, LC);
|
|
|
|
}
|
2011-12-21 06:35:30 +08:00
|
|
|
|
|
|
|
const Decl *CallOrObjCMessage::getDecl() const {
|
|
|
|
if (isCXXCall()) {
|
|
|
|
const CXXMemberCallExpr *CE =
|
|
|
|
cast<CXXMemberCallExpr>(CallE.dyn_cast<const CallExpr *>());
|
|
|
|
assert(CE);
|
|
|
|
return CE->getMethodDecl();
|
|
|
|
} else if (isObjCMessage()) {
|
|
|
|
return Msg.getMethodDecl();
|
|
|
|
} else if (isFunctionCall()) {
|
|
|
|
// In case of a C style call, use the path sensitive information to find
|
|
|
|
// the function declaration.
|
|
|
|
SVal CalleeVal = getFunctionCallee();
|
|
|
|
return CalleeVal.getAsFunctionDecl();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-04 07:50:28 +08:00
|
|
|
bool CallOrObjCMessage::isCallbackArg(unsigned Idx, const Type *T) const {
|
|
|
|
// Should we dig into struct fields, arrays ect?
|
|
|
|
if (T->isBlockPointerType() || T->isFunctionPointerType())
|
|
|
|
if (!getArgSVal(Idx).isZeroConstant())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CallOrObjCMessage::hasNonZeroCallbackArg() const {
|
|
|
|
unsigned NumOfArgs = getNumArgs();
|
|
|
|
|
|
|
|
// Process ObjC message first.
|
|
|
|
if (!CallE) {
|
|
|
|
const ObjCMethodDecl *D = Msg.getMethodDecl();
|
|
|
|
unsigned Idx = 0;
|
|
|
|
for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
|
|
|
|
E = D->param_end(); I != E; ++I, ++Idx) {
|
|
|
|
if (NumOfArgs <= Idx)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (isCallbackArg(Idx, (*I)->getType().getTypePtr()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Else, assume we are dealing with a Function call.
|
|
|
|
const FunctionDecl *FD = 0;
|
|
|
|
if (const CXXConstructExpr *Ctor =
|
|
|
|
CallE.dyn_cast<const CXXConstructExpr *>())
|
|
|
|
FD = Ctor->getConstructor();
|
|
|
|
|
|
|
|
const CallExpr * CE = CallE.get<const CallExpr *>();
|
|
|
|
FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
|
|
|
|
|
|
|
|
// If calling using a function pointer, assume the function does not
|
|
|
|
// have a callback. TODO: We could check the types of the arguments here.
|
|
|
|
if (!FD)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned Idx = 0;
|
|
|
|
for (FunctionDecl::param_const_iterator I = FD->param_begin(),
|
|
|
|
E = FD->param_end(); I != E; ++I, ++Idx) {
|
|
|
|
if (NumOfArgs <= Idx)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (isCallbackArg(Idx, (*I)->getType().getTypePtr()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CallOrObjCMessage::isCFCGAllowingEscape(StringRef FName) {
|
|
|
|
if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G'))
|
|
|
|
if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
|
|
|
|
StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
|
|
|
|
StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
|
|
|
|
StrInStrNoCase(FName, "WithData") != StringRef::npos ||
|
|
|
|
StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
|
|
|
|
StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|