AnalyzerStatsChecker.cpp 5.0 KB

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