clang API Documentation

ObjCMessage.cpp
Go to the documentation of this file.
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