Clang Project

clang_source_code/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
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
23using namespace clang;
24using namespace ento;
25
26#define DEBUG_TYPE "StatsChecker"
27
28STATISTIC(NumBlocks,
29          "The # of blocks in top level functions");
30STATISTIC(NumBlocksUnreachable,
31          "The # of unreachable blocks in analyzing top level functions");
32
33namespace {
34class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
35public:
36  void checkEndAnalysis(ExplodedGraph &GBugReporter &B,ExprEngine &Engconst;
37};
38}
39
40void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
41                                            BugReporter &B,
42                                            ExprEngine &Engconst {
43  const CFG *C = nullptr;
44  const SourceManager &SM = B.getSourceManager();
45  llvm::SmallPtrSet<const CFGBlock*, 32> reachable;
46
47  // Root node should have the location context of the top most function.
48  const ExplodedNode *GraphRoot = *G.roots_begin();
49  const LocationContext *LC = GraphRoot->getLocation().getLocationContext();
50
51  const Decl *D = LC->getDecl();
52
53  // Iterate over the exploded graph.
54  for (ExplodedGraph::node_iterator I = G.nodes_begin();
55      I != G.nodes_end(); ++I) {
56    const ProgramPoint &P = I->getLocation();
57
58    // Only check the coverage in the top level function (optimization).
59    if (D != P.getLocationContext()->getDecl())
60      continue;
61
62    if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
63      const CFGBlock *CB = BE->getBlock();
64      reachable.insert(CB);
65    }
66  }
67
68  // Get the CFG and the Decl of this block.
69  C = LC->getCFG();
70
71  unsigned total = 0unreachable = 0;
72
73  // Find CFGBlocks that were not covered by any node
74  for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
75    const CFGBlock *CB = *I;
76    ++total;
77    // Check if the block is unreachable
78    if (!reachable.count(CB)) {
79      ++unreachable;
80    }
81  }
82
83  // We never 'reach' the entry block, so correct the unreachable count
84  unreachable--;
85  // There is no BlockEntrance corresponding to the exit block as well, so
86  // assume it is reached as well.
87  unreachable--;
88
89  // Generate the warning string
90  SmallString<128buf;
91  llvm::raw_svector_ostream output(buf);
92  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
93  if (!Loc.isValid())
94    return;
95
96  if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
97    const NamedDecl *ND = cast<NamedDecl>(D);
98    output << *ND;
99  }
100  else if (isa<BlockDecl>(D)) {
101    output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
102  }
103
104  NumBlocksUnreachable += unreachable;
105  NumBlocks += total;
106  std::string NameOfRootFunction = output.str();
107
108  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
109      << unreachable << " | Exhausted Block: "
110      << (Eng.wasBlocksExhausted() ? "yes" : "no")
111      << " | Empty WorkList: "
112      << (Eng.hasEmptyWorkList() ? "yes" : "no");
113
114  B.EmitBasicReport(D, this"Analyzer Statistics""Internal Statistics",
115                    output.str(), PathDiagnosticLocation(D, SM));
116
117  // Emit warning for each block we bailed out on.
118  typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
119  const CoreEngine &CE = Eng.getCoreEngine();
120  for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
121      E = CE.blocks_exhausted_end(); I != E; ++I) {
122    const BlockEdge &BE =  I->first;
123    const CFGBlock *Exit = BE.getDst();
124    if (Exit->empty())
125      continue;
126    const CFGElement &CE = Exit->front();
127    if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
128      SmallString<128bufI;
129      llvm::raw_svector_ostream outputI(bufI);
130      outputI << "(" << NameOfRootFunction << ")" <<
131                 ": The analyzer generated a sink at this point";
132      B.EmitBasicReport(
133          D, this"Sink Point""Internal Statistics", outputI.str(),
134          PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
135    }
136  }
137}
138
139void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
140  mgr.registerChecker<AnalyzerStatsChecker>();
141}
142
143bool ento::shouldRegisterAnalyzerStatsChecker(const LangOptions &LO) {
144  return true;
145}
146