clang API Documentation
00001 //===- ObjCMessage.cpp - Wrapper for ObjC messages and dot syntax -*- C++ -*--// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines ObjCMessage which serves as a common wrapper for ObjC 00011 // message expressions or implicit messages for loading/storing ObjC properties. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 00016 #include "clang/AST/DeclCXX.h" 00017 00018 using namespace clang; 00019 using namespace ento; 00020 00021 QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { 00022 QualType resultTy; 00023 bool isLVal = false; 00024 00025 if (isObjCMessage()) { 00026 resultTy = Msg.getResultType(ctx); 00027 } else if (const CXXConstructExpr *Ctor = 00028 CallE.dyn_cast<const CXXConstructExpr *>()) { 00029 resultTy = Ctor->getType(); 00030 } else { 00031 const CallExpr *FunctionCall = CallE.get<const CallExpr *>(); 00032 00033 isLVal = FunctionCall->isGLValue(); 00034 const Expr *Callee = FunctionCall->getCallee(); 00035 if (const FunctionDecl *FD = State->getSVal(Callee, LCtx).getAsFunctionDecl()) 00036 resultTy = FD->getResultType(); 00037 else 00038 resultTy = FunctionCall->getType(); 00039 } 00040 00041 if (isLVal) 00042 resultTy = ctx.getPointerType(resultTy); 00043 00044 return resultTy; 00045 } 00046 00047 SVal CallOrObjCMessage::getFunctionCallee() const { 00048 assert(isFunctionCall()); 00049 assert(!isCXXCall()); 00050 const Expr *Fun = CallE.get<const CallExpr *>()->getCallee()->IgnoreParens(); 00051 return State->getSVal(Fun, LCtx); 00052 } 00053 00054 SVal CallOrObjCMessage::getCXXCallee() const { 00055 assert(isCXXCall()); 00056 const CallExpr *ActualCall = CallE.get<const CallExpr *>(); 00057 const Expr *callee = 00058 cast<CXXMemberCallExpr>(ActualCall)->getImplicitObjectArgument(); 00059 00060 // FIXME: Will eventually need to cope with member pointers. This is 00061 // a limitation in getImplicitObjectArgument(). 00062 if (!callee) 00063 return UnknownVal(); 00064 00065 return State->getSVal(callee, LCtx); 00066 } 00067 00068 SVal 00069 CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const { 00070 assert(isObjCMessage()); 00071 return Msg.getInstanceReceiverSVal(State, LC); 00072 } 00073 00074 const Decl *CallOrObjCMessage::getDecl() const { 00075 if (isCXXCall()) { 00076 const CXXMemberCallExpr *CE = 00077 cast<CXXMemberCallExpr>(CallE.dyn_cast<const CallExpr *>()); 00078 assert(CE); 00079 return CE->getMethodDecl(); 00080 } else if (isObjCMessage()) { 00081 return Msg.getMethodDecl(); 00082 } else if (isFunctionCall()) { 00083 // In case of a C style call, use the path sensitive information to find 00084 // the function declaration. 00085 SVal CalleeVal = getFunctionCallee(); 00086 return CalleeVal.getAsFunctionDecl(); 00087 } 00088 return 0; 00089 } 00090 00091 bool CallOrObjCMessage::isCallbackArg(unsigned Idx, const Type *T) const { 00092 // If the parameter is 0, it's harmless. 00093 if (getArgSVal(Idx).isZeroConstant()) 00094 return false; 00095 00096 // If a parameter is a block or a callback, assume it can modify pointer. 00097 if (T->isBlockPointerType() || 00098 T->isFunctionPointerType() || 00099 T->isObjCSelType()) 00100 return true; 00101 00102 // Check if a callback is passed inside a struct (for both, struct passed by 00103 // reference and by value). Dig just one level into the struct for now. 00104 if (const PointerType *PT = dyn_cast<PointerType>(T)) 00105 T = PT->getPointeeType().getTypePtr(); 00106 00107 if (const RecordType *RT = T->getAsStructureType()) { 00108 const RecordDecl *RD = RT->getDecl(); 00109 for (RecordDecl::field_iterator I = RD->field_begin(), 00110 E = RD->field_end(); I != E; ++I ) { 00111 const Type *FieldT = I->getType().getTypePtr(); 00112 if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType()) 00113 return true; 00114 } 00115 } 00116 return false; 00117 } 00118 00119 bool CallOrObjCMessage::hasNonZeroCallbackArg() const { 00120 unsigned NumOfArgs = getNumArgs(); 00121 00122 // Process ObjC message first. 00123 if (!CallE) { 00124 const ObjCMethodDecl *D = Msg.getMethodDecl(); 00125 unsigned Idx = 0; 00126 for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), 00127 E = D->param_end(); I != E; ++I, ++Idx) { 00128 if (NumOfArgs <= Idx) 00129 break; 00130 00131 if (isCallbackArg(Idx, (*I)->getType().getTypePtr())) 00132 return true; 00133 } 00134 return false; 00135 } 00136 00137 // Else, assume we are dealing with a Function call. 00138 const FunctionDecl *FD = 0; 00139 if (const CXXConstructExpr *Ctor = 00140 CallE.dyn_cast<const CXXConstructExpr *>()) 00141 FD = Ctor->getConstructor(); 00142 00143 const CallExpr * CE = CallE.get<const CallExpr *>(); 00144 FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl()); 00145 00146 // If calling using a function pointer, assume the function does not 00147 // have a callback. TODO: We could check the types of the arguments here. 00148 if (!FD) 00149 return false; 00150 00151 unsigned Idx = 0; 00152 for (FunctionDecl::param_const_iterator I = FD->param_begin(), 00153 E = FD->param_end(); I != E; ++I, ++Idx) { 00154 if (NumOfArgs <= Idx) 00155 break; 00156 00157 if (isCallbackArg(Idx, (*I)->getType().getTypePtr())) 00158 return true; 00159 } 00160 return false; 00161 } 00162 00163 bool CallOrObjCMessage::isCFCGAllowingEscape(StringRef FName) { 00164 if (!FName.startswith("CF") && !FName.startswith("CG")) 00165 return false; 00166 00167 return StrInStrNoCase(FName, "InsertValue") != StringRef::npos || 00168 StrInStrNoCase(FName, "AddValue") != StringRef::npos || 00169 StrInStrNoCase(FName, "SetValue") != StringRef::npos || 00170 StrInStrNoCase(FName, "WithData") != StringRef::npos || 00171 StrInStrNoCase(FName, "AppendValue") != StringRef::npos || 00172 StrInStrNoCase(FName, "SetAttribute") != StringRef::npos; 00173 } 00174 00175