xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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