clang API Documentation

ObjCMessage.h
Go to the documentation of this file.
00001 //===- ObjCMessage.h - 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 #ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
00016 #define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
00017 
00018 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
00019 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
00020 #include "clang/AST/ExprObjC.h"
00021 #include "clang/AST/ExprCXX.h"
00022 #include "clang/Basic/SourceManager.h"
00023 #include "llvm/ADT/PointerUnion.h"
00024 #include "llvm/ADT/StringExtras.h"
00025 #include "llvm/Support/Compiler.h"
00026 
00027 namespace clang {
00028 namespace ento {
00029 using llvm::StrInStrNoCase;
00030 
00031 /// \brief Represents both explicit ObjC message expressions and implicit
00032 /// messages that are sent for handling properties in dot syntax.
00033 class ObjCMessage {
00034   const ObjCMessageExpr *Msg;
00035   const ObjCPropertyRefExpr *PE;
00036   const bool IsPropSetter;
00037 public:
00038   ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
00039 
00040   ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0,
00041               bool isSetter = false)
00042     : Msg(E), PE(pe), IsPropSetter(isSetter) {
00043     assert(E && "should not be initialized with null expression");
00044   }
00045 
00046   bool isValid() const { return Msg; }
00047   
00048   bool isPureMessageExpr() const { return !PE; }
00049 
00050   bool isPropertyGetter() const { return PE && !IsPropSetter; }
00051 
00052   bool isPropertySetter() const {
00053     return IsPropSetter;
00054   }
00055 
00056   const Expr *getMessageExpr() const { 
00057     return Msg;
00058   }
00059 
00060   QualType getType(ASTContext &ctx) const {
00061     return Msg->getType();
00062   }
00063 
00064   QualType getResultType(ASTContext &ctx) const {
00065     if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
00066       return MD->getResultType();
00067     return getType(ctx);
00068   }
00069 
00070   ObjCMethodFamily getMethodFamily() const {
00071     return Msg->getMethodFamily();
00072   }
00073 
00074   Selector getSelector() const {
00075     return Msg->getSelector();
00076   }
00077 
00078   const Expr *getInstanceReceiver() const {
00079     return Msg->getInstanceReceiver();
00080   }
00081 
00082   SVal getInstanceReceiverSVal(ProgramStateRef State,
00083                                const LocationContext *LC) const {
00084     if (!isInstanceMessage())
00085       return UndefinedVal();
00086     if (const Expr *Ex = getInstanceReceiver())
00087       return State->getSValAsScalarOrLoc(Ex, LC);
00088 
00089     // An instance message with no expression means we are sending to super.
00090     // In this case the object reference is the same as 'self'.
00091     const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
00092     assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
00093     return State->getSVal(State->getRegion(SelfDecl, LC));
00094   }
00095 
00096   bool isInstanceMessage() const {
00097     return Msg->isInstanceMessage();
00098   }
00099 
00100   const ObjCMethodDecl *getMethodDecl() const {
00101     return Msg->getMethodDecl();
00102   }
00103 
00104   const ObjCInterfaceDecl *getReceiverInterface() const {
00105     return Msg->getReceiverInterface();
00106   }
00107 
00108   SourceLocation getSuperLoc() const {
00109     if (PE)
00110       return PE->getReceiverLocation();
00111     return Msg->getSuperLoc();
00112   }  
00113 
00114   SourceRange getSourceRange() const LLVM_READONLY {
00115     if (PE)
00116       return PE->getSourceRange();
00117     return Msg->getSourceRange();
00118   }
00119 
00120   unsigned getNumArgs() const {
00121     return Msg->getNumArgs();
00122   }
00123 
00124   SVal getArgSVal(unsigned i,
00125                   const LocationContext *LCtx,
00126                   ProgramStateRef state) const {
00127     assert(i < getNumArgs() && "Invalid index for argument");
00128     return state->getSVal(Msg->getArg(i), LCtx);
00129   }
00130 
00131   QualType getArgType(unsigned i) const {
00132     assert(i < getNumArgs() && "Invalid index for argument");
00133     return Msg->getArg(i)->getType();
00134   }
00135 
00136   const Expr *getArgExpr(unsigned i) const {
00137     assert(i < getNumArgs() && "Invalid index for argument");
00138     return Msg->getArg(i);
00139   }
00140 
00141   SourceRange getArgSourceRange(unsigned i) const {
00142     const Expr *argE = getArgExpr(i);
00143     return argE->getSourceRange();
00144   }
00145 
00146   SourceRange getReceiverSourceRange() const {
00147     if (PE) {
00148       if (PE->isObjectReceiver())
00149         return PE->getBase()->getSourceRange();
00150     }
00151     else {
00152       return Msg->getReceiverRange();
00153     }
00154 
00155     // FIXME: This isn't a range.
00156     return PE->getReceiverLocation();
00157   }
00158 };
00159 
00160 /// \brief Common wrapper for a call expression, ObjC message, or C++ 
00161 /// constructor, mainly to provide a common interface for their arguments.
00162 class CallOrObjCMessage {
00163   llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
00164   ObjCMessage Msg;
00165   ProgramStateRef State;
00166   const LocationContext *LCtx;
00167 
00168   bool isCallbackArg(unsigned Idx, const Type *T) const;
00169 
00170 public:
00171   CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state,
00172                     const LocationContext *lctx)
00173     : CallE(callE), State(state), LCtx(lctx) {}
00174   CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state,
00175                     const LocationContext *lctx)
00176     : CallE(consE), State(state), LCtx(lctx) {}
00177   CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state,
00178                     const LocationContext *lctx)
00179     : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {}
00180 
00181   QualType getResultType(ASTContext &ctx) const;
00182   
00183   bool isFunctionCall() const {
00184     return CallE && CallE.is<const CallExpr *>();
00185   }
00186 
00187   bool isCXXConstructExpr() const {
00188     return CallE && CallE.is<const CXXConstructExpr *>();
00189   }
00190 
00191   bool isObjCMessage() const {
00192     return !CallE;
00193   }
00194 
00195   bool isCXXCall() const {
00196     const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
00197     return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
00198   }
00199 
00200   /// Check if the callee is declared in the system header.
00201   bool isInSystemHeader() const {
00202     if (const Decl *FD = getDecl()) {
00203       const SourceManager &SM =
00204         State->getStateManager().getContext().getSourceManager();
00205       return SM.isInSystemHeader(FD->getLocation());
00206     }
00207     return false;
00208   }
00209 
00210   const Expr *getOriginExpr() const {
00211     if (!CallE)
00212       return Msg.getMessageExpr();
00213     if (const CXXConstructExpr *Ctor =
00214           CallE.dyn_cast<const CXXConstructExpr *>())
00215       return Ctor;
00216     return CallE.get<const CallExpr *>();
00217   }
00218   
00219   SVal getFunctionCallee() const;
00220   SVal getCXXCallee() const;
00221   SVal getInstanceMessageReceiver(const LocationContext *LC) const;
00222 
00223   /// Get the declaration of the function or method.
00224   const Decl *getDecl() const;
00225 
00226   unsigned getNumArgs() const {
00227     if (!CallE)
00228       return Msg.getNumArgs();
00229     if (const CXXConstructExpr *Ctor =
00230           CallE.dyn_cast<const CXXConstructExpr *>())
00231       return Ctor->getNumArgs();
00232     return CallE.get<const CallExpr *>()->getNumArgs();
00233   }
00234 
00235   SVal getArgSVal(unsigned i) const {
00236     assert(i < getNumArgs());
00237     if (!CallE)
00238       return Msg.getArgSVal(i, LCtx, State);
00239     return State->getSVal(getArg(i), LCtx);
00240   }
00241 
00242   const Expr *getArg(unsigned i) const {
00243     assert(i < getNumArgs());
00244     if (!CallE)
00245       return Msg.getArgExpr(i);
00246     if (const CXXConstructExpr *Ctor =
00247           CallE.dyn_cast<const CXXConstructExpr *>())
00248       return Ctor->getArg(i);
00249     return CallE.get<const CallExpr *>()->getArg(i);
00250   }
00251 
00252   SourceRange getArgSourceRange(unsigned i) const {
00253     assert(i < getNumArgs());
00254     if (CallE)
00255       return getArg(i)->getSourceRange();
00256     return Msg.getArgSourceRange(i);
00257   }
00258 
00259   SourceRange getReceiverSourceRange() const {
00260     assert(isObjCMessage());
00261     return Msg.getReceiverSourceRange();
00262   }
00263 
00264   /// \brief Check if one of the arguments might be a callback.
00265   bool hasNonZeroCallbackArg() const;
00266 
00267 
00268   /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics 
00269   /// function that allows objects to escape.
00270   ///
00271   /// Many methods allow a tracked object to escape.  For example:
00272   ///
00273   ///   CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
00274   ///   CFDictionaryAddValue(y, key, x);
00275   ///
00276   /// We handle this and similar cases with the following heuristic.  If the
00277   /// function name contains "InsertValue", "SetValue", "AddValue",
00278   /// "AppendValue", or "SetAttribute", then we assume that arguments may
00279   /// escape.
00280   //
00281   // TODO: To reduce false negatives here, we should track the container
00282   // allocation site and check if a proper deallocator was set there.
00283   static bool isCFCGAllowingEscape(StringRef FName);
00284 };
00285 
00286 }
00287 }
00288 
00289 #endif