forked from OSchip/llvm-project
[analyzer][CallAndMessage] Add checker options for each bug type
iAs listed in the summary D77846, we have 5 different categories of bugs we're checking for in CallAndMessage. I think the documentation placed in the code explains my thought process behind my decisions quite well. A non-obvious change I had here is removing the entry for CallAndMessageUnInitRefArg. In fact, I removed the CheckerNameRef typed field back in D77845 (it was dead code), so that checker didn't really exist in any meaningful way anyways. Differential Revision: https://reviews.llvm.org/D77866
This commit is contained in:
parent
361e4f14e3
commit
1c8f999e0b
|
@ -122,14 +122,70 @@ def FuchsiaAlpha : Package<"fuchsia">, ParentPackage<Alpha>;
|
|||
|
||||
let ParentPackage = Core in {
|
||||
|
||||
def DereferenceChecker : Checker<"NullDereference">,
|
||||
HelpText<"Check for dereferences of null pointers">,
|
||||
def CallAndMessageModeling : Checker<"CallAndMessageModeling">,
|
||||
HelpText<"Responsible for essential modeling and assumptions after a "
|
||||
"function/method call. For instance, if we can't reason about the "
|
||||
"nullability of the implicit this parameter after a method call, "
|
||||
"this checker conservatively assumes it to be non-null">,
|
||||
Documentation<HasDocumentation>;
|
||||
|
||||
def CallAndMessageChecker : Checker<"CallAndMessage">,
|
||||
HelpText<"Check for logical errors for function calls and Objective-C "
|
||||
"message expressions (e.g., uninitialized arguments, null function "
|
||||
"pointers)">,
|
||||
CheckerOptions<[
|
||||
CmdLineOption<Boolean,
|
||||
"FunctionPointer",
|
||||
"Check whether a called function pointer is null or "
|
||||
"undefined",
|
||||
"true",
|
||||
Released>,
|
||||
CmdLineOption<Boolean,
|
||||
"ParameterCount",
|
||||
"Check whether a function was called with the appropriate "
|
||||
"number of arguments",
|
||||
"true",
|
||||
Released>,
|
||||
CmdLineOption<Boolean,
|
||||
"CXXThisMethodCall",
|
||||
"Check whether the implicit this parameter is null or "
|
||||
"undefined upon a method call",
|
||||
"true",
|
||||
Released>,
|
||||
CmdLineOption<Boolean,
|
||||
"CXXDeallocationArg",
|
||||
"Check whether the argument of operator delete is undefined",
|
||||
"true",
|
||||
Released>,
|
||||
CmdLineOption<Boolean,
|
||||
"ArgInitializedness",
|
||||
"Check whether any of the pass-by-value parameters is "
|
||||
"undefined",
|
||||
"true",
|
||||
Released>,
|
||||
CmdLineOption<Boolean,
|
||||
"ArgPointeeInitializedness",
|
||||
"Check whether the pointee of a pass-by-reference or "
|
||||
"pass-by-pointer is undefined",
|
||||
"false",
|
||||
InAlpha>,
|
||||
CmdLineOption<Boolean,
|
||||
"NilReceiver",
|
||||
"Check whether the reciever in the message expression is nil",
|
||||
"true",
|
||||
Released>,
|
||||
CmdLineOption<Boolean,
|
||||
"UndefReceiver",
|
||||
"Check whether the reciever in the message expression is "
|
||||
"undefined",
|
||||
"true",
|
||||
Released>,
|
||||
]>,
|
||||
Documentation<HasDocumentation>,
|
||||
Dependencies<[CallAndMessageModeling]>;
|
||||
|
||||
def DereferenceChecker : Checker<"NullDereference">,
|
||||
HelpText<"Check for dereferences of null pointers">,
|
||||
Documentation<HasDocumentation>;
|
||||
|
||||
def NonNullParamChecker : Checker<"NonNullParamChecker">,
|
||||
|
@ -211,13 +267,6 @@ def SizeofPointerChecker : Checker<"SizeofPtr">,
|
|||
HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
|
||||
Documentation<HasAlphaDocumentation>;
|
||||
|
||||
def CallAndMessageUnInitRefArg : Checker<"CallAndMessageUnInitRefArg">,
|
||||
HelpText<"Check for logical errors for function calls and Objective-C "
|
||||
"message expressions (e.g., uninitialized arguments, null function "
|
||||
"pointers, and pointer to undefined variables)">,
|
||||
Dependencies<[CallAndMessageChecker]>,
|
||||
Documentation<HasAlphaDocumentation>;
|
||||
|
||||
def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">,
|
||||
HelpText<"Check for division by variable that is later compared against 0. "
|
||||
"Either the comparison is useless or there is division by zero.">,
|
||||
|
@ -295,7 +344,7 @@ let ParentPackage = APIModeling in {
|
|||
|
||||
def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
|
||||
HelpText<"Improve modeling of the C standard library functions">,
|
||||
Dependencies<[NonNullParamChecker, CallAndMessageChecker]>,
|
||||
Dependencies<[NonNullParamChecker, CallAndMessageModeling]>,
|
||||
CheckerOptions<[
|
||||
CmdLineOption<Boolean,
|
||||
"DisplayLoadedSummaries",
|
||||
|
|
|
@ -175,8 +175,7 @@ public:
|
|||
/// @param Pred The transition will be generated from the specified Pred node
|
||||
/// to the newly generated node.
|
||||
/// @param Tag The tag to uniquely identify the creation site.
|
||||
ExplodedNode *addTransition(ProgramStateRef State,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNode *addTransition(ProgramStateRef State, ExplodedNode *Pred,
|
||||
const ProgramPointTag *Tag = nullptr) {
|
||||
return addTransitionImpl(State, false, Pred, Tag);
|
||||
}
|
||||
|
@ -189,6 +188,14 @@ public:
|
|||
return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
|
||||
}
|
||||
|
||||
/// Add a sink node to the current path of execution, halting analysis.
|
||||
void addSink(ProgramStateRef State = nullptr,
|
||||
const ProgramPointTag *Tag = nullptr) {
|
||||
if (!State)
|
||||
State = getState();
|
||||
addTransition(State, generateSink(State, getPredecessor()));
|
||||
}
|
||||
|
||||
/// Generate a transition to a node that will be used to report
|
||||
/// an error. This node will be a sink. That is, it will stop exploration of
|
||||
/// the given path.
|
||||
|
|
|
@ -47,9 +47,36 @@ class CallAndMessageChecker
|
|||
mutable std::unique_ptr<BugType> BT_call_few_args;
|
||||
|
||||
public:
|
||||
enum CheckKind { CK_CallAndMessageUnInitRefArg, CK_NumCheckKinds };
|
||||
// These correspond with the checker options. Looking at other checkers such
|
||||
// as MallocChecker and CStringChecker, this is similar as to how they pull
|
||||
// off having a modeling class, but emitting diagnostics under a smaller
|
||||
// checker's name that can be safely disabled without disturbing the
|
||||
// underlaying modeling engine.
|
||||
// The reason behind having *checker options* rather then actual *checkers*
|
||||
// here is that CallAndMessage is among the oldest checkers out there, and can
|
||||
// be responsible for the majority of the reports on any given project. This
|
||||
// is obviously not ideal, but changing checker name has the consequence of
|
||||
// changing the issue hashes associated with the reports, and databases
|
||||
// relying on this (CodeChecker, for instance) would suffer greatly.
|
||||
// If we ever end up making changes to the issue hash generation algorithm, or
|
||||
// the warning messages here, we should totally jump on the opportunity to
|
||||
// convert these to actual checkers.
|
||||
enum CheckKind {
|
||||
CK_FunctionPointer,
|
||||
CK_ParameterCount,
|
||||
CK_CXXThisMethodCall,
|
||||
CK_CXXDeallocationArg,
|
||||
CK_ArgInitializedness,
|
||||
CK_ArgPointeeInitializedness,
|
||||
CK_NilReceiver,
|
||||
CK_UndefReceiver,
|
||||
CK_NumCheckKinds
|
||||
};
|
||||
|
||||
DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
||||
// The original core.CallAndMessage checker name. This should rather be an
|
||||
// array, as seen in MallocChecker and CStringChecker.
|
||||
CheckerNameRef OriginalName;
|
||||
|
||||
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
|
||||
|
||||
|
@ -96,7 +123,7 @@ private:
|
|||
|
||||
void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
|
||||
if (!BT)
|
||||
BT.reset(new BuiltinBug(this, desc));
|
||||
BT.reset(new BuiltinBug(OriginalName, desc));
|
||||
}
|
||||
bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
|
||||
SourceRange ArgRange, const Expr *ArgEx,
|
||||
|
@ -161,7 +188,10 @@ bool CallAndMessageChecker::uninitRefOrPointer(
|
|||
CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
|
||||
std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
|
||||
int ArgumentNumber) const {
|
||||
if (!ChecksEnabled[CK_CallAndMessageUnInitRefArg])
|
||||
|
||||
// The pointee being uninitialized is a sign of code smell, not a bug, no need
|
||||
// to sink here.
|
||||
if (!ChecksEnabled[CK_ArgPointeeInitializedness])
|
||||
return false;
|
||||
|
||||
// No parameter declaration available, i.e. variadic function argument.
|
||||
|
@ -263,6 +293,10 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
|
|||
return true;
|
||||
|
||||
if (V.isUndef()) {
|
||||
if (!ChecksEnabled[CK_ArgInitializedness]) {
|
||||
C.addSink();
|
||||
return true;
|
||||
}
|
||||
if (ExplodedNode *N = C.generateErrorNode()) {
|
||||
LazyInit_BT(BD, BT);
|
||||
// Generate a report for this bug.
|
||||
|
@ -289,6 +323,10 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
|
|||
D->getStore());
|
||||
|
||||
if (F.Find(D->getRegion())) {
|
||||
if (!ChecksEnabled[CK_ArgInitializedness]) {
|
||||
C.addSink();
|
||||
return true;
|
||||
}
|
||||
if (ExplodedNode *N = C.generateErrorNode()) {
|
||||
LazyInit_BT(BD, BT);
|
||||
SmallString<512> Str;
|
||||
|
@ -336,9 +374,14 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
|
|||
SVal L = State->getSVal(Callee, LCtx);
|
||||
|
||||
if (L.isUndef()) {
|
||||
if (!ChecksEnabled[CK_FunctionPointer]) {
|
||||
C.addSink(State);
|
||||
return nullptr;
|
||||
}
|
||||
if (!BT_call_undef)
|
||||
BT_call_undef.reset(new BuiltinBug(
|
||||
this, "Called function pointer is an uninitialized pointer value"));
|
||||
OriginalName,
|
||||
"Called function pointer is an uninitialized pointer value"));
|
||||
emitBadCall(BT_call_undef.get(), C, Callee);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -347,9 +390,13 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
|
|||
std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
|
||||
|
||||
if (StNull && !StNonNull) {
|
||||
if (!ChecksEnabled[CK_FunctionPointer]) {
|
||||
C.addSink(StNull);
|
||||
return nullptr;
|
||||
}
|
||||
if (!BT_call_null)
|
||||
BT_call_null.reset(new BuiltinBug(
|
||||
this, "Called function pointer is null (null dereference)"));
|
||||
OriginalName, "Called function pointer is null (null dereference)"));
|
||||
emitBadCall(BT_call_null.get(), C, Callee);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -366,6 +413,11 @@ ProgramStateRef CallAndMessageChecker::checkParameterCount(
|
|||
if (Call.getNumArgs() >= Params)
|
||||
return State;
|
||||
|
||||
if (!ChecksEnabled[CK_ParameterCount]) {
|
||||
C.addSink(State);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExplodedNode *N = C.generateErrorNode();
|
||||
if (!N)
|
||||
return nullptr;
|
||||
|
@ -393,9 +445,13 @@ ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
|
|||
|
||||
SVal V = CC->getCXXThisVal();
|
||||
if (V.isUndef()) {
|
||||
if (!ChecksEnabled[CK_CXXThisMethodCall]) {
|
||||
C.addSink(State);
|
||||
return nullptr;
|
||||
}
|
||||
if (!BT_cxx_call_undef)
|
||||
BT_cxx_call_undef.reset(
|
||||
new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
|
||||
BT_cxx_call_undef.reset(new BuiltinBug(
|
||||
OriginalName, "Called C++ object pointer is uninitialized"));
|
||||
emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -404,9 +460,13 @@ ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
|
|||
std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
|
||||
|
||||
if (StNull && !StNonNull) {
|
||||
if (!ChecksEnabled[CK_CXXThisMethodCall]) {
|
||||
C.addSink(StNull);
|
||||
return nullptr;
|
||||
}
|
||||
if (!BT_cxx_call_null)
|
||||
BT_cxx_call_null.reset(
|
||||
new BuiltinBug(this, "Called C++ object pointer is null"));
|
||||
new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
|
||||
emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -424,13 +484,18 @@ CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
|
|||
if (!Arg.isUndef())
|
||||
return State;
|
||||
|
||||
if (!ChecksEnabled[CK_CXXDeallocationArg]) {
|
||||
C.addSink(State);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StringRef Desc;
|
||||
ExplodedNode *N = C.generateErrorNode();
|
||||
if (!N)
|
||||
return nullptr;
|
||||
if (!BT_cxx_delete_undef)
|
||||
BT_cxx_delete_undef.reset(
|
||||
new BuiltinBug(this, "Uninitialized argument value"));
|
||||
new BuiltinBug(OriginalName, "Uninitialized argument value"));
|
||||
if (DE->isArrayFormAsWritten())
|
||||
Desc = "Argument to 'delete[]' is uninitialized";
|
||||
else
|
||||
|
@ -511,12 +576,16 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
CheckerContext &C) const {
|
||||
SVal recVal = msg.getReceiverSVal();
|
||||
if (recVal.isUndef()) {
|
||||
if (!ChecksEnabled[CK_UndefReceiver]) {
|
||||
C.addSink();
|
||||
return;
|
||||
}
|
||||
if (ExplodedNode *N = C.generateErrorNode()) {
|
||||
BugType *BT = nullptr;
|
||||
switch (msg.getMessageKind()) {
|
||||
case OCM_Message:
|
||||
if (!BT_msg_undef)
|
||||
BT_msg_undef.reset(new BuiltinBug(this,
|
||||
BT_msg_undef.reset(new BuiltinBug(OriginalName,
|
||||
"Receiver in message expression "
|
||||
"is an uninitialized value"));
|
||||
BT = BT_msg_undef.get();
|
||||
|
@ -524,13 +593,15 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
case OCM_PropertyAccess:
|
||||
if (!BT_objc_prop_undef)
|
||||
BT_objc_prop_undef.reset(new BuiltinBug(
|
||||
this, "Property access on an uninitialized object pointer"));
|
||||
OriginalName,
|
||||
"Property access on an uninitialized object pointer"));
|
||||
BT = BT_objc_prop_undef.get();
|
||||
break;
|
||||
case OCM_Subscript:
|
||||
if (!BT_objc_subscript_undef)
|
||||
BT_objc_subscript_undef.reset(new BuiltinBug(
|
||||
this, "Subscript access on an uninitialized object pointer"));
|
||||
OriginalName,
|
||||
"Subscript access on an uninitialized object pointer"));
|
||||
BT = BT_objc_subscript_undef.get();
|
||||
break;
|
||||
}
|
||||
|
@ -557,10 +628,14 @@ void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
|
|||
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
|
||||
const ObjCMethodCall &msg,
|
||||
ExplodedNode *N) const {
|
||||
if (!ChecksEnabled[CK_NilReceiver]) {
|
||||
C.addSink();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BT_msg_ret)
|
||||
BT_msg_ret.reset(
|
||||
new BuiltinBug(this, "Receiver in message expression is 'nil'"));
|
||||
BT_msg_ret.reset(new BuiltinBug(OriginalName,
|
||||
"Receiver in message expression is 'nil'"));
|
||||
|
||||
const ObjCMessageExpr *ME = msg.getOriginExpr();
|
||||
|
||||
|
@ -655,21 +730,34 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
|
|||
C.addTransition(state);
|
||||
}
|
||||
|
||||
void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
|
||||
void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
|
||||
mgr.registerChecker<CallAndMessageChecker>();
|
||||
}
|
||||
|
||||
bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
|
||||
CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
|
||||
|
||||
checker->OriginalName = mgr.getCurrentCheckerName();
|
||||
|
||||
#define QUERY_CHECKER_OPTION(OPTION) \
|
||||
checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
|
||||
mgr.getAnalyzerOptions().getCheckerBooleanOption( \
|
||||
mgr.getCurrentCheckerName(), #OPTION);
|
||||
|
||||
QUERY_CHECKER_OPTION(FunctionPointer)
|
||||
QUERY_CHECKER_OPTION(ParameterCount)
|
||||
QUERY_CHECKER_OPTION(CXXThisMethodCall)
|
||||
QUERY_CHECKER_OPTION(CXXDeallocationArg)
|
||||
QUERY_CHECKER_OPTION(ArgInitializedness)
|
||||
QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
|
||||
QUERY_CHECKER_OPTION(NilReceiver)
|
||||
QUERY_CHECKER_OPTION(UndefReceiver)
|
||||
}
|
||||
|
||||
bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#define REGISTER_CHECKER(name) \
|
||||
void ento::register##name(CheckerManager &mgr) { \
|
||||
CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>(); \
|
||||
checker->ChecksEnabled[CallAndMessageChecker::CK_##name] = true; \
|
||||
\
|
||||
} \
|
||||
\
|
||||
bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
|
||||
|
||||
REGISTER_CHECKER(CallAndMessageUnInitRefArg)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.core.CallAndMessageUnInitRefArg %s -verify
|
||||
// RUN: %clang_analyze_cc1 %s -verify \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
|
||||
|
||||
void f(const int *end);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ConfigDumper > %t 2>&1
|
||||
// RUN: FileCheck --input-file=%t %s --match-full-lines
|
||||
|
||||
// CHECK: [config]
|
||||
// CHECK: [config]
|
||||
// CHECK-NEXT: add-pop-up-notes = true
|
||||
// CHECK-NEXT: aggressive-binary-operation-simplification = false
|
||||
// CHECK-NEXT: alpha.clone.CloneChecker:IgnoredFilesPattern = ""
|
||||
|
@ -30,6 +30,14 @@
|
|||
// CHECK-NEXT: cfg-rich-constructors = true
|
||||
// CHECK-NEXT: cfg-scopes = false
|
||||
// CHECK-NEXT: cfg-temporary-dtors = true
|
||||
// CHECK-NEXT: core.CallAndMessage:ArgInitializedness = true
|
||||
// CHECK-NEXT: core.CallAndMessage:ArgPointeeInitializedness = false
|
||||
// CHECK-NEXT: core.CallAndMessage:CXXDeallocationArg = true
|
||||
// CHECK-NEXT: core.CallAndMessage:CXXThisMethodCall = true
|
||||
// CHECK-NEXT: core.CallAndMessage:FunctionPointer = true
|
||||
// CHECK-NEXT: core.CallAndMessage:NilReceiver = true
|
||||
// CHECK-NEXT: core.CallAndMessage:ParameterCount = true
|
||||
// CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
|
||||
// CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
|
||||
// CHECK-NEXT: crosscheck-with-z3 = false
|
||||
// CHECK-NEXT: ctu-dir = ""
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
// CHECK: OVERVIEW: Clang Static Analyzer Enabled Checkers List
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: core.NonNullParamChecker
|
||||
// CHECK-NEXT: core.CallAndMessage
|
||||
// CHECK-NEXT: core.CallAndMessageModeling
|
||||
// CHECK-NEXT: apiModeling.StdCLibraryFunctions
|
||||
// CHECK-NEXT: apiModeling.TrustNonnull
|
||||
// CHECK-NEXT: apiModeling.llvm.CastValue
|
||||
// CHECK-NEXT: apiModeling.llvm.ReturnValue
|
||||
// CHECK-NEXT: core.CallAndMessage
|
||||
// CHECK-NEXT: core.DivideZero
|
||||
// CHECK-NEXT: core.DynamicTypePropagation
|
||||
// CHECK-NEXT: core.NonnilStringConstants
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %clang_analyze_cc1 %s -verify \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true \
|
||||
// RUN: -analyzer-output=plist -o %t.plist
|
||||
// RUN: cat %t.plist | FileCheck %s
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s -verify=no-pointee \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false
|
||||
|
||||
// no-pointee-no-diagnostics
|
||||
|
||||
void doStuff_pointerToConstInt(const int *u){};
|
||||
void pointee_uninit() {
|
||||
int i;
|
||||
int *p = &i;
|
||||
doStuff_pointerToConstInt(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:ArgPointeeInitializedness from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>97a74322d64dca40aa57303842c745a1</string>
|
|
@ -0,0 +1,172 @@
|
|||
// RUN: %clang_analyze_cc1 %s -verify=fn-pointer \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=true \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=false
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s -verify=param-count \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=true \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=false
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s -verify=method \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=true \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=false
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s -verify=delete \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=true \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=false
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s -verify=arg-init \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=true \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=false
|
||||
|
||||
// Testing for ArgPointeeInitializedness is in call-and-message.c.
|
||||
|
||||
// RUN: %clang_analyze_cc1 %s \
|
||||
// RUN: -verify=fn-pointer,param-count,method,delete,arg-init \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-output=plist -o %t.plist
|
||||
// RUN: cat %t.plist | FileCheck %s
|
||||
|
||||
namespace function_pointer {
|
||||
using Fn = void (*)();
|
||||
|
||||
void uninit() {
|
||||
Fn f;
|
||||
f(); // fn-pointer-warning{{Called function pointer is an uninitialized pointer value [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
void null() {
|
||||
Fn f = nullptr;
|
||||
f(); // fn-pointer-warning{{Called function pointer is null (null dereference) [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:FunctionPointer from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>eb2083c01775eef452afa75728dd4d8f</string>
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>407c50d9bedd8db28bf34f9411308100</string>
|
||||
|
||||
} // namespace function_pointer
|
||||
|
||||
namespace wrong_param_count {
|
||||
using FnOneParam = void (*)(int);
|
||||
using FnTwoParam = void (*)(int, int);
|
||||
|
||||
void f(int, int) {}
|
||||
|
||||
void wrong_cast() {
|
||||
FnTwoParam f1 = f;
|
||||
FnOneParam f2 = reinterpret_cast<FnOneParam>(f1);
|
||||
f2(5); // param-count-warning{{Function taking 2 arguments is called with fewer (1) [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:ParameterCount from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>9ff0e9b728422017945c9d5a673de223</string>
|
||||
} // namespace wrong_param_count
|
||||
|
||||
namespace method_call {
|
||||
struct A {
|
||||
void m();
|
||||
};
|
||||
|
||||
void uninit() {
|
||||
A *a;
|
||||
a->m(); // method-warning{{Called C++ object pointer is uninitialized [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:CXXThisMethodCall from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>7bc35c70465837948a3f5018f27b21cd</string>
|
||||
|
||||
void null() {
|
||||
A *a = nullptr;
|
||||
a->m(); // method-warning{{Called C++ object pointer is null [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:CXXThisMethodCall from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>8ec260c9ef11d7c51fa872212df1163f</string>
|
||||
} // namespace method_call
|
||||
|
||||
namespace operator_delete {
|
||||
void f() {
|
||||
int *i;
|
||||
delete i; // delete-warning{{Argument to 'delete' is uninitialized [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:CXXDeallocationArg from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>a8ff99ebaa8746457d3e14af8ef7e75c</string>
|
||||
} // namespace operator_delete
|
||||
|
||||
namespace uninit_arg {
|
||||
template <class T>
|
||||
void consume(T);
|
||||
|
||||
void fundamental_uninit() {
|
||||
int i;
|
||||
consume(i); // arg-init-warning{{1st function call argument is an uninitialized value [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
struct A {
|
||||
int i;
|
||||
};
|
||||
|
||||
void record_uninit() {
|
||||
A a;
|
||||
consume(a); // arg-init-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'i') [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn
|
||||
// core.CallAndMessage:ArgInitializedness from a checker option into a
|
||||
// checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>a46bb5c1ee44d4611ffeb13f7f499605</string>
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>e0e0d30ea5a7b2e3a71e1931fa0768a5</string>
|
||||
} // namespace uninit_arg
|
|
@ -0,0 +1,134 @@
|
|||
// RUN: %clang_analyze_cc1 %s -verify \
|
||||
// RUN: -Wno-objc-root-class \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=true \
|
||||
// RUN: -analyzer-output=plist -o %t.plist
|
||||
// RUN: cat %t.plist | FileCheck %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The following code is reduced using delta-debugging from
|
||||
// Foundation.h (Mac OS X).
|
||||
//
|
||||
// It includes the basic definitions for the test cases below.
|
||||
// Not directly including Foundation.h directly makes this test case
|
||||
// both svelte and portable to non-Mac platforms.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef unsigned int NSUInteger;
|
||||
typedef struct _NSZone NSZone;
|
||||
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
|
||||
@protocol NSObject
|
||||
- (BOOL)isEqual:(id)object;
|
||||
@end
|
||||
@protocol NSCopying
|
||||
- (id)copyWithZone:(NSZone *)zone;
|
||||
@end
|
||||
@protocol NSMutableCopying
|
||||
- (id)mutableCopyWithZone:(NSZone *)zone;
|
||||
@end
|
||||
@protocol NSCoding
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder;
|
||||
@end
|
||||
@interface NSObject <NSObject> {
|
||||
}
|
||||
@end
|
||||
@class NSString, NSData;
|
||||
@class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
|
||||
typedef struct {
|
||||
} NSFastEnumerationState;
|
||||
@protocol NSFastEnumeration
|
||||
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
|
||||
@end
|
||||
@class NSData, NSIndexSet, NSString, NSURL;
|
||||
@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
|
||||
- (NSUInteger)count;
|
||||
@end
|
||||
@interface NSArray (NSArrayCreation)
|
||||
+ (id)array;
|
||||
- (NSUInteger)length;
|
||||
- (void)addObject:(id)object;
|
||||
@end
|
||||
extern NSString *const NSUndoManagerCheckpointNotification;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test cases.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
unsigned f1() {
|
||||
NSString *aString;
|
||||
return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn core.CallAndMessage:UndefReceiver from
|
||||
// a checker option into a checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>29873175e1cc0a98f7040057279925a0</string>
|
||||
|
||||
@interface RDar9241180
|
||||
@property(readwrite, assign) id x;
|
||||
- (id)testAnalyzer1:(int)y;
|
||||
@end
|
||||
|
||||
@implementation RDar9241180
|
||||
@synthesize x;
|
||||
- (id)testAnalyzer1:(int)y {
|
||||
RDar9241180 *o;
|
||||
if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer [core.CallAndMessage]}}
|
||||
return o;
|
||||
|
||||
// TODO: If this hash ever changes, turn core.CallAndMessage:UndefReceiver from
|
||||
// a checker option into a checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>00ddd30796a283de33e662da8449c796</string>
|
||||
|
||||
return o; // expected-warning {{Undefined or garbage value returned to caller [core.uninitialized.UndefReturn]}}
|
||||
}
|
||||
@end
|
||||
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>8d468e24df7d887f4182bf49f5dd8b71</string>
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef unsigned int NSUInteger;
|
||||
|
||||
@interface Subscriptable : NSObject
|
||||
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index;
|
||||
- (id)objectAtIndexedSubscript:(NSUInteger)index;
|
||||
|
||||
- (void)setObject:(id)obj forKeyedSubscript:(id)key;
|
||||
- (id)objectForKeyedSubscript:(id)key;
|
||||
@end
|
||||
|
||||
@interface Test : Subscriptable
|
||||
@end
|
||||
|
||||
@implementation Test
|
||||
|
||||
// <rdar://problem/9241180> for subscripting
|
||||
- (id)testUninitializedObject:(BOOL)keyed {
|
||||
Test *o;
|
||||
if (keyed) {
|
||||
if (o[self]) // expected-warning {{Subscript access on an uninitialized object pointer [core.CallAndMessage]}}
|
||||
return o; // no-warning (sink)
|
||||
} else {
|
||||
if (o[0]) // expected-warning {{Subscript access on an uninitialized object pointer [core.CallAndMessage]}}
|
||||
return o; // no-warning (sink)
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
// TODO: If this hash ever changes, turn core.CallAndMessage:UndefReceiver from
|
||||
// a checker option into a checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>8d943563d78377fc5dfcd4fdde904e5e</string>
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>9a2a9698763d62bed38d91fe5fb4aefd</string>
|
|
@ -0,0 +1,32 @@
|
|||
// RUN: %clang_analyze_cc1 %s -verify \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:FunctionPointer=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ParameterCount=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
|
||||
// RUN: -analyzer-config core.CallAndMessage:NilReceiver=true \
|
||||
// RUN: -analyzer-config core.CallAndMessage:UndefReceiver=false \
|
||||
// RUN: -analyzer-output=plist -o %t.plist
|
||||
// RUN: cat %t.plist | FileCheck %s
|
||||
|
||||
@interface Foo
|
||||
- (int &)ref;
|
||||
@end
|
||||
|
||||
Foo *getFoo() { return 0; }
|
||||
|
||||
void testNullPointerSuppression() {
|
||||
getFoo().ref = 1;
|
||||
}
|
||||
|
||||
void testPositiveNullReference() {
|
||||
Foo *x = 0;
|
||||
x.ref = 1; // expected-warning {{The receiver of message 'ref' is nil, which results in forming a null reference [core.CallAndMessage]}}
|
||||
}
|
||||
|
||||
// TODO: If this hash ever changes, turn core.CallAndMessage:NilReceiver from a
|
||||
// checker option into a checker, as described in the CallAndMessage comments!
|
||||
// CHECK: <key>issue_hash_content_of_line_in_context</key>
|
||||
// CHECK-SAME: <string>abe2e0574dd901094c511bae2f93f926</string>
|
|
@ -1,9 +1,10 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
|
||||
// RUN: %clang_analyze_cc1 %s -verify \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
|
||||
//
|
||||
// Just exercise the analyzer on code that has at one point caused issues
|
||||
// (i.e., no assertions or crashes).
|
||||
|
||||
|
||||
static void f1(const char *x, char *y) {
|
||||
while (*x != 0) {
|
||||
*y++ = *x++;
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -Wno-null-dereference %s
|
||||
|
||||
@interface Foo
|
||||
- (int &)ref;
|
||||
@end
|
||||
|
||||
Foo *getFoo() { return 0; }
|
||||
|
||||
void testNullPointerSuppression() {
|
||||
getFoo().ref = 1;
|
||||
}
|
||||
|
||||
void testPositiveNullReference() {
|
||||
Foo *x = 0;
|
||||
x.ref = 1; // expected-warning {{The receiver of message 'ref' is nil, which results in forming a null reference}}
|
||||
}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc,core,alpha.core.CallAndMessageUnInitRefArg,debug.ExprInspection -analyzer-output=text -verify %s
|
||||
// RUN: %clang_analyze_cc1 -analyzer-output=text -verify %s \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-checker=unix.Malloc \
|
||||
// RUN: -analyzer-checker=debug.ExprInspection \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
|
||||
|
||||
void clang_analyzer_warnIfReached();
|
||||
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -verify %s
|
||||
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -DTEST_INLINABLE_ALLOCATORS -verify %s
|
||||
// RUN: %clang_analyze_cc1 -analyzer-output=text -verify %s \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-checker=cplusplus.NewDelete \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
|
||||
|
||||
// RUN: %clang_analyze_cc1 -analyzer-output=text -verify %s \
|
||||
// RUN: -DTEST_INLINABLE_ALLOCATORS \
|
||||
// RUN: -analyzer-checker=core \
|
||||
// RUN: -analyzer-checker=cplusplus.NewDelete \
|
||||
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
|
||||
|
||||
// Passing uninitialized const data to unknown function
|
||||
|
||||
#include "Inputs/system-header-simulator-cxx.h"
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The following code is reduced using delta-debugging from
|
||||
// Foundation.h (Mac OS X).
|
||||
//
|
||||
// It includes the basic definitions for the test cases below.
|
||||
// Not directly including Foundation.h directly makes this test case
|
||||
// both svelte and portable to non-Mac platforms.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef unsigned int NSUInteger;
|
||||
typedef struct _NSZone NSZone;
|
||||
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
|
||||
@protocol NSObject - (BOOL)isEqual:(id)object; @end
|
||||
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
|
||||
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
|
||||
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
|
||||
@interface NSObject <NSObject> {} @end
|
||||
@class NSString, NSData;
|
||||
@class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
|
||||
typedef struct {} NSFastEnumerationState;
|
||||
@protocol NSFastEnumeration
|
||||
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
|
||||
@end
|
||||
@class NSData, NSIndexSet, NSString, NSURL;
|
||||
@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
|
||||
- (NSUInteger)count;
|
||||
@end
|
||||
@interface NSArray (NSArrayCreation)
|
||||
+ (id)array;
|
||||
- (NSUInteger)length;
|
||||
- (void)addObject:(id)object;
|
||||
@end
|
||||
extern NSString * const NSUndoManagerCheckpointNotification;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test cases.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
unsigned f1() {
|
||||
NSString *aString;
|
||||
return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value}}
|
||||
}
|
||||
|
||||
unsigned f2() {
|
||||
NSString *aString = 0;
|
||||
return [aString length]; // no-warning
|
||||
}
|
||||
|
||||
void f3() {
|
||||
NSMutableArray *aArray = [NSArray array];
|
||||
NSString *aString;
|
||||
[aArray addObject:aString]; // expected-warning {{1st argument in message expression is an uninitialized value}}
|
||||
}
|
Loading…
Reference in New Issue