Home | History | Annotate | Download | only in PathSensitive
      1 //===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines ObjCMessage which serves as a common wrapper for ObjC
     11 // message expressions or implicit messages for loading/storing ObjC properties.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
     16 #define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
     17 
     18 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
     19 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
     20 #include "clang/AST/ExprObjC.h"
     21 #include "clang/AST/ExprCXX.h"
     22 #include "clang/Basic/SourceManager.h"
     23 #include "llvm/ADT/PointerUnion.h"
     24 #include "llvm/ADT/StringExtras.h"
     25 #include "llvm/Support/Compiler.h"
     26 
     27 namespace clang {
     28 namespace ento {
     29 using llvm::StrInStrNoCase;
     30 
     31 /// \brief Represents both explicit ObjC message expressions and implicit
     32 /// messages that are sent for handling properties in dot syntax.
     33 class ObjCMessage {
     34   const ObjCMessageExpr *Msg;
     35   const ObjCPropertyRefExpr *PE;
     36   const bool IsPropSetter;
     37 public:
     38   ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
     39 
     40   ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0,
     41               bool isSetter = false)
     42     : Msg(E), PE(pe), IsPropSetter(isSetter) {
     43     assert(E && "should not be initialized with null expression");
     44   }
     45 
     46   bool isValid() const { return Msg; }
     47 
     48   bool isPureMessageExpr() const { return !PE; }
     49 
     50   bool isPropertyGetter() const { return PE && !IsPropSetter; }
     51 
     52   bool isPropertySetter() const {
     53     return IsPropSetter;
     54   }
     55 
     56   const Expr *getMessageExpr() const {
     57     return Msg;
     58   }
     59 
     60   QualType getType(ASTContext &ctx) const {
     61     return Msg->getType();
     62   }
     63 
     64   QualType getResultType(ASTContext &ctx) const {
     65     if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
     66       return MD->getResultType();
     67     return getType(ctx);
     68   }
     69 
     70   ObjCMethodFamily getMethodFamily() const {
     71     return Msg->getMethodFamily();
     72   }
     73 
     74   Selector getSelector() const {
     75     return Msg->getSelector();
     76   }
     77 
     78   const Expr *getInstanceReceiver() const {
     79     return Msg->getInstanceReceiver();
     80   }
     81 
     82   SVal getInstanceReceiverSVal(ProgramStateRef State,
     83                                const LocationContext *LC) const {
     84     if (!isInstanceMessage())
     85       return UndefinedVal();
     86     if (const Expr *Ex = getInstanceReceiver())
     87       return State->getSValAsScalarOrLoc(Ex, LC);
     88 
     89     // An instance message with no expression means we are sending to super.
     90     // In this case the object reference is the same as 'self'.
     91     const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
     92     assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
     93     return State->getSVal(State->getRegion(SelfDecl, LC));
     94   }
     95 
     96   bool isInstanceMessage() const {
     97     return Msg->isInstanceMessage();
     98   }
     99 
    100   const ObjCMethodDecl *getMethodDecl() const {
    101     return Msg->getMethodDecl();
    102   }
    103 
    104   const ObjCInterfaceDecl *getReceiverInterface() const {
    105     return Msg->getReceiverInterface();
    106   }
    107 
    108   SourceLocation getSuperLoc() const {
    109     if (PE)
    110       return PE->getReceiverLocation();
    111     return Msg->getSuperLoc();
    112   }
    113 
    114   SourceRange getSourceRange() const LLVM_READONLY {
    115     if (PE)
    116       return PE->getSourceRange();
    117     return Msg->getSourceRange();
    118   }
    119 
    120   unsigned getNumArgs() const {
    121     return Msg->getNumArgs();
    122   }
    123 
    124   SVal getArgSVal(unsigned i,
    125                   const LocationContext *LCtx,
    126                   ProgramStateRef state) const {
    127     assert(i < getNumArgs() && "Invalid index for argument");
    128     return state->getSVal(Msg->getArg(i), LCtx);
    129   }
    130 
    131   QualType getArgType(unsigned i) const {
    132     assert(i < getNumArgs() && "Invalid index for argument");
    133     return Msg->getArg(i)->getType();
    134   }
    135 
    136   const Expr *getArgExpr(unsigned i) const {
    137     assert(i < getNumArgs() && "Invalid index for argument");
    138     return Msg->getArg(i);
    139   }
    140 
    141   SourceRange getArgSourceRange(unsigned i) const {
    142     const Expr *argE = getArgExpr(i);
    143     return argE->getSourceRange();
    144   }
    145 
    146   SourceRange getReceiverSourceRange() const {
    147     if (PE) {
    148       if (PE->isObjectReceiver())
    149         return PE->getBase()->getSourceRange();
    150     }
    151     else {
    152       return Msg->getReceiverRange();
    153     }
    154 
    155     // FIXME: This isn't a range.
    156     return PE->getReceiverLocation();
    157   }
    158 };
    159 
    160 /// \brief Common wrapper for a call expression, ObjC message, or C++
    161 /// constructor, mainly to provide a common interface for their arguments.
    162 class CallOrObjCMessage {
    163   llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
    164   ObjCMessage Msg;
    165   ProgramStateRef State;
    166   const LocationContext *LCtx;
    167 public:
    168   CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state,
    169                     const LocationContext *lctx)
    170     : CallE(callE), State(state), LCtx(lctx) {}
    171   CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state,
    172                     const LocationContext *lctx)
    173     : CallE(consE), State(state), LCtx(lctx) {}
    174   CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state,
    175                     const LocationContext *lctx)
    176     : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {}
    177 
    178   QualType getResultType(ASTContext &ctx) const;
    179 
    180   bool isFunctionCall() const {
    181     return CallE && CallE.is<const CallExpr *>();
    182   }
    183 
    184   bool isCXXConstructExpr() const {
    185     return CallE && CallE.is<const CXXConstructExpr *>();
    186   }
    187 
    188   bool isObjCMessage() const {
    189     return !CallE;
    190   }
    191 
    192   bool isCXXCall() const {
    193     const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
    194     return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
    195   }
    196 
    197   /// Check if the callee is declared in the system header.
    198   bool isInSystemHeader() const {
    199     if (const Decl *FD = getDecl()) {
    200       const SourceManager &SM =
    201         State->getStateManager().getContext().getSourceManager();
    202       return SM.isInSystemHeader(FD->getLocation());
    203     }
    204     return false;
    205   }
    206 
    207   const Expr *getOriginExpr() const {
    208     if (!CallE)
    209       return Msg.getMessageExpr();
    210     if (const CXXConstructExpr *Ctor =
    211           CallE.dyn_cast<const CXXConstructExpr *>())
    212       return Ctor;
    213     return CallE.get<const CallExpr *>();
    214   }
    215 
    216   SVal getFunctionCallee() const;
    217   SVal getCXXCallee() const;
    218   SVal getInstanceMessageReceiver(const LocationContext *LC) const;
    219 
    220   /// Get the declaration of the function or method.
    221   const Decl *getDecl() const;
    222 
    223   unsigned getNumArgs() const {
    224     if (!CallE)
    225       return Msg.getNumArgs();
    226     if (const CXXConstructExpr *Ctor =
    227           CallE.dyn_cast<const CXXConstructExpr *>())
    228       return Ctor->getNumArgs();
    229     return CallE.get<const CallExpr *>()->getNumArgs();
    230   }
    231 
    232   SVal getArgSVal(unsigned i) const {
    233     assert(i < getNumArgs());
    234     if (!CallE)
    235       return Msg.getArgSVal(i, LCtx, State);
    236     return State->getSVal(getArg(i), LCtx);
    237   }
    238 
    239   const Expr *getArg(unsigned i) const {
    240     assert(i < getNumArgs());
    241     if (!CallE)
    242       return Msg.getArgExpr(i);
    243     if (const CXXConstructExpr *Ctor =
    244           CallE.dyn_cast<const CXXConstructExpr *>())
    245       return Ctor->getArg(i);
    246     return CallE.get<const CallExpr *>()->getArg(i);
    247   }
    248 
    249   SourceRange getArgSourceRange(unsigned i) const {
    250     assert(i < getNumArgs());
    251     if (CallE)
    252       return getArg(i)->getSourceRange();
    253     return Msg.getArgSourceRange(i);
    254   }
    255 
    256   SourceRange getReceiverSourceRange() const {
    257     assert(isObjCMessage());
    258     return Msg.getReceiverSourceRange();
    259   }
    260 
    261   /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics
    262   /// function that allows objects to escape.
    263   ///
    264   /// Many methods allow a tracked object to escape.  For example:
    265   ///
    266   ///   CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
    267   ///   CFDictionaryAddValue(y, key, x);
    268   ///
    269   /// We handle this and similar cases with the following heuristic.  If the
    270   /// function name contains "InsertValue", "SetValue", "AddValue",
    271   /// "AppendValue", or "SetAttribute", then we assume that arguments may
    272   /// escape.
    273   //
    274   // TODO: To reduce false negatives here, we should track the container
    275   // allocation site and check if a proper deallocator was set there.
    276   static bool isCFCGAllowingEscape(StringRef FName) {
    277     if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G'))
    278            if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
    279                StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
    280                StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
    281                StrInStrNoCase(FName, "WithData") != StringRef::npos ||
    282                StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
    283                StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) {
    284          return true;
    285        }
    286     return false;
    287   }
    288 };
    289 
    290 }
    291 }
    292 
    293 #endif
    294