diff options
Diffstat (limited to 'contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h')
-rw-r--r-- | contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h new file mode 100644 index 0000000..d8aec09 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -0,0 +1,293 @@ +//===- ObjCMessage.h - 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. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE +#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE + +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace ento { +using llvm::StrInStrNoCase; + +/// \brief Represents both explicit ObjC message expressions and implicit +/// messages that are sent for handling properties in dot syntax. +class ObjCMessage { + const ObjCMessageExpr *Msg; + const ObjCPropertyRefExpr *PE; + const bool IsPropSetter; +public: + ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {} + + ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0, + bool isSetter = false) + : Msg(E), PE(pe), IsPropSetter(isSetter) { + assert(E && "should not be initialized with null expression"); + } + + bool isValid() const { return Msg; } + + bool isPureMessageExpr() const { return !PE; } + + bool isPropertyGetter() const { return PE && !IsPropSetter; } + + bool isPropertySetter() const { + return IsPropSetter; + } + + const Expr *getMessageExpr() const { + return Msg; + } + + QualType getType(ASTContext &ctx) const { + return Msg->getType(); + } + + QualType getResultType(ASTContext &ctx) const { + if (const ObjCMethodDecl *MD = Msg->getMethodDecl()) + return MD->getResultType(); + return getType(ctx); + } + + ObjCMethodFamily getMethodFamily() const { + return Msg->getMethodFamily(); + } + + Selector getSelector() const { + return Msg->getSelector(); + } + + const Expr *getInstanceReceiver() const { + return Msg->getInstanceReceiver(); + } + + SVal getInstanceReceiverSVal(ProgramStateRef State, + const LocationContext *LC) const { + if (!isInstanceMessage()) + return UndefinedVal(); + if (const Expr *Ex = getInstanceReceiver()) + return State->getSValAsScalarOrLoc(Ex, LC); + + // An instance message with no expression means we are sending to super. + // In this case the object reference is the same as 'self'. + const ImplicitParamDecl *SelfDecl = LC->getSelfDecl(); + assert(SelfDecl && "No message receiver Expr, but not in an ObjC method"); + return State->getSVal(State->getRegion(SelfDecl, LC)); + } + + bool isInstanceMessage() const { + return Msg->isInstanceMessage(); + } + + const ObjCMethodDecl *getMethodDecl() const { + return Msg->getMethodDecl(); + } + + const ObjCInterfaceDecl *getReceiverInterface() const { + return Msg->getReceiverInterface(); + } + + SourceLocation getSuperLoc() const { + if (PE) + return PE->getReceiverLocation(); + return Msg->getSuperLoc(); + } + + SourceRange getSourceRange() const LLVM_READONLY { + if (PE) + return PE->getSourceRange(); + return Msg->getSourceRange(); + } + + unsigned getNumArgs() const { + return Msg->getNumArgs(); + } + + SVal getArgSVal(unsigned i, + const LocationContext *LCtx, + ProgramStateRef state) const { + assert(i < getNumArgs() && "Invalid index for argument"); + return state->getSVal(Msg->getArg(i), LCtx); + } + + QualType getArgType(unsigned i) const { + assert(i < getNumArgs() && "Invalid index for argument"); + return Msg->getArg(i)->getType(); + } + + const Expr *getArgExpr(unsigned i) const { + assert(i < getNumArgs() && "Invalid index for argument"); + return Msg->getArg(i); + } + + SourceRange getArgSourceRange(unsigned i) const { + const Expr *argE = getArgExpr(i); + return argE->getSourceRange(); + } + + SourceRange getReceiverSourceRange() const { + if (PE) { + if (PE->isObjectReceiver()) + return PE->getBase()->getSourceRange(); + } + else { + return Msg->getReceiverRange(); + } + + // FIXME: This isn't a range. + return PE->getReceiverLocation(); + } +}; + +/// \brief Common wrapper for a call expression, ObjC message, or C++ +/// constructor, mainly to provide a common interface for their arguments. +class CallOrObjCMessage { + llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE; + ObjCMessage Msg; + ProgramStateRef State; + const LocationContext *LCtx; +public: + CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state, + const LocationContext *lctx) + : CallE(callE), State(state), LCtx(lctx) {} + CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state, + const LocationContext *lctx) + : CallE(consE), State(state), LCtx(lctx) {} + CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state, + const LocationContext *lctx) + : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {} + + QualType getResultType(ASTContext &ctx) const; + + bool isFunctionCall() const { + return CallE && CallE.is<const CallExpr *>(); + } + + bool isCXXConstructExpr() const { + return CallE && CallE.is<const CXXConstructExpr *>(); + } + + bool isObjCMessage() const { + return !CallE; + } + + bool isCXXCall() const { + const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>(); + return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE); + } + + /// Check if the callee is declared in the system header. + bool isInSystemHeader() const { + if (const Decl *FD = getDecl()) { + const SourceManager &SM = + State->getStateManager().getContext().getSourceManager(); + return SM.isInSystemHeader(FD->getLocation()); + } + return false; + } + + const Expr *getOriginExpr() const { + if (!CallE) + return Msg.getMessageExpr(); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) + return Ctor; + return CallE.get<const CallExpr *>(); + } + + SVal getFunctionCallee() const; + SVal getCXXCallee() const; + SVal getInstanceMessageReceiver(const LocationContext *LC) const; + + /// Get the declaration of the function or method. + const Decl *getDecl() const; + + unsigned getNumArgs() const { + if (!CallE) + return Msg.getNumArgs(); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) + return Ctor->getNumArgs(); + return CallE.get<const CallExpr *>()->getNumArgs(); + } + + SVal getArgSVal(unsigned i) const { + assert(i < getNumArgs()); + if (!CallE) + return Msg.getArgSVal(i, LCtx, State); + return State->getSVal(getArg(i), LCtx); + } + + const Expr *getArg(unsigned i) const { + assert(i < getNumArgs()); + if (!CallE) + return Msg.getArgExpr(i); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) + return Ctor->getArg(i); + return CallE.get<const CallExpr *>()->getArg(i); + } + + SourceRange getArgSourceRange(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) + return getArg(i)->getSourceRange(); + return Msg.getArgSourceRange(i); + } + + SourceRange getReceiverSourceRange() const { + assert(isObjCMessage()); + return Msg.getReceiverSourceRange(); + } + + /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics + /// function that allows objects to escape. + /// + /// Many methods allow a tracked object to escape. For example: + /// + /// CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator); + /// CFDictionaryAddValue(y, key, x); + /// + /// We handle this and similar cases with the following heuristic. If the + /// function name contains "InsertValue", "SetValue", "AddValue", + /// "AppendValue", or "SetAttribute", then we assume that arguments may + /// escape. + // + // TODO: To reduce false negatives here, we should track the container + // allocation site and check if a proper deallocator was set there. + static bool 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; + } +}; + +} +} + +#endif |