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