[analyzer] Use the CFG to see if a constructor is for a local variable.

Previously we were using ParentMap and crawling through the parent DeclStmt.
This should be at least slightly cheaper (and is also more flexible).

No (intended) functionality change.

llvm-svn: 160807
This commit is contained in:
Jordan Rose 2012-07-26 20:04:16 +00:00
parent b970505d0d
commit 05375eb4ec
1 changed files with 22 additions and 34 deletions

View File

@ -17,7 +17,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/ParentMap.h"
using namespace clang;
using namespace ento;
@ -41,45 +40,35 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
}
static const VarDecl *findDirectConstruction(const DeclStmt *DS,
const Expr *Init) {
for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
const VarDecl *Var = dyn_cast<VarDecl>(*I);
if (!Var)
continue;
if (Var->getInit() != Init)
continue;
// FIXME: We need to decide how copy-elision should work here.
if (!Var->isDirectInit())
break;
if (Var->getType()->isReferenceType())
break;
return Var;
}
return 0;
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
const MemRegion *Target = 0;
switch (CE->getConstructionKind()) {
case CXXConstructExpr::CK_Complete: {
// See if we're constructing an existing region.
// FIXME: This is inefficient. Not only are we getting the parent of the
// CXXConstructExpr, but we also then have to crawl through it if it's a
// DeclStmt to find out which variable is being constructed. (The CFG has
// one (fake) DeclStmt per Decl, but ParentMap uses the original AST.)
const ParentMap &PM = LCtx->getParentMap();
if (const DeclStmt *DS = dyn_cast_or_null<DeclStmt>(PM.getParent(CE)))
if (const VarDecl *Var = findDirectConstruction(DS, CE))
Target = Pred->getState()->getLValue(Var, LCtx).getAsRegion();
// If we can't find an existing region to construct into, we'll just
// See if we're constructing an existing region by looking at the next
// element in the CFG.
const CFGBlock *B = currentBuilderContext->getBlock();
if (currentStmtIdx + 1 < B->size()) {
CFGElement Next = (*B)[currentStmtIdx+1];
// Is this a constructor for a local variable?
if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next))
if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt()))
if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl()))
if (Var->getInit() == CE)
Target = State->getLValue(Var, LCtx).getAsRegion();
// FIXME: This will eventually need to handle new-expressions as well.
}
// If we couldn't find an existing region to construct into, we'll just
// generate a symbolic region, which is fine.
break;
}
case CXXConstructExpr::CK_NonVirtualBase:
@ -88,7 +77,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
LCtx->getCurrentStackFrame());
SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
SVal ThisVal = State->getSVal(ThisPtr);
if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) {
Target = ThisVal.getAsRegion();
@ -102,8 +91,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
}
}
CXXConstructorCall Call(CE, Target, Pred->getState(),
Pred->getLocationContext());
CXXConstructorCall Call(CE, Target, State, LCtx);
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);