summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
diff options
context:
space:
mode:
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.h293
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
OpenPOWER on IntegriCloud