forked from OSchip/llvm-project
static analyzer: add inlining support for directly called blocks.
llvm-svn: 157833
This commit is contained in:
parent
0bc272cf9a
commit
c3da376fbc
|
@ -38,6 +38,7 @@ class PseudoConstantAnalysis;
|
|||
class ImplicitParamDecl;
|
||||
class LocationContextManager;
|
||||
class StackFrameContext;
|
||||
class BlockInvocationContext;
|
||||
class AnalysisDeclContextManager;
|
||||
class LocationContext;
|
||||
|
||||
|
@ -162,6 +163,11 @@ public:
|
|||
const Stmt *S,
|
||||
const CFGBlock *Blk,
|
||||
unsigned Idx);
|
||||
|
||||
const BlockInvocationContext *
|
||||
getBlockInvocationContext(const LocationContext *parent,
|
||||
const BlockDecl *BD,
|
||||
const void *ContextData);
|
||||
|
||||
/// Return the specified analysis object, lazily running the analysis if
|
||||
/// necessary. Return NULL if the analysis could not run.
|
||||
|
@ -227,8 +233,6 @@ public:
|
|||
}
|
||||
|
||||
const StackFrameContext *getCurrentStackFrame() const;
|
||||
const StackFrameContext *
|
||||
getStackFrameForDeclContext(const DeclContext *DC) const;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
|
||||
|
||||
|
@ -307,27 +311,32 @@ public:
|
|||
};
|
||||
|
||||
class BlockInvocationContext : public LocationContext {
|
||||
// FIXME: Add back context-sensivity (we don't want libAnalysis to know
|
||||
// about MemRegion).
|
||||
const BlockDecl *BD;
|
||||
|
||||
// FIXME: Come up with a more type-safe way to model context-sensitivity.
|
||||
const void *ContextData;
|
||||
|
||||
friend class LocationContextManager;
|
||||
|
||||
BlockInvocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const BlockDecl *bd)
|
||||
: LocationContext(Block, ctx, parent), BD(bd) {}
|
||||
const BlockDecl *bd, const void *contextData)
|
||||
: LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {}
|
||||
|
||||
public:
|
||||
~BlockInvocationContext() {}
|
||||
|
||||
const BlockDecl *getBlockDecl() const { return BD; }
|
||||
|
||||
const void *getContextData() const { return ContextData; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const BlockDecl *bd) {
|
||||
const LocationContext *parent, const BlockDecl *bd,
|
||||
const void *contextData) {
|
||||
ProfileCommon(ID, Block, ctx, parent, bd);
|
||||
ID.AddPointer(contextData);
|
||||
}
|
||||
|
||||
static bool classof(const LocationContext *Ctx) {
|
||||
|
@ -348,6 +357,12 @@ public:
|
|||
const ScopeContext *getScope(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s);
|
||||
|
||||
const BlockInvocationContext *
|
||||
getBlockInvocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const BlockDecl *BD,
|
||||
const void *ContextData);
|
||||
|
||||
/// Discard all previously created LocationContext objects.
|
||||
void clear();
|
||||
|
@ -404,7 +419,6 @@ public:
|
|||
return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
|
||||
}
|
||||
|
||||
|
||||
/// Discard all previously created AnalysisDeclContexts.
|
||||
void clear();
|
||||
|
||||
|
|
|
@ -494,7 +494,7 @@ private:
|
|||
ProgramStateRef St, SVal location,
|
||||
const ProgramPointTag *tag, bool isLoad);
|
||||
|
||||
bool shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred);
|
||||
bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
|
||||
bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
|
||||
|
||||
bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
|
||||
|
|
|
@ -572,7 +572,7 @@ class SymbolReaper {
|
|||
|
||||
RegionSetTy RegionRoots;
|
||||
|
||||
const LocationContext *LCtx;
|
||||
const StackFrameContext *LCtx;
|
||||
const Stmt *Loc;
|
||||
SymbolManager& SymMgr;
|
||||
StoreRef reapedStore;
|
||||
|
@ -586,7 +586,8 @@ public:
|
|||
/// considered live.
|
||||
SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr,
|
||||
StoreManager &storeMgr)
|
||||
: LCtx(ctx), Loc(s), SymMgr(symmgr), reapedStore(0, storeMgr) {}
|
||||
: LCtx(ctx->getCurrentStackFrame()), Loc(s), SymMgr(symmgr),
|
||||
reapedStore(0, storeMgr) {}
|
||||
|
||||
~SymbolReaper() {}
|
||||
|
||||
|
|
|
@ -204,6 +204,14 @@ AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
|
|||
return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx);
|
||||
}
|
||||
|
||||
const BlockInvocationContext *
|
||||
AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent,
|
||||
const clang::BlockDecl *BD,
|
||||
const void *ContextData) {
|
||||
return getLocationContextManager().getBlockInvocationContext(this, parent,
|
||||
BD, ContextData);
|
||||
}
|
||||
|
||||
LocationContextManager & AnalysisDeclContext::getLocationContextManager() {
|
||||
assert(Manager &&
|
||||
"Cannot create LocationContexts without an AnalysisDeclContextManager!");
|
||||
|
@ -234,7 +242,7 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
|
|||
}
|
||||
|
||||
void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getAnalysisDeclContext(), getParent(), BD);
|
||||
Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -283,6 +291,24 @@ LocationContextManager::getScope(AnalysisDeclContext *ctx,
|
|||
return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
|
||||
}
|
||||
|
||||
const BlockInvocationContext *
|
||||
LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const BlockDecl *BD,
|
||||
const void *ContextData) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
BlockInvocationContext::Profile(ID, ctx, parent, BD, ContextData);
|
||||
void *InsertPos;
|
||||
BlockInvocationContext *L =
|
||||
cast_or_null<BlockInvocationContext>(Contexts.FindNodeOrInsertPos(ID,
|
||||
InsertPos));
|
||||
if (!L) {
|
||||
L = new BlockInvocationContext(ctx, parent, BD, ContextData);
|
||||
Contexts.InsertNode(L, InsertPos);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LocationContext methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -297,19 +323,6 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const StackFrameContext *
|
||||
LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const {
|
||||
const LocationContext *LC = this;
|
||||
while (LC) {
|
||||
if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) {
|
||||
if (cast<DeclContext>(SFC->getDecl()) == DC)
|
||||
return SFC;
|
||||
}
|
||||
LC = LC->getParent();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool LocationContext::isParentOf(const LocationContext *LC) const {
|
||||
do {
|
||||
const LocationContext *Parent = LC->getParent();
|
||||
|
|
|
@ -103,7 +103,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
|
|||
|
||||
const StackFrameContext *calleeCtx =
|
||||
CEBNode->getLocationContext()->getCurrentStackFrame();
|
||||
const LocationContext *callerCtx = calleeCtx->getParent();
|
||||
|
||||
// The parent context might not be a stack frame, so make sure we
|
||||
// look up the first enclosing stack frame.
|
||||
const StackFrameContext *callerCtx =
|
||||
calleeCtx->getParent()->getCurrentStackFrame();
|
||||
|
||||
const Stmt *CE = calleeCtx->getCallSite();
|
||||
ProgramStateRef state = CEBNode->getState();
|
||||
// Find the last statement in the function and the corresponding basic block.
|
||||
|
@ -199,8 +204,8 @@ static unsigned getNumberStackFrames(const LocationContext *LCtx) {
|
|||
}
|
||||
|
||||
// Determine if we should inline the call.
|
||||
bool ExprEngine::shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred) {
|
||||
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD);
|
||||
bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
|
||||
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
|
||||
const CFG *CalleeCFG = CalleeADC->getCFG();
|
||||
|
||||
// It is possible that the CFG cannot be constructed.
|
||||
|
@ -212,7 +217,7 @@ bool ExprEngine::shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred) {
|
|||
== AMgr.InlineMaxStackDepth)
|
||||
return false;
|
||||
|
||||
if (Engine.FunctionSummaries->hasReachedMaxBlockCount(FD))
|
||||
if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D))
|
||||
return false;
|
||||
|
||||
if (CalleeCFG->getNumBlockIDs() > AMgr.InlineMaxFunctionSize)
|
||||
|
@ -231,10 +236,7 @@ static bool shouldInlineCallExpr(const CallExpr *CE, ExprEngine *E) {
|
|||
if (const PointerType *PT = callee->getAs<PointerType>())
|
||||
FT = dyn_cast<FunctionProtoType>(PT->getPointeeType());
|
||||
else if (const BlockPointerType *BT = callee->getAs<BlockPointerType>()) {
|
||||
// FIXME: inline blocks.
|
||||
// FT = dyn_cast<FunctionProtoType>(BT->getPointeeType());
|
||||
(void) BT;
|
||||
return false;
|
||||
FT = dyn_cast<FunctionProtoType>(BT->getPointeeType());
|
||||
}
|
||||
// If we have no prototype, assume the function is okay.
|
||||
if (!FT)
|
||||
|
@ -250,41 +252,64 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
|
|||
if (!shouldInlineCallExpr(CE, this))
|
||||
return false;
|
||||
|
||||
const StackFrameContext *CallerSFC =
|
||||
Pred->getLocationContext()->getCurrentStackFrame();
|
||||
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
const FunctionDecl *FD =
|
||||
state->getSVal(Callee, Pred->getLocationContext()).getAsFunctionDecl();
|
||||
if (!FD || !FD->hasBody(FD))
|
||||
SVal CalleeVal = state->getSVal(Callee, Pred->getLocationContext());
|
||||
const Decl *D = 0;
|
||||
const LocationContext *ParentOfCallee = 0;
|
||||
|
||||
if (const FunctionDecl *FD = CalleeVal.getAsFunctionDecl()) {
|
||||
if (!FD->hasBody(FD))
|
||||
return false;
|
||||
|
||||
switch (CE->getStmtClass()) {
|
||||
default:
|
||||
// FIXME: Handle C++.
|
||||
break;
|
||||
case Stmt::CallExprClass: {
|
||||
D = FD;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
} else if (const BlockDataRegion *BR =
|
||||
dyn_cast_or_null<BlockDataRegion>(CalleeVal.getAsRegion())) {
|
||||
assert(CE->getStmtClass() == Stmt::CallExprClass);
|
||||
const BlockDecl *BD = BR->getDecl();
|
||||
D = BD;
|
||||
AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(BD);
|
||||
ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
|
||||
BD,
|
||||
BR);
|
||||
} else {
|
||||
// This is case we don't handle yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!D || !shouldInlineDecl(D, Pred))
|
||||
return false;
|
||||
|
||||
switch (CE->getStmtClass()) {
|
||||
default:
|
||||
// FIXME: Handle C++.
|
||||
break;
|
||||
case Stmt::CallExprClass: {
|
||||
if (!shouldInlineDecl(FD, Pred))
|
||||
return false;
|
||||
if (!ParentOfCallee)
|
||||
ParentOfCallee = CallerSFC;
|
||||
|
||||
// Construct a new stack frame for the callee.
|
||||
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD);
|
||||
const StackFrameContext *CallerSFC =
|
||||
Pred->getLocationContext()->getCurrentStackFrame();
|
||||
const StackFrameContext *CalleeSFC =
|
||||
CalleeADC->getStackFrame(CallerSFC, CE,
|
||||
currentBuilderContext->getBlock(),
|
||||
currentStmtIdx);
|
||||
|
||||
CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext());
|
||||
bool isNew;
|
||||
if (ExplodedNode *N = G.getNode(Loc, state, false, &isNew)) {
|
||||
N->addPredecessor(Pred, G);
|
||||
if (isNew)
|
||||
Engine.getWorkList()->enqueue(N);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Construct a new stack frame for the callee.
|
||||
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
|
||||
const StackFrameContext *CalleeSFC =
|
||||
CalleeADC->getStackFrame(ParentOfCallee, CE,
|
||||
currentBuilderContext->getBlock(),
|
||||
currentStmtIdx);
|
||||
|
||||
CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext());
|
||||
bool isNew;
|
||||
if (ExplodedNode *N = G.getNode(Loc, state, false, &isNew)) {
|
||||
N->addPredecessor(Pred, G);
|
||||
if (isNew)
|
||||
Engine.getWorkList()->enqueue(N);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isPointerToConst(const ParmVarDecl *ParamDecl) {
|
||||
|
|
|
@ -643,6 +643,37 @@ MemRegionManager::getObjCStringRegion(const ObjCStringLiteral* Str){
|
|||
return getSubRegion<ObjCStringRegion>(Str, getGlobalsRegion());
|
||||
}
|
||||
|
||||
/// Look through a chain of LocationContexts to either find the
|
||||
/// StackFrameContext that matches a DeclContext, or find a VarRegion
|
||||
/// for a variable captured by a block.
|
||||
static llvm::PointerUnion<const StackFrameContext *, const VarRegion *>
|
||||
getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
|
||||
const DeclContext *DC,
|
||||
const VarDecl *VD) {
|
||||
while (LC) {
|
||||
if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) {
|
||||
if (cast<DeclContext>(SFC->getDecl()) == DC)
|
||||
return SFC;
|
||||
}
|
||||
if (const BlockInvocationContext *BC =
|
||||
dyn_cast<BlockInvocationContext>(LC)) {
|
||||
const BlockDataRegion *BR =
|
||||
static_cast<const BlockDataRegion*>(BC->getContextData());
|
||||
// FIXME: This can be made more efficient.
|
||||
for (BlockDataRegion::referenced_vars_iterator
|
||||
I = BR->referenced_vars_begin(),
|
||||
E = BR->referenced_vars_end(); I != E; ++I) {
|
||||
if (const VarRegion *VR = dyn_cast<VarRegion>(I.getOriginalRegion()))
|
||||
if (VR->getDecl() == VD)
|
||||
return cast<VarRegion>(I.getCapturedRegion());
|
||||
}
|
||||
}
|
||||
|
||||
LC = LC->getParent();
|
||||
}
|
||||
return (const StackFrameContext*)0;
|
||||
}
|
||||
|
||||
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
|
||||
const LocationContext *LC) {
|
||||
const MemRegion *sReg = 0;
|
||||
|
@ -675,7 +706,13 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
|
|||
// FIXME: Once we implement scope handling, we will need to properly lookup
|
||||
// 'D' to the proper LocationContext.
|
||||
const DeclContext *DC = D->getDeclContext();
|
||||
const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC);
|
||||
llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
|
||||
getStackOrCaptureRegionForDeclContext(LC, DC, D);
|
||||
|
||||
if (V.is<const VarRegion*>())
|
||||
return V.get<const VarRegion*>();
|
||||
|
||||
const StackFrameContext *STC = V.get<const StackFrameContext*>();
|
||||
|
||||
if (!STC)
|
||||
sReg = getUnknownRegion();
|
||||
|
|
|
@ -568,6 +568,16 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
|
|||
if (!scan(SR->getSuperRegion()))
|
||||
return false;
|
||||
|
||||
// Regions captured by a block are also implicitly reachable.
|
||||
if (const BlockDataRegion *BDR = dyn_cast<BlockDataRegion>(R)) {
|
||||
BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
|
||||
E = BDR->referenced_vars_end();
|
||||
for ( ; I != E; ++I) {
|
||||
if (!scan(I.getCapturedRegion()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now look at the binding to this region (if any).
|
||||
if (!scan(state->getSValAsScalarOrLoc(R)))
|
||||
return false;
|
||||
|
|
|
@ -394,6 +394,12 @@ public: // Part of public interface to class.
|
|||
const LocationContext *callerCtx,
|
||||
const StackFrameContext *calleeCtx);
|
||||
|
||||
StoreRef enterStackFrame(ProgramStateRef state,
|
||||
const FunctionDecl *FD,
|
||||
const LocationContext *callerCtx,
|
||||
const StackFrameContext *calleeCtx);
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Region "extents".
|
||||
//===------------------------------------------------------------------===//
|
||||
|
@ -1944,8 +1950,18 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
|
|||
}
|
||||
|
||||
// If V is a region, then add it to the worklist.
|
||||
if (const MemRegion *R = V.getAsRegion())
|
||||
if (const MemRegion *R = V.getAsRegion()) {
|
||||
AddToWorkList(R);
|
||||
|
||||
// All regions captured by a block are also live.
|
||||
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
|
||||
BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(),
|
||||
E = BR->referenced_vars_end();
|
||||
for ( ; I != E; ++I)
|
||||
AddToWorkList(I.getCapturedRegion());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the set of live symbols.
|
||||
for (SymExpr::symbol_iterator SI = V.symbol_begin(), SE = V.symbol_end();
|
||||
|
@ -1964,21 +1980,6 @@ void removeDeadBindingsWorker::VisitBindingKey(BindingKey K) {
|
|||
// should continue to track that symbol.
|
||||
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
|
||||
SymReaper.markLive(SymR->getSymbol());
|
||||
|
||||
// For BlockDataRegions, enqueue the VarRegions for variables marked
|
||||
// with __block (passed-by-reference).
|
||||
// via BlockDeclRefExprs.
|
||||
if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
|
||||
for (BlockDataRegion::referenced_vars_iterator
|
||||
RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
|
||||
RI != RE; ++RI) {
|
||||
if ((*RI)->getDecl()->getAttr<BlocksAttr>())
|
||||
AddToWorkList(*RI);
|
||||
}
|
||||
|
||||
// No possible data bindings on a BlockDataRegion.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Visit the data binding for K.
|
||||
|
@ -2045,12 +2046,37 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
|
|||
return StoreRef(B.getRootWithoutRetain(), *this);
|
||||
}
|
||||
|
||||
|
||||
StoreRef RegionStoreManager::enterStackFrame(ProgramStateRef state,
|
||||
const LocationContext *callerCtx,
|
||||
const StackFrameContext *calleeCtx)
|
||||
{
|
||||
FunctionDecl const *FD = cast<FunctionDecl>(calleeCtx->getDecl());
|
||||
const Decl *D = calleeCtx->getDecl();
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
||||
return enterStackFrame(state, FD, callerCtx, calleeCtx);
|
||||
|
||||
// FIXME: when we handle more cases, this will need to be expanded.
|
||||
|
||||
const BlockDecl *BD = cast<BlockDecl>(D);
|
||||
BlockDecl::param_const_iterator PI = BD->param_begin(),
|
||||
PE = BD->param_end();
|
||||
StoreRef store = StoreRef(state->getStore(), *this);
|
||||
const CallExpr *CE = cast<CallExpr>(calleeCtx->getCallSite());
|
||||
CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
|
||||
for (; AI != AE && PI != PE; ++AI, ++PI) {
|
||||
SVal ArgVal = state->getSVal(*AI, callerCtx);
|
||||
store = Bind(store.getStore(),
|
||||
svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
|
||||
ArgVal);
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
StoreRef RegionStoreManager::enterStackFrame(ProgramStateRef state,
|
||||
const FunctionDecl *FD,
|
||||
const LocationContext *callerCtx,
|
||||
const StackFrameContext *calleeCtx)
|
||||
{
|
||||
FunctionDecl::param_const_iterator PI = FD->param_begin(),
|
||||
PE = FD->param_end();
|
||||
StoreRef store = StoreRef(state->getStore(), *this);
|
||||
|
|
|
@ -79,9 +79,7 @@ void test2() {
|
|||
void test2_b() {
|
||||
static int y = 0;
|
||||
__block int x;
|
||||
// This is also a bug, but should be found not by checking the value
|
||||
// 'x' is bound at block creation.
|
||||
^{ y = x + 1; }(); // no-warning
|
||||
^{ y = x + 1; }(); // expected-warning {{left operand of '+' is a garbage value}}
|
||||
}
|
||||
|
||||
void test2_c() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t
|
||||
// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -fblocks -o %t
|
||||
// RUN: FileCheck -input-file %t %s
|
||||
|
||||
// <rdar://problem/10967815>
|
||||
|
@ -37,6 +37,32 @@ void bar(int *p) {
|
|||
triggers_bug(p);
|
||||
}
|
||||
|
||||
// ========================================================================== //
|
||||
// Test inlining of blocks.
|
||||
// ========================================================================== //
|
||||
|
||||
void test_block__capture_null() {
|
||||
int *p = 0;
|
||||
^(){ *p = 1; }();
|
||||
}
|
||||
|
||||
void test_block_ret() {
|
||||
int *p = ^(){ int *q = 0; return q; }();
|
||||
*p = 1;
|
||||
}
|
||||
|
||||
void test_block_blockvar() {
|
||||
__block int *p;
|
||||
^(){ p = 0; }();
|
||||
*p = 1;
|
||||
}
|
||||
|
||||
void test_block_arg() {
|
||||
int *p;
|
||||
^(int **q){ *q = 0; }(&p);
|
||||
*p = 1;
|
||||
}
|
||||
|
||||
// CHECK: <?xml version="1.0" encoding="UTF-8"?>
|
||||
// CHECK: <plist version="1.0">
|
||||
// CHECK: <dict>
|
||||
|
@ -630,6 +656,528 @@ void bar(int *p) {
|
|||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>path</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>45</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>45</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>45</integer>
|
||||
// CHECK: <key>col</key><integer>8</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>depth</key><integer>0</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Variable 'p' initialized to a null pointer value</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Variable 'p' initialized to a null pointer value</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>45</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>45</integer>
|
||||
// CHECK: <key>col</key><integer>8</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>18</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>depth</key><integer>0</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Calling anonymous block</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Calling anonymous block</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>depth</key><integer>1</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Entered call from 'test_block__capture_null'</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Entered call from 'test_block__capture_null'</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>8</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>8</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>8</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>9</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>9</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>depth</key><integer>1</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>category</key><string>Logic error</string>
|
||||
// CHECK: <key>type</key><string>Dereference of null pointer</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>46</integer>
|
||||
// CHECK: <key>col</key><integer>8</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>path</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>50</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>50</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>50</integer>
|
||||
// CHECK: <key>col</key><integer>12</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>50</integer>
|
||||
// CHECK: <key>col</key><integer>12</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>50</integer>
|
||||
// CHECK: <key>col</key><integer>12</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>50</integer>
|
||||
// CHECK: <key>col</key><integer>41</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>51</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>51</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>51</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>51</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>51</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>depth</key><integer>0</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>category</key><string>Logic error</string>
|
||||
// CHECK: <key>type</key><string>Dereference of null pointer</string>
|
||||
// CHECK: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK: <key>issue_context</key><string>test_block_ret</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>51</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>path</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>55</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>55</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>56</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>56</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>56</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>56</integer>
|
||||
// CHECK: <key>col</key><integer>17</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>57</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>57</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>57</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>57</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>57</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>depth</key><integer>0</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>category</key><string>Logic error</string>
|
||||
// CHECK: <key>type</key><string>Dereference of null pointer</string>
|
||||
// CHECK: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK: <key>issue_context</key><string>test_block_blockvar</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>57</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>path</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>61</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>61</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>62</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>62</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>control</string>
|
||||
// CHECK: <key>edges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>start</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>62</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>62</integer>
|
||||
// CHECK: <key>col</key><integer>27</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>end</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>63</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>63</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>kind</key><string>event</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>63</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>63</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>63</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>depth</key><integer>0</integer>
|
||||
// CHECK: <key>extended_message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>message</key>
|
||||
// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string>
|
||||
// CHECK: <key>category</key><string>Logic error</string>
|
||||
// CHECK: <key>type</key><string>Dereference of null pointer</string>
|
||||
// CHECK: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK: <key>issue_context</key><string>test_block_arg</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>63</integer>
|
||||
// CHECK: <key>col</key><integer>3</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </plist>
|
||||
|
|
|
@ -1452,8 +1452,7 @@ void test_blocks_1_indirect_release_via_call(void) {
|
|||
}
|
||||
|
||||
void test_blocks_1_indirect_retain_via_call(void) {
|
||||
// Eventually this should be reported as a leak.
|
||||
NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning
|
||||
NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning {{leak}}
|
||||
^(NSObject *o){ [o retain]; }(number);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue