[analyzer;alternate edges] prune out extra edges to a subexpression where we dive-in and out of a subexpression.

Fixes <rdar://problem/13941891>.

llvm-svn: 182426
This commit is contained in:
Ted Kremenek 2013-05-21 21:38:05 +00:00
parent 6d5bbec32e
commit 9f0629f669
1 changed files with 46 additions and 4 deletions

View File

@ -1950,6 +1950,18 @@ void PathPieces::dump() const {
}
}
/// \brief Return true if X is contained by Y.
static bool lexicalContains(ParentMap &PM,
const Stmt *X,
const Stmt *Y) {
while (X) {
if (X == Y)
return true;
X = PM.getParent(X);
}
return false;
}
static bool optimizeEdges(PathPieces &path, SourceManager &SM,
OptimizedCallsSet &OCS,
LocationContextMap &LCM) {
@ -2058,10 +2070,40 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
// to prevent this optimization.
//
if (s1End && s1End == s2Start && level2) {
if (isIncrementOrInitInForLoop(s1End, level2) ||
(isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End)) &&
!isConditionForTerminator(level2, s1End)))
{
bool removeEdge = false;
// Remove edges into the increment or initialization of a
// loop that have no interleaving event. This means that
// they aren't interesting.
if (isIncrementOrInitInForLoop(s1End, level2))
removeEdge = true;
// Next only consider edges that are not anchored on
// the condition of a terminator. This are intermediate edges
// that we might want to trim.
else if (!isConditionForTerminator(level2, s1End)) {
// Trim edges on expressions that are consumed by
// the parent expression.
if (isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End))) {
removeEdge = true;
}
// Trim edges where a lexical containment doesn't exist.
// For example:
//
// X -> Y -> Z
//
// If 'Z' lexically contains Y (it is an ancestor) and
// 'X' does not lexically contain Y (it is a descendant OR
// it has no lexical relationship at all) then trim.
//
// This can eliminate edges where we dive into a subexpression
// and then pop back out, etc.
else if (s1Start && s2End &&
lexicalContains(PM, s2Start, s2End) &&
!lexicalContains(PM, s1End, s1Start)) {
removeEdge = true;
}
}
if (removeEdge) {
PieceI->setEndLocation(PieceNextI->getEndLocation());
path.erase(NextI);
hasChanges = true;