r324507 - [analyzer] [NFC] Factor out generating path diagnostics for a statement into a function
George Karpenkov via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 7 11:56:52 PST 2018
Author: george.karpenkov
Date: Wed Feb 7 11:56:52 2018
New Revision: 324507
URL: http://llvm.org/viewvc/llvm-project?rev=324507&view=rev
Log:
[analyzer] [NFC] Factor out generating path diagnostics for a statement into a function
Differential Revision: https://reviews.llvm.org/D42558
Modified:
cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp?rev=324507&r1=324506&r2=324507&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp Wed Feb 7 11:56:52 2018
@@ -556,330 +556,330 @@ static void updateStackPiecesWithMessage
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
-static bool GenerateMinimalPathDiagnostic(
- PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
- LocationContextMap &LCM,
- ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
+/// Add path diagnostic for statement associated with node \p N
+/// to diagnostics \p PD.
+/// Precondition: location associated with \p N is a \c BlockEdge.
+static void generateMinimalDiagnosticsForBlockEdge(const ExplodedNode *N,
+ PathDiagnosticBuilder &PDB,
+ PathDiagnostic &PD) {
+
+ const LocationContext *LC = N->getLocationContext();
SourceManager& SMgr = PDB.getSourceManager();
- const LocationContext *LC = PDB.LC;
- const ExplodedNode *NextNode = N->pred_empty()
- ? nullptr : *(N->pred_begin());
+ BlockEdge BE = N->getLocation().castAs<BlockEdge>();
+ const CFGBlock *Src = BE.getSrc();
+ const CFGBlock *Dst = BE.getDst();
+ const Stmt *T = Src->getTerminator();
+ if (!T)
+ return;
- StackDiagVector CallStack;
+ auto Start = PathDiagnosticLocation::createBegin(T, SMgr, LC);
+ switch (T->getStmtClass()) {
+ default:
+ break;
+
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass: {
+ const Stmt *S = PathDiagnosticLocation::getNextStmt(N);
- while (NextNode) {
- N = NextNode;
- PDB.LC = N->getLocationContext();
- NextNode = N->getFirstPred();
+ if (!S)
+ break;
- ProgramPoint P = N->getLocation();
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
+
+ os << "Control jumps to line " << End.asLocation().getExpansionLineNumber();
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
+ break;
+ }
+
+ case Stmt::SwitchStmtClass: {
+ // Figure out what case arm we took.
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
- do {
- if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
- auto C = PathDiagnosticCallPiece::construct(N, *CE, SMgr);
- // Record the mapping from call piece to LocationContext.
- LCM[&C->path] = CE->getCalleeContext();
- auto *P = C.get();
- PD.getActivePath().push_front(std::move(C));
- PD.pushActivePath(&P->path);
- CallStack.push_back(StackDiagPair(P, N));
+ if (const Stmt *S = Dst->getLabel()) {
+ PathDiagnosticLocation End(S, SMgr, LC);
+
+ switch (S->getStmtClass()) {
+ default:
+ os << "No cases match in the switch statement. "
+ "Control jumps to line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
+ case Stmt::DefaultStmtClass:
+ os << "Control jumps to the 'default' case at line "
+ << End.asLocation().getExpansionLineNumber();
break;
- }
- if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
- // Flush all locations, and pop the active path.
- bool VisitedEntireCall = PD.isWithinCall();
- PD.popActivePath();
-
- // Either we just added a bunch of stuff to the top-level path, or
- // we have a previous CallExitEnd. If the former, it means that the
- // path terminated within a function call. We must then take the
- // current contents of the active path and place it within
- // a new PathDiagnosticCallPiece.
- PathDiagnosticCallPiece *C;
- if (VisitedEntireCall) {
- C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
- } else {
- const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
- // Record the mapping from call piece to LocationContext.
- LCM[&C->path] = CE->getCalleeContext();
+ case Stmt::CaseStmtClass: {
+ os << "Control jumps to 'case ";
+ const CaseStmt *Case = cast<CaseStmt>(S);
+ const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
+
+ // Determine if it is an enum.
+ bool GetRawInt = true;
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
+ // FIXME: Maybe this should be an assertion. Are there cases
+ // were it is not an EnumConstantDecl?
+ const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+ if (D) {
+ GetRawInt = false;
+ os << *D;
+ }
}
- C->setCallee(*CE, SMgr);
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
- }
+ if (GetRawInt)
+ os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
+
+ os << ":' at line " << End.asLocation().getExpansionLineNumber();
break;
}
+ }
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ } else {
+ os << "'Default' branch taken. ";
+ const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ }
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
- const CFGBlock *Src = BE->getSrc();
- const CFGBlock *Dst = BE->getDst();
- const Stmt *T = Src->getTerminator();
+ break;
+ }
- if (!T)
- break;
+ case Stmt::BreakStmtClass:
+ case Stmt::ContinueStmtClass: {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
+ break;
+ }
+
+ // Determine control-flow for ternary '?'.
+ case Stmt::BinaryConditionalOperatorClass:
+ case Stmt::ConditionalOperatorClass: {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "'?' condition is ";
+
+ if (*(Src->succ_begin() + 1) == Dst)
+ os << "false";
+ else
+ os << "true";
+
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
+ break;
+ }
+
+ // Determine control-flow for short-circuited '&&' and '||'.
+ case Stmt::BinaryOperatorClass: {
+ if (!PDB.supportsLogicalOpControlFlow())
+ break;
+
+ const BinaryOperator *B = cast<BinaryOperator>(T);
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "Left side of '";
+
+ if (B->getOpcode() == BO_LAnd) {
+ os << "&&"
+ << "' is ";
+
+ if (*(Src->succ_begin() + 1) == Dst) {
+ os << "false";
+ PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
+ PathDiagnosticLocation Start =
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ } else {
+ os << "true";
+ PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ }
+ } else {
+ assert(B->getOpcode() == BO_LOr);
+ os << "||"
+ << "' is ";
+
+ if (*(Src->succ_begin() + 1) == Dst) {
+ os << "false";
+ PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ } else {
+ os << "true";
+ PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
- PathDiagnosticLocation::createBegin(T, SMgr,
- N->getLocationContext());
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ }
+ }
- switch (T->getStmtClass()) {
- default:
- break;
+ break;
+ }
- case Stmt::GotoStmtClass:
- case Stmt::IndirectGotoStmtClass: {
- const Stmt *S = PathDiagnosticLocation::getNextStmt(N);
-
- if (!S)
- break;
-
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
-
- os << "Control jumps to line "
- << End.asLocation().getExpansionLineNumber();
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- break;
- }
+ case Stmt::DoStmtClass: {
+ if (*(Src->succ_begin()) == Dst) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
- case Stmt::SwitchStmtClass: {
- // Figure out what case arm we took.
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
-
- if (const Stmt *S = Dst->getLabel()) {
- PathDiagnosticLocation End(S, SMgr, LC);
-
- switch (S->getStmtClass()) {
- default:
- os << "No cases match in the switch statement. "
- "Control jumps to line "
- << End.asLocation().getExpansionLineNumber();
- break;
- case Stmt::DefaultStmtClass:
- os << "Control jumps to the 'default' case at line "
- << End.asLocation().getExpansionLineNumber();
- break;
-
- case Stmt::CaseStmtClass: {
- os << "Control jumps to 'case ";
- const CaseStmt *Case = cast<CaseStmt>(S);
- const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
-
- // Determine if it is an enum.
- bool GetRawInt = true;
-
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
- // FIXME: Maybe this should be an assertion. Are there cases
- // were it is not an EnumConstantDecl?
- const EnumConstantDecl *D =
- dyn_cast<EnumConstantDecl>(DR->getDecl());
-
- if (D) {
- GetRawInt = false;
- os << *D;
- }
- }
-
- if (GetRawInt)
- os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
-
- os << ":' at line "
- << End.asLocation().getExpansionLineNumber();
- break;
- }
- }
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- else {
- os << "'Default' branch taken. ";
- const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
+ os << "Loop condition is true. ";
+ PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- break;
- }
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
- case Stmt::BreakStmtClass:
- case Stmt::ContinueStmtClass: {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- break;
- }
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ } else {
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- // Determine control-flow for ternary '?'.
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ConditionalOperatorClass: {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- os << "'?' condition is ";
-
- if (*(Src->succ_begin()+1) == Dst)
- os << "false";
- else
- os << "true";
-
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
-
- if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
-
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- break;
- }
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
- // Determine control-flow for short-circuited '&&' and '||'.
- case Stmt::BinaryOperatorClass: {
- if (!PDB.supportsLogicalOpControlFlow())
- break;
-
- const BinaryOperator *B = cast<BinaryOperator>(T);
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- os << "Left side of '";
-
- if (B->getOpcode() == BO_LAnd) {
- os << "&&" << "' is ";
-
- if (*(Src->succ_begin()+1) == Dst) {
- os << "false";
- PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
- PathDiagnosticLocation Start =
- PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- else {
- os << "true";
- PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- }
- else {
- assert(B->getOpcode() == BO_LOr);
- os << "||" << "' is ";
-
- if (*(Src->succ_begin()+1) == Dst) {
- os << "false";
- PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- else {
- os << "true";
- PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
- PathDiagnosticLocation Start =
- PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- }
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(
+ Start, End, "Loop condition is false. Exiting loop"));
+ }
- break;
- }
+ break;
+ }
- case Stmt::DoStmtClass: {
- if (*(Src->succ_begin()) == Dst) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
-
- os << "Loop condition is true. ";
- PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
-
- if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
-
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- else {
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ case Stmt::WhileStmtClass:
+ case Stmt::ForStmtClass: {
+ if (*(Src->succ_begin() + 1) == Dst) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "Loop condition is false. ";
+ PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
+ os.str()));
+ } else {
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(
+ Start, End, "Loop condition is true. Entering loop body"));
+ }
- if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ break;
+ }
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(
- Start, End, "Loop condition is false. Exiting loop"));
- }
+ case Stmt::IfStmtClass: {
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- break;
- }
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
- case Stmt::WhileStmtClass:
- case Stmt::ForStmtClass: {
- if (*(Src->succ_begin()+1) == Dst) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
-
- os << "Loop condition is false. ";
- PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
-
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
- os.str()));
- }
- else {
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
-
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(
- Start, End, "Loop condition is true. Entering loop body"));
- }
+ if (*(Src->succ_begin() + 1) == Dst)
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(
+ Start, End, "Taking false branch"));
+ else
+ PD.getActivePath().push_front(
+ std::make_shared<PathDiagnosticControlFlowPiece>(
+ Start, End, "Taking true branch"));
- break;
- }
+ break;
+ }
+ }
+}
- case Stmt::IfStmtClass: {
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+/// Generate minimal diagnostics for node \p N, and write it into path
+/// diagnostics \p PD.
+void generateMinimalDiagnosticsForNode(const ExplodedNode *N,
+ PathDiagnosticBuilder &PDB,
+ PathDiagnostic &PD,
+ LocationContextMap &LCM,
+ StackDiagVector &CallStack) {
- if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ SourceManager &SMgr = PDB.getSourceManager();
+ ProgramPoint P = N->getLocation();
- if (*(Src->succ_begin()+1) == Dst)
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(
- Start, End, "Taking false branch"));
- else
- PD.getActivePath().push_front(
- std::make_shared<PathDiagnosticControlFlowPiece>(
- Start, End, "Taking true branch"));
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
+ auto C = PathDiagnosticCallPiece::construct(N, *CE, SMgr);
+ // Record the mapping from call piece to LocationContext.
+ LCM[&C->path] = CE->getCalleeContext();
+ auto *P = C.get();
+ PD.getActivePath().push_front(std::move(C));
+ PD.pushActivePath(&P->path);
+ CallStack.push_back(StackDiagPair(P, N));
+ } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
+ // Flush all locations, and pop the active path.
+ bool VisitedEntireCall = PD.isWithinCall();
+ PD.popActivePath();
+
+ // Either we just added a bunch of stuff to the top-level path, or
+ // we have a previous CallExitEnd. If the former, it means that the
+ // path terminated within a function call. We must then take the
+ // current contents of the active path and place it within
+ // a new PathDiagnosticCallPiece.
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ // Record the mapping from call piece to LocationContext.
+ LCM[&C->path] = CE->getCalleeContext();
+ }
- break;
- }
- }
- }
- } while(0);
+ C->setCallee(*CE, SMgr);
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ } else if (P.getKind() == ProgramPoint::BlockEdgeKind) {
+ generateMinimalDiagnosticsForBlockEdge(N, PDB, PD);
+ }
+}
+
+static bool GenerateMinimalPathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
+ const ExplodedNode *NextNode = N->pred_empty()
+ ? nullptr : *(N->pred_begin());
+ StackDiagVector CallStack;
+
+ while (NextNode) {
+ N = NextNode;
+ PDB.LC = N->getLocationContext();
+ NextNode = N->getFirstPred();
+
+ generateMinimalDiagnosticsForNode(N, PDB, PD, LCM, CallStack);
if (NextNode) {
// Add diagnostic pieces from custom visitors.
@@ -1315,6 +1315,8 @@ static void reversePropagateInterestingS
}
}
+
+
//===----------------------------------------------------------------------===//
// Functions for determining if a loop was executed 0 times.
//===----------------------------------------------------------------------===//
@@ -1404,183 +1406,187 @@ static bool isInLoopBody(ParentMap &PM,
return isContainedByStmt(PM, LoopBody, S);
}
-//===----------------------------------------------------------------------===//
-// Top-level logic for generating extensive path diagnostics.
-//===----------------------------------------------------------------------===//
+/// Generate extensive diagnostics for statement associated with node \p N,
+/// and write it into \p PD.
+static void generateExtensiveDiagnosticsForNode(
+ const ExplodedNode *N,
+ PathDiagnosticBuilder &PDB,
+ LocationContextMap &LCM,
+ EdgeBuilder &EB,
+ StackDiagVector &CallStack,
+ PathDiagnostic &PD,
+ InterestingExprs &IE) {
-static bool GenerateExtensivePathDiagnostic(
- PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
- LocationContextMap &LCM,
- ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
- EdgeBuilder EB(PD, PDB);
+ const ExplodedNode *NextNode = N->getFirstPred();
+ ProgramPoint P = N->getLocation();
const SourceManager& SM = PDB.getSourceManager();
- StackDiagVector CallStack;
- InterestingExprs IE;
-
- const ExplodedNode *NextNode = N->pred_empty() ? nullptr : *(N->pred_begin());
- while (NextNode) {
- N = NextNode;
- NextNode = N->getFirstPred();
- ProgramPoint P = N->getLocation();
-
- do {
- if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
- if (const Expr *Ex = PS->getStmtAs<Expr>())
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), Ex,
- N->getLocationContext());
- }
-
- if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
- const Stmt *S = CE->getCalleeContext()->getCallSite();
- if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), Ex,
- N->getLocationContext());
- }
- auto C = PathDiagnosticCallPiece::construct(N, *CE, SM);
- LCM[&C->path] = CE->getCalleeContext();
-
- EB.addEdge(C->callReturn, /*AlwaysAdd=*/true, /*IsPostJump=*/true);
- EB.flushLocations();
-
- auto *P = C.get();
- PD.getActivePath().push_front(std::move(C));
- PD.pushActivePath(&P->path);
- CallStack.push_back(StackDiagPair(P, N));
- break;
- }
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
+ if (const Expr *Ex = PS->getStmtAs<Expr>())
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().get(), Ex,
+ N->getLocationContext());
+ return;
+ } else if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
+ const Stmt *S = CE->getCalleeContext()->getCallSite();
+ if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().get(), Ex,
+ N->getLocationContext());
+ }
- // Pop the call hierarchy if we are done walking the contents
- // of a function call.
- if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
- // Add an edge to the start of the function.
- const Decl *D = CE->getCalleeContext()->getDecl();
- PathDiagnosticLocation pos =
- PathDiagnosticLocation::createBegin(D, SM);
- EB.addEdge(pos);
-
- // Flush all locations, and pop the active path.
- bool VisitedEntireCall = PD.isWithinCall();
- EB.flushLocations();
- PD.popActivePath();
- PDB.LC = N->getLocationContext();
-
- // Either we just added a bunch of stuff to the top-level path, or
- // we have a previous CallExitEnd. If the former, it means that the
- // path terminated within a function call. We must then take the
- // current contents of the active path and place it within
- // a new PathDiagnosticCallPiece.
- PathDiagnosticCallPiece *C;
- if (VisitedEntireCall) {
- C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
- } else {
- const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
- LCM[&C->path] = CE->getCalleeContext();
- }
+ auto C = PathDiagnosticCallPiece::construct(N, *CE, SM);
+ LCM[&C->path] = CE->getCalleeContext();
- C->setCallee(*CE, SM);
- EB.addContext(C->getLocation());
+ EB.addEdge(C->callReturn, /*AlwaysAdd=*/true, /*IsPostJump=*/true);
+ EB.flushLocations();
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
- }
- break;
- }
+ auto *P = C.get();
+ PD.getActivePath().push_front(std::move(C));
+ PD.pushActivePath(&P->path);
+ CallStack.push_back(StackDiagPair(P, N));
+ return;
+ } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
- // Note that is important that we update the LocationContext
- // after looking at CallExits. CallExit basically adds an
- // edge in the *caller*, so we don't want to update the LocationContext
- // too soon.
- PDB.LC = N->getLocationContext();
-
- // Block edges.
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
- // Does this represent entering a call? If so, look at propagating
- // interesting symbols across call boundaries.
- if (NextNode) {
- const LocationContext *CallerCtx = NextNode->getLocationContext();
- const LocationContext *CalleeCtx = PDB.LC;
- if (CallerCtx != CalleeCtx) {
- reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(),
- CalleeCtx, CallerCtx);
- }
- }
+ // Pop the call hierarchy if we are done walking the contents
+ // of a function call.
- // Are we jumping to the head of a loop? Add a special diagnostic.
- if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
- PathDiagnosticLocation L(Loop, SM, PDB.LC);
- const CompoundStmt *CS = nullptr;
-
- if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(FS->getBody());
- else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(WS->getBody());
-
- auto p = std::make_shared<PathDiagnosticEventPiece>(
- L, "Looping back to the head of the loop");
- p->setPrunable(true);
+ // Add an edge to the start of the function.
+ const Decl *D = CE->getCalleeContext()->getDecl();
+ PathDiagnosticLocation pos =
+ PathDiagnosticLocation::createBegin(D, SM);
+ EB.addEdge(pos);
+
+ // Flush all locations, and pop the active path.
+ bool VisitedEntireCall = PD.isWithinCall();
+ EB.flushLocations();
+ PD.popActivePath();
+ PDB.LC = N->getLocationContext();
- EB.addEdge(p->getLocation(), true);
- PD.getActivePath().push_front(std::move(p));
+ // Either we just added a bunch of stuff to the top-level path, or
+ // we have a previous CallExitEnd. If the former, it means that the
+ // path terminated within a function call. We must then take the
+ // current contents of the active path and place it within
+ // a new PathDiagnosticCallPiece.
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ LCM[&C->path] = CE->getCalleeContext();
+ }
- if (CS) {
- PathDiagnosticLocation BL =
- PathDiagnosticLocation::createEndBrace(CS, SM);
- EB.addEdge(BL);
- }
- }
+ C->setCallee(*CE, SM);
+ EB.addContext(C->getLocation());
- const CFGBlock *BSrc = BE->getSrc();
- ParentMap &PM = PDB.getParentMap();
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ return;
+ }
- if (const Stmt *Term = BSrc->getTerminator()) {
- // Are we jumping past the loop body without ever executing the
- // loop (because the condition was false)?
- if (isLoopJumpPastBody(Term, &*BE) &&
- !isInLoopBody(PM,
- getStmtBeforeCond(PM,
- BSrc->getTerminatorCondition(),
- N),
- Term)) {
- PathDiagnosticLocation L(Term, SM, PDB.LC);
- auto PE = std::make_shared<PathDiagnosticEventPiece>(
- L, "Loop body executed 0 times");
- PE->setPrunable(true);
+ // Note that is important that we update the LocationContext
+ // after looking at CallExits. CallExit basically adds an
+ // edge in the *caller*, so we don't want to update the LocationContext
+ // too soon.
+ PDB.LC = N->getLocationContext();
+
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ // Does this represent entering a call? If so, look at propagating
+ // interesting symbols across call boundaries.
+ if (NextNode) {
+ const LocationContext *CallerCtx = NextNode->getLocationContext();
+ const LocationContext *CalleeCtx = PDB.LC;
+ if (CallerCtx != CalleeCtx) {
+ reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
+ N->getState().get(),
+ CalleeCtx, CallerCtx);
+ }
+ }
- EB.addEdge(PE->getLocation(), true);
- PD.getActivePath().push_front(std::move(PE));
- }
+ // Are we jumping to the head of a loop? Add a special diagnostic.
+ if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
+ PathDiagnosticLocation L(Loop, SM, PDB.LC);
+ const CompoundStmt *CS = nullptr;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(FS->getBody());
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(WS->getBody());
+
+ auto p = std::make_shared<PathDiagnosticEventPiece>(
+ L, "Looping back to the head of the loop");
+ p->setPrunable(true);
+
+ EB.addEdge(p->getLocation(), true);
+ PD.getActivePath().push_front(std::move(p));
+
+ if (CS) {
+ PathDiagnosticLocation BL =
+ PathDiagnosticLocation::createEndBrace(CS, SM);
+ EB.addEdge(BL);
+ }
+ }
- // In any case, add the terminator as the current statement
- // context for control edges.
- EB.addContext(Term);
- }
+ const CFGBlock *BSrc = BE->getSrc();
+ ParentMap &PM = PDB.getParentMap();
- break;
+ if (const Stmt *Term = BSrc->getTerminator()) {
+ // Are we jumping past the loop body without ever executing the
+ // loop (because the condition was false)?
+ if (isLoopJumpPastBody(Term, &*BE) &&
+ !isInLoopBody(PM,
+ getStmtBeforeCond(PM,
+ BSrc->getTerminatorCondition(),
+ N),
+ Term)) {
+ PathDiagnosticLocation L(Term, SM, PDB.LC);
+ auto PE = std::make_shared<PathDiagnosticEventPiece>(
+ L, "Loop body executed 0 times");
+ PE->setPrunable(true);
+
+ EB.addEdge(PE->getLocation(), true);
+ PD.getActivePath().push_front(std::move(PE));
+ }
+
+ // In any case, add the terminator as the current statement
+ // context for control edges.
+ EB.addContext(Term);
+ }
+ } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ Optional<CFGElement> First = BE->getFirstElement();
+ if (Optional<CFGStmt> S = First ? First->getAs<CFGStmt>() : None) {
+ const Stmt *stmt = S->getStmt();
+ if (IsControlFlowExpr(stmt)) {
+ // Add the proper context for '&&', '||', and '?'.
+ EB.addContext(stmt);
}
+ else
+ EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
+ }
+ }
+}
- if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
- Optional<CFGElement> First = BE->getFirstElement();
- if (Optional<CFGStmt> S = First ? First->getAs<CFGStmt>() : None) {
- const Stmt *stmt = S->getStmt();
- if (IsControlFlowExpr(stmt)) {
- // Add the proper context for '&&', '||', and '?'.
- EB.addContext(stmt);
- }
- else
- EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
- }
+//===----------------------------------------------------------------------===//
+// Top-level logic for generating extensive path diagnostics.
+//===----------------------------------------------------------------------===//
- break;
- }
+static bool GenerateExtensivePathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
+ EdgeBuilder EB(PD, PDB);
+ StackDiagVector CallStack;
+ InterestingExprs IE;
+ const ExplodedNode *NextNode = N->pred_empty() ? nullptr : *(N->pred_begin());
+ while (NextNode) {
+ N = NextNode;
+ NextNode = N->getFirstPred();
- } while (0);
+ generateExtensiveDiagnosticsForNode(N, PDB, LCM, EB, CallStack, PD, IE);
if (!NextNode)
continue;
@@ -1651,236 +1657,242 @@ static const char StrLoopRangeEmpty[] =
static const char StrLoopCollectionEmpty[] =
"Loop body skipped when collection is empty";
-static bool GenerateAlternateExtensivePathDiagnostic(
- PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
- LocationContextMap &LCM,
- ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
-
- BugReport *report = PDB.getBugReport();
- const SourceManager& SM = PDB.getSourceManager();
- StackDiagVector CallStack;
- InterestingExprs IE;
-
- PathDiagnosticLocation PrevLoc = PD.getLocation();
-
+/// Generate alternate-extensive diagnostics for the node \p N,
+/// and write it into \p PD.
+static void generateAlternateExtensiveDiagnosticsForNode(const ExplodedNode *N,
+ PathDiagnostic &PD,
+ PathDiagnosticLocation &PrevLoc,
+ PathDiagnosticBuilder &PDB,
+ LocationContextMap &LCM,
+ StackDiagVector &CallStack,
+ InterestingExprs &IE) {
const ExplodedNode *NextNode = N->getFirstPred();
- while (NextNode) {
- N = NextNode;
- NextNode = N->getFirstPred();
- ProgramPoint P = N->getLocation();
+ ProgramPoint P = N->getLocation();
+ const SourceManager& SM = PDB.getSourceManager();
- do {
- // Have we encountered an entrance to a call? It may be
- // the case that we have not encountered a matching
- // call exit before this point. This means that the path
- // terminated within the call itself.
- if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
- // Add an edge to the start of the function.
- const StackFrameContext *CalleeLC = CE->getCalleeContext();
- const Decl *D = CalleeLC->getDecl();
- // Add the edge only when the callee has body. We jump to the beginning
- // of the *declaration*, however we expect it to be followed by the
- // body. This isn't the case for autosynthesized property accessors in
- // Objective-C. No need for a similar extra check for CallExit points
- // because the exit edge comes from a statement (i.e. return),
- // not from declaration.
- if (D->hasBody())
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createBegin(D, SM), CalleeLC);
+ // Have we encountered an entrance to a call? It may be
+ // the case that we have not encountered a matching
+ // call exit before this point. This means that the path
+ // terminated within the call itself.
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
+ // Add an edge to the start of the function.
+ const StackFrameContext *CalleeLC = CE->getCalleeContext();
+ const Decl *D = CalleeLC->getDecl();
+ // Add the edge only when the callee has body. We jump to the beginning
+ // of the *declaration*, however we expect it to be followed by the
+ // body. This isn't the case for autosynthesized property accessors in
+ // Objective-C. No need for a similar extra check for CallExit points
+ // because the exit edge comes from a statement (i.e. return),
+ // not from declaration.
+ if (D->hasBody())
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createBegin(D, SM), CalleeLC);
+
+ // Did we visit an entire call?
+ bool VisitedEntireCall = PD.isWithinCall();
+ PD.popActivePath();
+
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ PathDiagnosticPiece *P = PD.getActivePath().front().get();
+ C = cast<PathDiagnosticCallPiece>(P);
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+
+ // Since we just transferred the path over to the call piece,
+ // reset the mapping from active to location context.
+ assert(PD.getActivePath().size() == 1 &&
+ PD.getActivePath().front().get() == C);
+ LCM[&PD.getActivePath()] = nullptr;
+
+ // Record the location context mapping for the path within
+ // the call.
+ assert(LCM[&C->path] == nullptr ||
+ LCM[&C->path] == CE->getCalleeContext());
+ LCM[&C->path] = CE->getCalleeContext();
+
+ // If this is the first item in the active path, record
+ // the new mapping from active path to location context.
+ const LocationContext *&NewLC = LCM[&PD.getActivePath()];
+ if (!NewLC)
+ NewLC = N->getLocationContext();
- // Did we visit an entire call?
- bool VisitedEntireCall = PD.isWithinCall();
- PD.popActivePath();
-
- PathDiagnosticCallPiece *C;
- if (VisitedEntireCall) {
- PathDiagnosticPiece *P = PD.getActivePath().front().get();
- C = cast<PathDiagnosticCallPiece>(P);
- } else {
- const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ PDB.LC = NewLC;
+ }
+ C->setCallee(*CE, SM);
- // Since we just transferred the path over to the call piece,
- // reset the mapping from active to location context.
- assert(PD.getActivePath().size() == 1 &&
- PD.getActivePath().front().get() == C);
- LCM[&PD.getActivePath()] = nullptr;
-
- // Record the location context mapping for the path within
- // the call.
- assert(LCM[&C->path] == nullptr ||
- LCM[&C->path] == CE->getCalleeContext());
- LCM[&C->path] = CE->getCalleeContext();
-
- // If this is the first item in the active path, record
- // the new mapping from active path to location context.
- const LocationContext *&NewLC = LCM[&PD.getActivePath()];
- if (!NewLC)
- NewLC = N->getLocationContext();
+ // Update the previous location in the active path.
+ PrevLoc = C->getLocation();
- PDB.LC = NewLC;
- }
- C->setCallee(*CE, SM);
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ return;
+ }
- // Update the previous location in the active path.
- PrevLoc = C->getLocation();
+ // Query the location context here and the previous location
+ // as processing CallEnter may change the active path.
+ PDB.LC = N->getLocationContext();
+
+ // Record the mapping from the active path to the location
+ // context.
+ assert(!LCM[&PD.getActivePath()] ||
+ LCM[&PD.getActivePath()] == PDB.LC);
+ LCM[&PD.getActivePath()] = PDB.LC;
+
+ // Have we encountered an exit from a function call?
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
+ const Stmt *S = CE->getCalleeContext()->getCallSite();
+ // Propagate the interesting symbols accordingly.
+ if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().get(), Ex,
+ N->getLocationContext());
+ }
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
- }
- break;
+ // We are descending into a call (backwards). Construct
+ // a new call piece to contain the path pieces for that call.
+ auto C = PathDiagnosticCallPiece::construct(N, *CE, SM);
+
+ // Record the location context for this call piece.
+ LCM[&C->path] = CE->getCalleeContext();
+
+ // Add the edge to the return site.
+ addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, PDB.LC);
+ auto *P = C.get();
+ PD.getActivePath().push_front(std::move(C));
+ PrevLoc.invalidate();
+
+ // Make the contents of the call the active path for now.
+ PD.pushActivePath(&P->path);
+ CallStack.push_back(StackDiagPair(P, N));
+ } else if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
+ // For expressions, make sure we propagate the
+ // interesting symbols correctly.
+ if (const Expr *Ex = PS->getStmtAs<Expr>())
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().get(), Ex,
+ N->getLocationContext());
+
+ // Add an edge. If this is an ObjCForCollectionStmt do
+ // not add an edge here as it appears in the CFG both
+ // as a terminator and as a terminator condition.
+ if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation(PS->getStmt(), SM, PDB.LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, L, PDB.LC);
+ }
+ } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ // Does this represent entering a call? If so, look at propagating
+ // interesting symbols across call boundaries.
+ if (NextNode) {
+ const LocationContext *CallerCtx = NextNode->getLocationContext();
+ const LocationContext *CalleeCtx = PDB.LC;
+ if (CallerCtx != CalleeCtx) {
+ reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
+ N->getState().get(),
+ CalleeCtx, CallerCtx);
}
+ }
- // Query the location context here and the previous location
- // as processing CallEnter may change the active path.
- PDB.LC = N->getLocationContext();
-
- // Record the mapping from the active path to the location
- // context.
- assert(!LCM[&PD.getActivePath()] ||
- LCM[&PD.getActivePath()] == PDB.LC);
- LCM[&PD.getActivePath()] = PDB.LC;
-
- // Have we encountered an exit from a function call?
- if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
- const Stmt *S = CE->getCalleeContext()->getCallSite();
- // Propagate the interesting symbols accordingly.
- if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), Ex,
- N->getLocationContext());
- }
-
- // We are descending into a call (backwards). Construct
- // a new call piece to contain the path pieces for that call.
- auto C = PathDiagnosticCallPiece::construct(N, *CE, SM);
-
- // Record the location context for this call piece.
- LCM[&C->path] = CE->getCalleeContext();
-
- // Add the edge to the return site.
- addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, PDB.LC);
- auto *P = C.get();
- PD.getActivePath().push_front(std::move(C));
- PrevLoc.invalidate();
-
- // Make the contents of the call the active path for now.
- PD.pushActivePath(&P->path);
- CallStack.push_back(StackDiagPair(P, N));
- break;
+ // Are we jumping to the head of a loop? Add a special diagnostic.
+ if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
+ PathDiagnosticLocation L(Loop, SM, PDB.LC);
+ const Stmt *Body = nullptr;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+ Body = FS->getBody();
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+ Body = WS->getBody();
+ else if (const ObjCForCollectionStmt *OFS =
+ dyn_cast<ObjCForCollectionStmt>(Loop)) {
+ Body = OFS->getBody();
+ } else if (const CXXForRangeStmt *FRS =
+ dyn_cast<CXXForRangeStmt>(Loop)) {
+ Body = FRS->getBody();
+ }
+ // do-while statements are explicitly excluded here
+
+ auto p = std::make_shared<PathDiagnosticEventPiece>(
+ L, "Looping back to the head "
+ "of the loop");
+ p->setPrunable(true);
+
+ addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC);
+ PD.getActivePath().push_front(std::move(p));
+
+ if (const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createEndBrace(CS, SM),
+ PDB.LC);
}
+ }
- if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
- // For expressions, make sure we propagate the
- // interesting symbols correctly.
- if (const Expr *Ex = PS->getStmtAs<Expr>())
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), Ex,
- N->getLocationContext());
-
- // Add an edge. If this is an ObjCForCollectionStmt do
- // not add an edge here as it appears in the CFG both
- // as a terminator and as a terminator condition.
- if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
- PathDiagnosticLocation L =
- PathDiagnosticLocation(PS->getStmt(), SM, PDB.LC);
- addEdgeToPath(PD.getActivePath(), PrevLoc, L, PDB.LC);
- }
- break;
- }
+ const CFGBlock *BSrc = BE->getSrc();
+ ParentMap &PM = PDB.getParentMap();
- // Block edges.
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
- // Does this represent entering a call? If so, look at propagating
- // interesting symbols across call boundaries.
- if (NextNode) {
- const LocationContext *CallerCtx = NextNode->getLocationContext();
- const LocationContext *CalleeCtx = PDB.LC;
- if (CallerCtx != CalleeCtx) {
- reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(),
- CalleeCtx, CallerCtx);
+ if (const Stmt *Term = BSrc->getTerminator()) {
+ // Are we jumping past the loop body without ever executing the
+ // loop (because the condition was false)?
+ if (isLoop(Term)) {
+ const Stmt *TermCond = getTerminatorCondition(BSrc);
+ bool IsInLoopBody =
+ isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term);
+
+ const char *str = nullptr;
+
+ if (isJumpToFalseBranch(&*BE)) {
+ if (!IsInLoopBody) {
+ if (isa<ObjCForCollectionStmt>(Term)) {
+ str = StrLoopCollectionEmpty;
+ } else if (isa<CXXForRangeStmt>(Term)) {
+ str = StrLoopRangeEmpty;
+ } else {
+ str = StrLoopBodyZero;
+ }
}
+ } else {
+ str = StrEnteringLoop;
}
- // Are we jumping to the head of a loop? Add a special diagnostic.
- if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
- PathDiagnosticLocation L(Loop, SM, PDB.LC);
- const Stmt *Body = nullptr;
-
- if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
- Body = FS->getBody();
- else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
- Body = WS->getBody();
- else if (const ObjCForCollectionStmt *OFS =
- dyn_cast<ObjCForCollectionStmt>(Loop)) {
- Body = OFS->getBody();
- } else if (const CXXForRangeStmt *FRS =
- dyn_cast<CXXForRangeStmt>(Loop)) {
- Body = FRS->getBody();
- }
- // do-while statements are explicitly excluded here
-
- auto p = std::make_shared<PathDiagnosticEventPiece>(
- L, "Looping back to the head "
- "of the loop");
- p->setPrunable(true);
+ if (str) {
+ PathDiagnosticLocation L(TermCond ? TermCond : Term, SM, PDB.LC);
+ auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
+ PE->setPrunable(true);
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PE->getLocation(), PDB.LC);
+ PD.getActivePath().push_front(std::move(PE));
+ }
+ } else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
+ isa<GotoStmt>(Term)) {
+ PathDiagnosticLocation L(Term, SM, PDB.LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, L, PDB.LC);
+ }
+ }
+ }
+}
- addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC);
- PD.getActivePath().push_front(std::move(p));
+static bool GenerateAlternateExtensivePathDiagnostic(
+ PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
- if (const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createEndBrace(CS, SM),
- PDB.LC);
- }
- }
+ BugReport *report = PDB.getBugReport();
+ const SourceManager& SM = PDB.getSourceManager();
+ StackDiagVector CallStack;
+ InterestingExprs IE;
- const CFGBlock *BSrc = BE->getSrc();
- ParentMap &PM = PDB.getParentMap();
+ PathDiagnosticLocation PrevLoc = PD.getLocation();
- if (const Stmt *Term = BSrc->getTerminator()) {
- // Are we jumping past the loop body without ever executing the
- // loop (because the condition was false)?
- if (isLoop(Term)) {
- const Stmt *TermCond = getTerminatorCondition(BSrc);
- bool IsInLoopBody =
- isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term);
-
- const char *str = nullptr;
-
- if (isJumpToFalseBranch(&*BE)) {
- if (!IsInLoopBody) {
- if (isa<ObjCForCollectionStmt>(Term)) {
- str = StrLoopCollectionEmpty;
- } else if (isa<CXXForRangeStmt>(Term)) {
- str = StrLoopRangeEmpty;
- } else {
- str = StrLoopBodyZero;
- }
- }
- } else {
- str = StrEnteringLoop;
- }
+ const ExplodedNode *NextNode = N->getFirstPred();
+ while (NextNode) {
+ N = NextNode;
+ NextNode = N->getFirstPred();
- if (str) {
- PathDiagnosticLocation L(TermCond ? TermCond : Term, SM, PDB.LC);
- auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
- PE->setPrunable(true);
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PE->getLocation(), PDB.LC);
- PD.getActivePath().push_front(std::move(PE));
- }
- } else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
- isa<GotoStmt>(Term)) {
- PathDiagnosticLocation L(Term, SM, PDB.LC);
- addEdgeToPath(PD.getActivePath(), PrevLoc, L, PDB.LC);
- }
- }
- break;
- }
- } while (0);
+ generateAlternateExtensiveDiagnosticsForNode(
+ N, PD, PrevLoc, PDB, LCM, CallStack, IE);
if (!NextNode)
continue;
More information about the cfe-commits
mailing list