aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/BugReporter.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-04-01 06:13:56 +0000
committerTed Kremenek <kremenek@apple.com>2009-04-01 06:13:56 +0000
commit5fb5dfb6646464db3cd6d54a6332375c8fe36b75 (patch)
tree0c5fc288044b8320b5337de39cb1d2dddc7c0bde /lib/Analysis/BugReporter.cpp
parent360431660b2245a109f5c6870729126dbcdea254 (diff)
- Changed PathDiagnosticPiece::getLocation() to return a PathDiagnosticLocation
instead of a FullSourceLoc. This resulted in a bunch of small edits in various clients. - Updated BugReporter to include an alternate PathDiagnostic generation algorithm for PathDiagnosticClients desiring more control-flow pieces. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68193 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/BugReporter.cpp')
-rw-r--r--lib/Analysis/BugReporter.cpp173
1 files changed, 168 insertions, 5 deletions
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 1d1c2fa7d0..f54200b040 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -154,6 +154,14 @@ public:
PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
+ PathDiagnosticLocation
+ getEnclosingStmtLocation(const PathDiagnosticLocation &L) {
+ if (const Stmt *S = L.asStmt())
+ return getEnclosingStmtLocation(S);
+
+ return L;
+ }
+
PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const {
return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive;
}
@@ -196,13 +204,21 @@ PathDiagnosticLocation
PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
ParentMap &P = getParentMap();
- while (isa<Expr>(S)) {
+
+ while (isa<DeclStmt>(S) || isa<Expr>(S)) {
const Stmt *Parent = P.getParent(S);
if (!Parent)
break;
switch (Parent->getStmtClass()) {
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *B = cast<BinaryOperator>(Parent);
+ if (B->isLogicalOp())
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ }
+
case Stmt::CompoundStmtClass:
case Stmt::StmtExprClass:
return PathDiagnosticLocation(S, SMgr);
@@ -674,7 +690,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
End = PDB.getEnclosingStmtLocation(S);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is true. Entering loop body"));
+ "Loop condition is true. Entering loop body"));
}
break;
@@ -688,10 +704,10 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (*(Src->succ_begin()+1) == Dst)
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking false branch"));
+ "Taking false branch"));
else
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking true branch"));
+ "Taking true branch"));
break;
}
@@ -715,6 +731,151 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
//===----------------------------------------------------------------------===//
+// "Extensive" PathDiagnostic generation.
+//===----------------------------------------------------------------------===//
+
+static bool IsControlFlowExpr(const Stmt *S) {
+ const Expr *E = dyn_cast<Expr>(S);
+
+ if (!E)
+ return false;
+
+ E = E->IgnoreParenCasts();
+
+ if (isa<ConditionalOperator>(E))
+ return true;
+
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
+ if (B->isLogicalOp())
+ return true;
+
+ return false;
+}
+
+static void GenExtAddEdge(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ PathDiagnosticLocation NewLoc,
+ PathDiagnosticLocation &PrevLoc,
+ PathDiagnosticLocation UpdateLoc) {
+
+ if (const Stmt *S = NewLoc.asStmt()) {
+ if (IsControlFlowExpr(S))
+ return;
+ }
+
+
+ if (!PrevLoc.isValid()) {
+ PrevLoc = NewLoc;
+ return;
+ }
+
+ if (NewLoc == PrevLoc)
+ return;
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(NewLoc, PrevLoc));
+ PrevLoc = UpdateLoc;
+}
+
+static bool IsNestedDeclStmt(const Stmt *S, ParentMap &PM) {
+ const DeclStmt *DS = dyn_cast<DeclStmt>(S);
+
+ if (!DS)
+ return false;
+
+ const Stmt *Parent = PM.getParent(DS);
+ if (!Parent)
+ return false;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Parent))
+ return FS->getInit() == DS;
+
+ // FIXME: In the future IfStmt/WhileStmt may contain DeclStmts in their condition.
+// if (const IfStmt *IF = dyn_cast<IfStmt>(Parent))
+// return IF->getCond() == DS;
+//
+// if (const WhileStmt *WS = dyn_cast<WhileStmt>(Parent))
+// return WS->getCond() == DS;
+
+ return false;
+}
+
+static void GenExtAddEdge(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const PathDiagnosticLocation &NewLoc,
+ PathDiagnosticLocation &PrevLoc) {
+ GenExtAddEdge(PD, PDB, NewLoc, PrevLoc, NewLoc);
+}
+
+static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode<GRState> *N) {
+
+ SourceManager& SMgr = PDB.getSourceManager();
+ const ExplodedNode<GRState>* NextNode = N->pred_empty()
+ ? NULL : *(N->pred_begin());
+
+ PathDiagnosticLocation PrevLoc;
+
+ while (NextNode) {
+ N = NextNode;
+ NextNode = GetPredecessorNode(N);
+ ProgramPoint P = N->getLocation();
+
+ // Block edges.
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const CFGBlock &Blk = *BE->getSrc();
+ if (const Stmt *Term = Blk.getTerminator()) {
+ const Stmt *Cond = Blk.getTerminatorCondition();
+
+ if (!Cond || !IsControlFlowExpr(Cond)) {
+ GenExtAddEdge(PD, PDB, PathDiagnosticLocation(Term, SMgr), PrevLoc);
+ continue;
+ }
+ }
+
+ // Only handle blocks with more than 1 statement here, as the blocks
+ // with one statement are handled at BlockEntrances.
+ if (Blk.size() > 1) {
+ const Stmt *S = *Blk.rbegin();
+
+ // We don't add control-flow edges for DeclStmt's that appear in
+ // the condition of if/while/for or are control-flow merge expressions.
+ if (!IsControlFlowExpr(S) && !IsNestedDeclStmt(S, PDB.getParentMap())) {
+ GenExtAddEdge(PD, PDB, PathDiagnosticLocation(S, SMgr), PrevLoc);
+ }
+ }
+
+ continue;
+ }
+
+ if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (const Stmt* S = BE->getFirstStmt()) {
+ if (!IsControlFlowExpr(S) && !IsNestedDeclStmt(S, PDB.getParentMap())) {
+ // Are we jumping with the same enclosing statement?
+ if (PrevLoc.isValid() && PDB.getEnclosingStmtLocation(S) ==
+ PDB.getEnclosingStmtLocation(PrevLoc)) {
+ continue;
+ }
+
+ GenExtAddEdge(PD, PDB, PDB.getEnclosingStmtLocation(S), PrevLoc);
+ }
+ }
+
+ continue;
+ }
+
+ PathDiagnosticPiece* p =
+ PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
+ PDB.getBugReporter(), PDB.getNodeMapClosure());
+
+ if (p) {
+ GenExtAddEdge(PD, PDB, p->getLocation(), PrevLoc);
+ PD.push_front(p);
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
BugType::~BugType() {}
@@ -993,7 +1154,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
// Get the location of the PathDiagnosticPiece.
- const FullSourceLoc Loc = I->getLocation();
+ const FullSourceLoc Loc = I->getLocation().asLocation();
// Determine the instantiation location, which is the location we group
// related PathDiagnosticPieces.
@@ -1114,6 +1275,8 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive:
+ GenerateExtensivePathDiagnostic(PD,PDB, N);
+ break;
case PathDiagnosticClient::Minimal:
GenerateMinimalPathDiagnostic(PD, PDB, N);
break;