Index: lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporter.cpp +++ lib/StaticAnalyzer/Core/BugReporter.cpp @@ -556,330 +556,318 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM); -static bool GenerateMinimalPathDiagnostic( - PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, - LocationContextMap &LCM, - ArrayRef> visitors) { +static void generateDiagnosticsForStmt(const Stmt *T, + const ExplodedNode *N, + PathDiagnosticBuilder &PDB, + const LocationContext *LC, + const CFGBlock *Src, + const CFGBlock *Dst, + SourceManager &SMgr, + PathDiagnostic &PD) { + + auto Start = PathDiagnosticLocation::createBegin(T, SMgr, LC); + switch (T->getStmtClass()) { + default: + break; - SourceManager& SMgr = PDB.getSourceManager(); - const LocationContext *LC = PDB.LC; - const ExplodedNode *NextNode = N->pred_empty() - ? nullptr : *(N->pred_begin()); + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: { + const Stmt *S = PathDiagnosticLocation::getNextStmt(N); - StackDiagVector CallStack; - - 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); - do { - if (Optional CE = P.getAs()) { - 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)); - break; - } + os << "Control jumps to line " << End.asLocation().getExpansionLineNumber(); + PD.getActivePath().push_front( + std::make_shared(Start, End, os.str())); + break; + } - if (Optional CE = P.getAs()) { - // Flush all locations, and pop the active path. - bool VisitedEntireCall = PD.isWithinCall(); - PD.popActivePath(); + case Stmt::SwitchStmtClass: { + // Figure out what case arm we took. + std::string sbuf; + llvm::raw_string_ostream os(sbuf); - // 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(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(); - } + if (const Stmt *S = Dst->getLabel()) { + PathDiagnosticLocation End(S, SMgr, LC); - C->setCallee(*CE, SMgr); - if (!CallStack.empty()) { - assert(CallStack.back().first == C); - CallStack.pop_back(); - } + 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 BE = P.getAs()) { - const CFGBlock *Src = BE->getSrc(); - const CFGBlock *Dst = BE->getDst(); - const Stmt *T = Src->getTerminator(); - - if (!T) - break; - - PathDiagnosticLocation Start = - PathDiagnosticLocation::createBegin(T, SMgr, - N->getLocationContext()); - - switch (T->getStmtClass()) { - default: - break; - case Stmt::GotoStmtClass: - case Stmt::IndirectGotoStmtClass: { - const Stmt *S = PathDiagnosticLocation::getNextStmt(N); + case Stmt::CaseStmtClass: { + os << "Control jumps to 'case "; + const CaseStmt *Case = cast(S); + const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); - if (!S) - break; + // Determine if it is an enum. + bool GetRawInt = true; - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S); + if (const DeclRefExpr *DR = dyn_cast(LHS)) { + // FIXME: Maybe this should be an assertion. Are there cases + // were it is not an EnumConstantDecl? + const EnumConstantDecl *D = dyn_cast(DR->getDecl()); - os << "Control jumps to line " - << End.asLocation().getExpansionLineNumber(); - PD.getActivePath().push_front( - std::make_shared(Start, End, - os.str())); - break; + if (D) { + GetRawInt = false; + os << *D; + } } - case Stmt::SwitchStmtClass: { - // Figure out what case arm we took. - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + if (GetRawInt) + os << LHS->EvaluateKnownConstInt(PDB.getASTContext()); - if (const Stmt *S = Dst->getLabel()) { - PathDiagnosticLocation End(S, SMgr, LC); + os << ":' at line " << End.asLocation().getExpansionLineNumber(); + break; + } + } + PD.getActivePath().push_front( + std::make_shared(Start, End, + os.str())); + } else { + os << "'Default' branch taken. "; + const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N); + PD.getActivePath().push_front( + std::make_shared(Start, End, + os.str())); + } - 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; + break; + } - case Stmt::CaseStmtClass: { - os << "Control jumps to 'case "; - const CaseStmt *Case = cast(S); - const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); + 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(Start, End, os.str())); + break; + } - // Determine if it is an enum. - bool GetRawInt = true; + // Determine control-flow for ternary '?'. + case Stmt::BinaryConditionalOperatorClass: + case Stmt::ConditionalOperatorClass: { + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + os << "'?' condition is "; - if (const DeclRefExpr *DR = dyn_cast(LHS)) { - // FIXME: Maybe this should be an assertion. Are there cases - // were it is not an EnumConstantDecl? - const EnumConstantDecl *D = - dyn_cast(DR->getDecl()); + if (*(Src->succ_begin() + 1) == Dst) + os << "false"; + else + os << "true"; - if (D) { - GetRawInt = false; - os << *D; - } - } + PathDiagnosticLocation End = PDB.ExecutionContinues(N); - if (GetRawInt) - os << LHS->EvaluateKnownConstInt(PDB.getASTContext()); + if (const Stmt *S = End.asStmt()) + End = PDB.getEnclosingStmtLocation(S); - os << ":' at line " - << End.asLocation().getExpansionLineNumber(); - break; - } - } - PD.getActivePath().push_front( - std::make_shared(Start, End, - os.str())); - } - else { - os << "'Default' branch taken. "; - const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N); - PD.getActivePath().push_front( - std::make_shared(Start, End, - os.str())); - } + PD.getActivePath().push_front( + std::make_shared(Start, End, os.str())); + break; + } - break; - } + // Determine control-flow for short-circuited '&&' and '||'. + case Stmt::BinaryOperatorClass: { + if (!PDB.supportsLogicalOpControlFlow()) + 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(Start, End, - os.str())); - break; - } + const BinaryOperator *B = cast(T); + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + os << "Left side of '"; - // Determine control-flow for ternary '?'. - case Stmt::BinaryConditionalOperatorClass: - case Stmt::ConditionalOperatorClass: { - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - os << "'?' condition is "; + if (B->getOpcode() == BO_LAnd) { + os << "&&" + << "' is "; - if (*(Src->succ_begin()+1) == Dst) - os << "false"; - else - os << "true"; + 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(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(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(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(Start, End, + os.str())); + } + } - PathDiagnosticLocation End = PDB.ExecutionContinues(N); + break; + } - if (const Stmt *S = End.asStmt()) - End = PDB.getEnclosingStmtLocation(S); + case Stmt::DoStmtClass: { + if (*(Src->succ_begin()) == Dst) { + std::string sbuf; + llvm::raw_string_ostream os(sbuf); - PD.getActivePath().push_front( - std::make_shared(Start, End, - os.str())); - break; - } + os << "Loop condition is true. "; + PathDiagnosticLocation End = PDB.ExecutionContinues(os, N); - // Determine control-flow for short-circuited '&&' and '||'. - case Stmt::BinaryOperatorClass: { - if (!PDB.supportsLogicalOpControlFlow()) - break; + if (const Stmt *S = End.asStmt()) + End = PDB.getEnclosingStmtLocation(S); - const BinaryOperator *B = cast(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(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(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(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(Start, End, - os.str())); - } - } + PD.getActivePath().push_front( + std::make_shared(Start, End, + os.str())); + } else { + PathDiagnosticLocation End = PDB.ExecutionContinues(N); - break; - } + if (const Stmt *S = End.asStmt()) + End = PDB.getEnclosingStmtLocation(S); - case Stmt::DoStmtClass: { - if (*(Src->succ_begin()) == Dst) { - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + PD.getActivePath().push_front( + std::make_shared( + Start, End, "Loop condition is false. Exiting loop")); + } - os << "Loop condition is true. "; - PathDiagnosticLocation End = PDB.ExecutionContinues(os, 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(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(Start, End, - os.str())); - } - else { - PathDiagnosticLocation End = PDB.ExecutionContinues(N); + PD.getActivePath().push_front( + std::make_shared( + 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( - 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); + if (*(Src->succ_begin() + 1) == Dst) + PD.getActivePath().push_front( + std::make_shared( + Start, End, "Taking false branch")); + else + PD.getActivePath().push_front( + std::make_shared( + Start, End, "Taking true branch")); - os << "Loop condition is false. "; - PathDiagnosticLocation End = PDB.ExecutionContinues(os, N); - if (const Stmt *S = End.asStmt()) - End = PDB.getEnclosingStmtLocation(S); + break; + } + } +} - PD.getActivePath().push_front( - std::make_shared(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( - Start, End, "Loop condition is true. Entering loop body")); - } +static bool GenerateMinimalPathDiagnostic( + PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, + LocationContextMap &LCM, + ArrayRef> visitors) { - break; - } + SourceManager& SMgr = PDB.getSourceManager(); + const LocationContext *LC = PDB.LC; + const ExplodedNode *NextNode = N->pred_empty() + ? nullptr : *(N->pred_begin()); - case Stmt::IfStmtClass: { - PathDiagnosticLocation End = PDB.ExecutionContinues(N); + StackDiagVector CallStack; - if (const Stmt *S = End.asStmt()) - End = PDB.getEnclosingStmtLocation(S); + while (NextNode) { + N = NextNode; + PDB.LC = N->getLocationContext(); + NextNode = N->getFirstPred(); - if (*(Src->succ_begin()+1) == Dst) - PD.getActivePath().push_front( - std::make_shared( - Start, End, "Taking false branch")); - else - PD.getActivePath().push_front( - std::make_shared( - Start, End, "Taking true branch")); + ProgramPoint P = N->getLocation(); - break; - } - } + if (Optional CE = P.getAs()) { + 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 CE = P.getAs()) { + // 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(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(); + } + + C->setCallee(*CE, SMgr); + if (!CallStack.empty()) { + assert(CallStack.back().first == C); + CallStack.pop_back(); } - } while(0); + } else if (Optional BE = P.getAs()) { + const CFGBlock *Src = BE->getSrc(); + const CFGBlock *Dst = BE->getDst(); + + if (const Stmt *T = Src->getTerminator()) + generateDiagnosticsForStmt(T, N, PDB, LC, Src, Dst, SMgr, PD); + } if (NextNode) { // Add diagnostic pieces from custom visitors.