1fa0734ecSArgyrios Kyrtzidis //==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
2fa0734ecSArgyrios Kyrtzidis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fa0734ecSArgyrios Kyrtzidis //
7fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
8fa0734ecSArgyrios Kyrtzidis // This file reports various statistics about analyzer visitation.
9fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
1076a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
113a02247dSChandler Carruth #include "clang/AST/DeclObjC.h"
123a02247dSChandler Carruth #include "clang/Basic/SourceManager.h"
133a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
146a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
15560bbb12SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
16f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
17560bbb12SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
18fa0734ecSArgyrios Kyrtzidis #include "llvm/ADT/SmallPtrSet.h"
194903802fSBenjamin Kramer #include "llvm/ADT/SmallString.h"
2006bf78c2SAnna Zaks #include "llvm/ADT/Statistic.h"
21444a1304SBenjamin Kramer #include "llvm/Support/raw_ostream.h"
22fa0734ecSArgyrios Kyrtzidis 
23fa0734ecSArgyrios Kyrtzidis using namespace clang;
24fa0734ecSArgyrios Kyrtzidis using namespace ento;
25fa0734ecSArgyrios Kyrtzidis 
2610346667SChandler Carruth #define DEBUG_TYPE "StatsChecker"
2710346667SChandler Carruth 
2806bf78c2SAnna Zaks STATISTIC(NumBlocks,
2906bf78c2SAnna Zaks           "The # of blocks in top level functions");
3006bf78c2SAnna Zaks STATISTIC(NumBlocksUnreachable,
3106bf78c2SAnna Zaks           "The # of unreachable blocks in analyzing top level functions");
3206bf78c2SAnna Zaks 
33fa0734ecSArgyrios Kyrtzidis namespace {
346a5674ffSArgyrios Kyrtzidis class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
35fa0734ecSArgyrios Kyrtzidis public:
36560bbb12SArgyrios Kyrtzidis   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
37fa0734ecSArgyrios Kyrtzidis };
38fa0734ecSArgyrios Kyrtzidis }
39fa0734ecSArgyrios Kyrtzidis 
checkEndAnalysis(ExplodedGraph & G,BugReporter & B,ExprEngine & Eng) const40560bbb12SArgyrios Kyrtzidis void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
41fa0734ecSArgyrios Kyrtzidis                                             BugReporter &B,
42560bbb12SArgyrios Kyrtzidis                                             ExprEngine &Eng) const {
430dbb783cSCraig Topper   const CFG *C = nullptr;
44fa0734ecSArgyrios Kyrtzidis   const SourceManager &SM = B.getSourceManager();
451d030077SMatthias Braun   llvm::SmallPtrSet<const CFGBlock*, 32> reachable;
46fa0734ecSArgyrios Kyrtzidis 
47395c0dd7SAnna Zaks   // Root node should have the location context of the top most function.
48395c0dd7SAnna Zaks   const ExplodedNode *GraphRoot = *G.roots_begin();
498293bae8SAnna Zaks   const LocationContext *LC = GraphRoot->getLocation().getLocationContext();
508293bae8SAnna Zaks 
518293bae8SAnna Zaks   const Decl *D = LC->getDecl();
52395c0dd7SAnna Zaks 
53395c0dd7SAnna Zaks   // Iterate over the exploded graph.
54fa0734ecSArgyrios Kyrtzidis   for (ExplodedGraph::node_iterator I = G.nodes_begin();
55fa0734ecSArgyrios Kyrtzidis       I != G.nodes_end(); ++I) {
56fa0734ecSArgyrios Kyrtzidis     const ProgramPoint &P = I->getLocation();
57395c0dd7SAnna Zaks 
588293bae8SAnna Zaks     // Only check the coverage in the top level function (optimization).
598293bae8SAnna Zaks     if (D != P.getLocationContext()->getDecl())
60395c0dd7SAnna Zaks       continue;
61fa0734ecSArgyrios Kyrtzidis 
6287396b9bSDavid Blaikie     if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
63fa0734ecSArgyrios Kyrtzidis       const CFGBlock *CB = BE->getBlock();
64fa0734ecSArgyrios Kyrtzidis       reachable.insert(CB);
65fa0734ecSArgyrios Kyrtzidis     }
66fa0734ecSArgyrios Kyrtzidis   }
67fa0734ecSArgyrios Kyrtzidis 
688293bae8SAnna Zaks   // Get the CFG and the Decl of this block.
69fa0734ecSArgyrios Kyrtzidis   C = LC->getCFG();
70fa0734ecSArgyrios Kyrtzidis 
71fa0734ecSArgyrios Kyrtzidis   unsigned total = 0, unreachable = 0;
72fa0734ecSArgyrios Kyrtzidis 
73fa0734ecSArgyrios Kyrtzidis   // Find CFGBlocks that were not covered by any node
74fa0734ecSArgyrios Kyrtzidis   for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
75fa0734ecSArgyrios Kyrtzidis     const CFGBlock *CB = *I;
76fa0734ecSArgyrios Kyrtzidis     ++total;
77fa0734ecSArgyrios Kyrtzidis     // Check if the block is unreachable
78fa0734ecSArgyrios Kyrtzidis     if (!reachable.count(CB)) {
79fa0734ecSArgyrios Kyrtzidis       ++unreachable;
80fa0734ecSArgyrios Kyrtzidis     }
81fa0734ecSArgyrios Kyrtzidis   }
82fa0734ecSArgyrios Kyrtzidis 
83fa0734ecSArgyrios Kyrtzidis   // We never 'reach' the entry block, so correct the unreachable count
84fa0734ecSArgyrios Kyrtzidis   unreachable--;
85395c0dd7SAnna Zaks   // There is no BlockEntrance corresponding to the exit block as well, so
86395c0dd7SAnna Zaks   // assume it is reached as well.
87395c0dd7SAnna Zaks   unreachable--;
88fa0734ecSArgyrios Kyrtzidis 
89fa0734ecSArgyrios Kyrtzidis   // Generate the warning string
902c1dd271SDylan Noblesmith   SmallString<128> buf;
91fa0734ecSArgyrios Kyrtzidis   llvm::raw_svector_ostream output(buf);
92fa0734ecSArgyrios Kyrtzidis   PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
93dc36e616SAnna Zaks   if (!Loc.isValid())
94dc36e616SAnna Zaks     return;
95fa0734ecSArgyrios Kyrtzidis 
96*16be17adSBalazs Benics   if (isa<FunctionDecl, ObjCMethodDecl>(D)) {
97fa0734ecSArgyrios Kyrtzidis     const NamedDecl *ND = cast<NamedDecl>(D);
98b89514a9SBenjamin Kramer     output << *ND;
99*16be17adSBalazs Benics   } else if (isa<BlockDecl>(D)) {
100fa0734ecSArgyrios Kyrtzidis     output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
101fa0734ecSArgyrios Kyrtzidis   }
102fa0734ecSArgyrios Kyrtzidis 
10306bf78c2SAnna Zaks   NumBlocksUnreachable += unreachable;
10406bf78c2SAnna Zaks   NumBlocks += total;
105adcd0268SBenjamin Kramer   std::string NameOfRootFunction = std::string(output.str());
10606bf78c2SAnna Zaks 
107fa0734ecSArgyrios Kyrtzidis   output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
1088f89f7c8STed Kremenek       << unreachable << " | Exhausted Block: "
1098f89f7c8STed Kremenek       << (Eng.wasBlocksExhausted() ? "yes" : "no")
110fa0734ecSArgyrios Kyrtzidis       << " | Empty WorkList: "
111fa0734ecSArgyrios Kyrtzidis       << (Eng.hasEmptyWorkList() ? "yes" : "no");
112fa0734ecSArgyrios Kyrtzidis 
1134aca9b1cSAlexander Kornienko   B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics",
1145a10f08bSTed Kremenek                     output.str(), PathDiagnosticLocation(D, SM));
115fa0734ecSArgyrios Kyrtzidis 
116dc36e616SAnna Zaks   // Emit warning for each block we bailed out on.
1178f89f7c8STed Kremenek   typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
118fa0734ecSArgyrios Kyrtzidis   const CoreEngine &CE = Eng.getCoreEngine();
1198f89f7c8STed Kremenek   for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
1208f89f7c8STed Kremenek       E = CE.blocks_exhausted_end(); I != E; ++I) {
121fa0734ecSArgyrios Kyrtzidis     const BlockEdge &BE =  I->first;
122fa0734ecSArgyrios Kyrtzidis     const CFGBlock *Exit = BE.getDst();
1235184fae0SPeter Szecsi     if (Exit->empty())
1245184fae0SPeter Szecsi       continue;
125fa0734ecSArgyrios Kyrtzidis     const CFGElement &CE = Exit->front();
12600be69abSDavid Blaikie     if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
127dc36e616SAnna Zaks       SmallString<128> bufI;
128dc36e616SAnna Zaks       llvm::raw_svector_ostream outputI(bufI);
129dc36e616SAnna Zaks       outputI << "(" << NameOfRootFunction << ")" <<
130dc36e616SAnna Zaks                  ": The analyzer generated a sink at this point";
13100be69abSDavid Blaikie       B.EmitBasicReport(
1324aca9b1cSAlexander Kornienko           D, this, "Sink Point", "Internal Statistics", outputI.str(),
13300be69abSDavid Blaikie           PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
134fa0734ecSArgyrios Kyrtzidis     }
135fa0734ecSArgyrios Kyrtzidis   }
136dc36e616SAnna Zaks }
137560bbb12SArgyrios Kyrtzidis 
registerAnalyzerStatsChecker(CheckerManager & mgr)138560bbb12SArgyrios Kyrtzidis void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
139560bbb12SArgyrios Kyrtzidis   mgr.registerChecker<AnalyzerStatsChecker>();
140560bbb12SArgyrios Kyrtzidis }
141058a7a45SKristof Umann 
shouldRegisterAnalyzerStatsChecker(const CheckerManager & mgr)142bda3dd0dSKirstóf Umann bool ento::shouldRegisterAnalyzerStatsChecker(const CheckerManager &mgr) {
143058a7a45SKristof Umann   return true;
144058a7a45SKristof Umann }
145