AnalyzerStatsChecker.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. #include <optional>
  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*, 32> 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 (std::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, ObjCMethodDecl>(D)) {
  82. const NamedDecl *ND = cast<NamedDecl>(D);
  83. output << *ND;
  84. } else if (isa<BlockDecl>(D)) {
  85. output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
  86. }
  87. NumBlocksUnreachable += unreachable;
  88. NumBlocks += total;
  89. std::string NameOfRootFunction = std::string(output.str());
  90. output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
  91. << unreachable << " | Exhausted Block: "
  92. << (Eng.wasBlocksExhausted() ? "yes" : "no")
  93. << " | Empty WorkList: "
  94. << (Eng.hasEmptyWorkList() ? "yes" : "no");
  95. B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics",
  96. output.str(), PathDiagnosticLocation(D, SM));
  97. // Emit warning for each block we bailed out on.
  98. typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
  99. const CoreEngine &CE = Eng.getCoreEngine();
  100. for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
  101. E = CE.blocks_exhausted_end(); I != E; ++I) {
  102. const BlockEdge &BE = I->first;
  103. const CFGBlock *Exit = BE.getDst();
  104. if (Exit->empty())
  105. continue;
  106. const CFGElement &CE = Exit->front();
  107. if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
  108. SmallString<128> bufI;
  109. llvm::raw_svector_ostream outputI(bufI);
  110. outputI << "(" << NameOfRootFunction << ")" <<
  111. ": The analyzer generated a sink at this point";
  112. B.EmitBasicReport(
  113. D, this, "Sink Point", "Internal Statistics", outputI.str(),
  114. PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
  115. }
  116. }
  117. }
  118. void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
  119. mgr.registerChecker<AnalyzerStatsChecker>();
  120. }
  121. bool ento::shouldRegisterAnalyzerStatsChecker(const CheckerManager &mgr) {
  122. return true;
  123. }