aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h35
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h163
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp53
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp121
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp1
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp29
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/Calls.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp1
17 files changed, 153 insertions, 343 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index fb224ef158..07a1ccff6c 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -122,7 +122,7 @@ public:
class PreObjCMessage {
template <typename CHECKER>
- static void _checkObjCMessage(void *checker, const ObjCMessage &msg,
+ static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
CheckerContext &C) {
((const CHECKER *)checker)->checkPreObjCMessage(msg, C);
}
@@ -137,7 +137,7 @@ public:
class PostObjCMessage {
template <typename CHECKER>
- static void _checkObjCMessage(void *checker, const ObjCMessage &msg,
+ static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
CheckerContext &C) {
((const CHECKER *)checker)->checkPostObjCMessage(msg, C);
}
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 3202fbe6b8..eef82fe848 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -33,7 +33,7 @@ namespace ento {
class AnalysisManager;
class BugReporter;
class CheckerContext;
- class ObjCMessage;
+ class ObjCMethodCall;
class SVal;
class ExplodedNode;
class ExplodedNodeSet;
@@ -207,7 +207,7 @@ public:
/// \brief Run checkers for pre-visiting obj-c messages.
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMessage &msg,
+ const ObjCMethodCall &msg,
ExprEngine &Eng) {
runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng);
}
@@ -215,7 +215,7 @@ public:
/// \brief Run checkers for post-visiting obj-c messages.
void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMessage &msg,
+ const ObjCMethodCall &msg,
ExprEngine &Eng) {
runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng);
}
@@ -224,7 +224,7 @@ public:
void runCheckersForObjCMessage(bool isPreVisit,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMessage &msg, ExprEngine &Eng);
+ const ObjCMethodCall &msg, ExprEngine &Eng);
/// \brief Run checkers for load/store of a location.
void runCheckersForLocation(ExplodedNodeSet &Dst,
@@ -343,7 +343,7 @@ public:
typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc;
- typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)>
+ typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>
CheckObjCMessageFunc;
typedef CheckerFn<void (const SVal &location, bool isLoad,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
index fdfb485a52..a16eb4afef 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
@@ -20,8 +20,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
namespace clang {
@@ -114,6 +113,10 @@ public:
/// \brief Returns the kind of call this is.
Kind getKind() const { return K; }
+ /// \brief Returns a source range for the entire call, suitable for
+ /// outputting in diagnostics.
+ virtual SourceRange getSourceRange() const = 0;
+
/// \brief Returns the value of a given argument at the time of the call.
virtual SVal getArgSVal(unsigned Index) const;
@@ -213,6 +216,7 @@ public:
const FunctionDecl *getDecl() const;
unsigned getNumArgs() const { return CE->getNumArgs(); }
+ SourceRange getSourceRange() const { return CE->getSourceRange(); }
const Expr *getArgExpr(unsigned Index) const {
return CE->getArg(Index);
@@ -305,6 +309,7 @@ public:
: AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(target) {}
const CXXConstructExpr *getOriginExpr() const { return CE; }
+ SourceRange getSourceRange() const { return CE->getSourceRange(); }
const CXXConstructorDecl *getDecl() const {
return CE->getConstructor();
@@ -341,7 +346,9 @@ public:
Selector getSelector() const { return Msg->getSelector(); }
bool isInstanceMessage() const { return Msg->isInstanceMessage(); }
ObjCMethodFamily getMethodFamily() const { return Msg->getMethodFamily(); }
+
const ObjCMethodDecl *getDecl() const { return Msg->getMethodDecl(); }
+ SourceRange getSourceRange() const { return Msg->getSourceRange(); }
unsigned getNumArgs() const { return Msg->getNumArgs(); }
const Expr *getArgExpr(unsigned Index) const {
return Msg->getArg(Index);
@@ -351,6 +358,10 @@ public:
SVal getReceiverSVal() const;
+ const Expr *getInstanceReceiverExpr() const {
+ return Msg->getInstanceReceiver();
+ }
+
const ObjCInterfaceDecl *getReceiverInterface() const {
return Msg->getReceiverInterface();
}
@@ -359,11 +370,6 @@ public:
return Msg->getReceiverRange();
}
- // FIXME: Remove this once everything is converted to use ObjCMethodCall.
- virtual operator ObjCMessage() const {
- return ObjCMessage(Msg);
- }
-
static bool classof(const CallEvent *CA) {
return CA->getKind() >= CE_BEG_OBJC_CALLS &&
CA->getKind() <= CE_END_OBJC_CALLS;
@@ -389,20 +395,23 @@ public:
/// Example: obj.prop += 1;
class ObjCPropertyAccess : public ObjCMethodCall {
const ObjCPropertyRefExpr *PropE;
+ SourceRange EntireRange;
public:
- ObjCPropertyAccess(const ObjCPropertyRefExpr *pe, const ObjCMessageExpr *Msg,
- const ProgramStateRef St, const LocationContext *LCtx)
- : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess), PropE(pe) {}
+ ObjCPropertyAccess(const ObjCPropertyRefExpr *pe, SourceRange range,
+ const ObjCMessageExpr *Msg, const ProgramStateRef St,
+ const LocationContext *LCtx)
+ : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess), PropE(pe),
+ EntireRange(range)
+ {}
/// \brief Returns true if this property access is calling the setter method.
bool isSetter() const {
return getNumArgs() > 0;
}
- // FIXME: Remove this once everything is converted to use ObjCMethodCall.
- operator ObjCMessage() const {
- return ObjCMessage(getOriginExpr(), PropE, isSetter());
+ SourceRange getSourceRange() const {
+ return EntireRange;
}
static bool classof(const CallEvent *CA) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
deleted file mode 100644
index f64326d2c6..0000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ /dev/null
@@ -1,163 +0,0 @@
-//===- 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 ObjCMessageExpr *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();
- }
-};
-
-}
-}
-
-#endif
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index c75c86faf4..1d0c4b336b 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -17,10 +17,10 @@
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -46,10 +46,10 @@ public:
// Utility functions.
//===----------------------------------------------------------------------===//
-static const char* GetReceiverNameType(const ObjCMessage &msg) {
+static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
- return ID->getIdentifier()->getNameStart();
- return 0;
+ return ID->getIdentifier()->getName();
+ return StringRef();
}
enum FoundationClass {
@@ -95,15 +95,15 @@ namespace {
mutable OwningPtr<APIMisuse> BT;
void WarnNilArg(CheckerContext &C,
- const ObjCMessage &msg, unsigned Arg) const;
+ const ObjCMethodCall &msg, unsigned Arg) const;
public:
- void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
};
}
void NilArgChecker::WarnNilArg(CheckerContext &C,
- const ObjCMessage &msg,
+ const ObjCMethodCall &msg,
unsigned int Arg) const
{
if (!BT)
@@ -112,7 +112,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
if (ExplodedNode *N = C.generateSink()) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
- os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
+ os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
<< msg.getSelector().getAsString() << "' cannot be nil";
BugReport *R = new BugReport(*BT, os.str(), N);
@@ -121,7 +121,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
}
}
-void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
+void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
if (!ID)
@@ -151,7 +151,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(msg.getArgSVal(0, C.getLocationContext(), C.getState())))
+ if (isNil(msg.getArgSVal(0)))
WarnNilArg(C, msg, 0);
}
}
@@ -455,11 +455,11 @@ class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
mutable OwningPtr<BugType> BT;
public:
- void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
};
}
-void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
+void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
if (!BT) {
@@ -511,18 +511,18 @@ class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
mutable Selector initWithObjectsAndKeysS;
mutable OwningPtr<BugType> BT;
- bool isVariadicMessage(const ObjCMessage &msg) const;
+ bool isVariadicMessage(const ObjCMethodCall &msg) const;
public:
- void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
};
}
/// isVariadicMessage - Returns whether the given message is a variadic message,
/// where all arguments must be Objective-C types.
bool
-VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
- const ObjCMethodDecl *MD = msg.getMethodDecl();
+VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
+ const ObjCMethodDecl *MD = msg.getDecl();
if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
return false;
@@ -566,7 +566,7 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
}
}
-void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
+void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
if (!BT) {
BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
@@ -602,7 +602,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
ProgramStateRef state = C.getState();
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
- QualType ArgTy = msg.getArgType(I);
+ QualType ArgTy = msg.getArgExpr(I)->getType();
if (ArgTy->isObjCObjectPointerType())
continue;
@@ -611,8 +611,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
continue;
// Ignore pointer constants.
- if (isa<loc::ConcreteInt>(msg.getArgSVal(I, C.getLocationContext(),
- state)))
+ if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
continue;
// Ignore pointer types annotated with 'NSObject' attribute.
@@ -624,9 +623,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
continue;
// Generate only one error node to use for all bug reports.
- if (!errorNode.hasValue()) {
+ if (!errorNode.hasValue())
errorNode = C.addTransition();
- }
if (!errorNode.getValue())
continue;
@@ -634,17 +632,18 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
- if (const char *TypeName = GetReceiverNameType(msg))
+ StringRef TypeName = GetReceiverInterfaceName(msg);
+ if (!TypeName.empty())
os << "Argument to '" << TypeName << "' method '";
else
os << "Argument to method '";
os << msg.getSelector().getAsString()
- << "' should be an Objective-C pointer type, not '"
- << ArgTy.getAsString() << "'";
+ << "' should be an Objective-C pointer type, not '";
+ ArgTy.print(os, C.getLangOpts());
+ os << "'";
- BugReport *R = new BugReport(*BT, os.str(),
- errorNode.getValue());
+ BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
R->addRange(msg.getArgSourceRange(I));
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 30be60c9a6..083f21ea3f 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -17,7 +17,6 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
@@ -39,7 +38,7 @@ class CallAndMessageChecker
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
private:
static void PreVisitProcessArgs(CheckerContext &C, const CallEvent &Call,
@@ -51,12 +50,12 @@ private:
OwningPtr<BugType> &BT);
static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
- void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
+ void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
ExplodedNode *N) const;
void HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
- ObjCMessage msg) const;
+ const ObjCMethodCall &msg) const;
static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
if (!BT)
@@ -248,65 +247,61 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
}
}
-void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
+void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
+ SVal recVal = msg.getReceiverSVal();
+ if (recVal.isUndef()) {
+ if (ExplodedNode *N = C.generateSink()) {
+ BugType *BT = 0;
+ if (isa<ObjCPropertyAccess>(msg)) {
+ if (!BT_objc_prop_undef)
+ BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
+ "uninitialized object pointer"));
+ BT = BT_objc_prop_undef.get();
+ } else {
+ if (!BT_msg_undef)
+ BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
+ "is an uninitialized value"));
+ BT = BT_msg_undef.get();
+ }
+ BugReport *R = new BugReport(*BT, BT->getName(), N);
+ R->addRange(msg.getReceiverSourceRange());
- ProgramStateRef state = C.getState();
- const LocationContext *LCtx = C.getLocationContext();
-
- // FIXME: Handle 'super'?
- if (const Expr *receiver = msg.getInstanceReceiver()) {
- SVal recVal = state->getSVal(receiver, LCtx);
- if (recVal.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- BugType *BT = 0;
- if (msg.isPureMessageExpr()) {
- if (!BT_msg_undef)
- BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
- "is an uninitialized value"));
- BT = BT_msg_undef.get();
- }
- else {
- if (!BT_objc_prop_undef)
- BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
- "uninitialized object pointer"));
- BT = BT_objc_prop_undef.get();
- }
- BugReport *R =
- new BugReport(*BT, BT->getName(), N);
- R->addRange(receiver->getSourceRange());
+ // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
+ if (const Expr *ReceiverE = msg.getInstanceReceiverExpr())
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- receiver,
+ ReceiverE,
R));
- C.EmitReport(R);
- }
+ C.EmitReport(R);
+ }
+ return;
+ } else {
+ // Bifurcate the state into nil and non-nil ones.
+ DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+
+ ProgramStateRef state = C.getState();
+ ProgramStateRef notNilState, nilState;
+ llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+
+ // Handle receiver must be nil.
+ if (nilState && !notNilState) {
+ HandleNilReceiver(C, state, msg);
return;
- } else {
- // Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
-
- ProgramStateRef notNilState, nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
-
- // Handle receiver must be nil.
- if (nilState && !notNilState) {
- HandleNilReceiver(C, state, msg);
- return;
- }
}
}
- const char *bugDesc = msg.isPropertySetter() ?
- "Argument for property setter is an uninitialized value"
- : "Argument in message expression is an uninitialized value";
+ const char *bugDesc = "Argument in message expression is an "
+ "uninitialized value";
+ if (const ObjCPropertyAccess *Prop = dyn_cast<ObjCPropertyAccess>(&msg))
+ if (Prop->isSetter())
+ bugDesc = "Argument for property setter is an uninitialized value";
+
// Check for any arguments that are uninitialized/undefined.
- // FIXME: ObjCMessage is set to be removed soon.
- PreVisitProcessArgs(C, ObjCMessageSend(msg.getMessageExpr(), state, LCtx),
- bugDesc, BT_msg_arg);
+ PreVisitProcessArgs(C, msg, bugDesc, BT_msg_arg);
}
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
- const ObjCMessage &msg,
+ const ObjCMethodCall &msg,
ExplodedNode *N) const {
if (!BT_msg_ret)
@@ -317,11 +312,13 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << msg.getSelector().getAsString()
- << "' is nil and returns a value of type '"
- << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
+ << "' is nil and returns a value of type '";
+ msg.getResultType().print(os, C.getLangOpts());
+ os << "' that will be garbage";
BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
- if (const Expr *receiver = msg.getInstanceReceiver()) {
+ // FIXME: This won't track "self" in messages to super.
+ if (const Expr *receiver = msg.getInstanceReceiverExpr()) {
report->addRange(receiver->getSourceRange());
report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
receiver,
@@ -338,25 +335,25 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
- ObjCMessage msg) const {
+ const ObjCMethodCall &Msg) const {
ASTContext &Ctx = C.getASTContext();
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
- QualType RetTy = msg.getType(Ctx);
+ QualType RetTy = Msg.getResultType();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
const LocationContext *LCtx = C.getLocationContext();
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
- SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
+ SVal V = C.getSValBuilder().makeZeroVal(RetTy);
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
return;
}
// Other cases: check if sizeof(return type) > sizeof(void*)
if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
- .isConsumedExpr(msg.getMessageExpr())) {
+ .isConsumedExpr(Msg.getOriginExpr())) {
// Compute: sizeof(void *) and sizeof(return type)
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
@@ -369,7 +366,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
Ctx.LongLongTy == CanRetTy ||
Ctx.UnsignedLongLongTy == CanRetTy))) {
if (ExplodedNode *N = C.generateSink(state))
- emitNilReceiverBug(C, msg, N);
+ emitNilReceiverBug(C, Msg, N);
return;
}
@@ -386,8 +383,8 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// it most likely isn't nil. We should assume the semantics
// of this case unless we have *a lot* more knowledge.
//
- SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
+ SVal V = C.getSValBuilder().makeZeroVal(RetTy);
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index 61582d028a..751b8f4c89 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -76,10 +76,10 @@ public:
void checkPostStmt(const CallExpr *DS, CheckerContext &C) const;
/// \brief Pre-visit the Objective C messages.
- void checkPreObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const {}
+ void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {}
/// \brief Post-visit the Objective C messages.
- void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const {}
+ void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {}
/// \brief Pre-visit of the condition statement of a branch (such as IfStmt).
void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const {}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 2c960921a4..41cd80e01e 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -124,7 +124,7 @@ public:
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkPreObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
+ void checkPreObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void checkEndPath(CheckerContext &C) const;
@@ -491,29 +491,21 @@ static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
return false;
}
-void MallocChecker::checkPreObjCMessage(const ObjCMessage &Msg,
+void MallocChecker::checkPreObjCMessage(const ObjCMethodCall &Call,
CheckerContext &C) const {
- const ObjCMethodDecl *MD = Msg.getMethodDecl();
- if (!MD)
- return;
-
- // FIXME: ObjCMessage is going away soon.
- ObjCMessageSend Call(Msg.getMessageExpr(), C.getState(),
- C.getLocationContext());
- Selector S = Msg.getSelector();
-
// If the first selector is dataWithBytesNoCopy, assume that the memory will
// be released with 'free' by the new object.
// Ex: [NSData dataWithBytesNoCopy:bytes length:10];
// Unless 'freeWhenDone' param set to 0.
// TODO: Check that the memory was allocated with malloc.
+ Selector S = Call.getSelector();
if ((S.getNameForSlot(0) == "dataWithBytesNoCopy" ||
S.getNameForSlot(0) == "initWithBytesNoCopy" ||
S.getNameForSlot(0) == "initWithCharactersNoCopy") &&
!isFreeWhenDoneSetToZero(Call)){
unsigned int argIdx = 0;
C.addTransition(FreeMemAux(C, Call.getArgExpr(argIdx),
- Msg.getMessageExpr(), C.getState(), true));
+ Call.getOriginExpr(), C.getState(), true));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/NSAu