AnalyzerStatsChecker.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // This file reports various statistics about analyzer visitation.
  10. //===----------------------------------------------------------------------===//
  11. #include "ClangSACheckers.h"
  12. #include "clang/AST/DeclObjC.h"
  13. #include "clang/Basic/SourceManager.h"
  14. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  15. #include "clang/StaticAnalyzer/Core/Checker.h"
  16. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  17. #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
  19. #include "llvm/ADT/SmallPtrSet.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/ADT/Statistic.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. using namespace clang;
  24. using namespace ento;
  25. #define DEBUG_TYPE "StatsChecker"
  26. STATISTIC(NumBlocks,
  27. "The # of blocks in top level functions");
  28. STATISTIC(NumBlocksUnreachable,
  29. "The # of unreachable blocks in analyzing top level functions");
  30. namespace {
  31. class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
  32. public:
  33. void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
  34. };
  35. }
  36. void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
  37. BugReporter &B,
  38. ExprEngine &Eng) const {
  39. const CFG *C = nullptr;
  40. const SourceManager &SM = B.getSourceManager();
  41. llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
  42. // Root node should have the location context of the top most function.
  43. const ExplodedNode *GraphRoot = *G.roots_begin();
  44. const LocationContext *LC = GraphRoot->getLocation().getLocationContext();
  45. const Decl *D = LC->getDecl();
  46. // Iterate over the exploded graph.
  47. for (ExplodedGraph::node_iterator I = G.nodes_begin();
  48. I != G.nodes_end(); ++I) {
  49. const ProgramPoint &P = I->getLocation();
  50. // Only check the coverage in the top level function (optimization).
  51. if (D != P.getLocationContext()->getDecl())
  52. continue;
  53. if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
  54. const CFGBlock *CB = BE->getBlock();
  55. reachable.insert(CB);
  56. }
  57. }
  58. // Get the CFG and the Decl of this block.
  59. C = LC->getCFG();
  60. unsigned total = 0, unreachable = 0;
  61. // Find CFGBlocks that were not covered by any node
  62. for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
  63. const CFGBlock *CB = *I;
  64. ++total;
  65. // Check if the block is unreachable
  66. if (!reachable.count(CB)) {
  67. ++unreachable;
  68. }
  69. }
  70. // We never 'reach' the entry block, so correct the unreachable count
  71. unreachable--;
  72. // There is no BlockEntrance corresponding to the exit block as well, so
  73. // assume it is reached as well.
  74. unreachable--;
  75. // Generate the warning string
  76. SmallString<128> buf;
  77. llvm::raw_svector_ostream output(buf);
  78. PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
  79. if (!Loc.isValid())
  80. return;
  81. if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
  82. const NamedDecl *ND = cast<NamedDecl>(D);
  83. output << *ND;
  84. }
  85. else if (isa<BlockDecl>(D)) {
  86. output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
  87. }
  88. NumBlocksUnreachable += unreachable;
  89. NumBlocks += total;
  90. std::string NameOfRootFunction = output.str();
  91. output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
  92. << unreachable << " | Exhausted Block: "
  93. << (Eng.wasBlocksExhausted() ? "yes" : "no")
  94. << " | Empty WorkList: "
  95. << (Eng.hasEmptyWorkList() ? "yes" : "no");
  96. B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics",
  97. output.str(), PathDiagnosticLocation(D, SM));
  98. // Emit warning for each block we bailed out on.
  99. typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
  100. const CoreEngine &CE = Eng.getCoreEngine();
  101. for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
  102. E = CE.blocks_exhausted_end(); I != E; ++I) {
  103. const BlockEdge &BE = I->first;
  104. const CFGBlock *Exit = BE.getDst();
  105. const CFGElement &CE = Exit->front();
  106. if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
  107. SmallString<128> bufI;
  108. llvm::raw_svector_ostream outputI(bufI);
  109. outputI << "(" << NameOfRootFunction << ")" <<
  110. ": The analyzer generated a sink at this point";
  111. B.EmitBasicReport(
  112. D, this, "Sink Point", "Internal Statistics", outputI.str(),
  113. PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
  114. }
  115. }
  116. }
  117. void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
  118. mgr.registerChecker<AnalyzerStatsChecker>();
  119. }