blob: 2aa1515bf37d90828637984d6727930d8a04439a [file] [log] [blame]
Tom Care52d861c2010-09-10 00:44:44 +00001//==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// This file reports various statistics about analyzer visitation.
10//===----------------------------------------------------------------------===//
11
Argyrios Kyrtzidis98cabba2010-12-22 18:51:49 +000012#include "clang/GR/PathSensitive/CheckerVisitor.h"
13#include "clang/GR/PathSensitive/ExplodedGraph.h"
14#include "clang/GR/BugReporter/BugReporter.h"
Argyrios Kyrtzidisa7af5ea2010-12-22 18:52:56 +000015
16// FIXME: Restructure checker registration.
17#include "Checkers/GRExprEngineExperimentalChecks.h"
18
Tom Care52d861c2010-09-10 00:44:44 +000019#include "clang/Basic/SourceManager.h"
20#include "llvm/ADT/SmallPtrSet.h"
21
22using namespace clang;
23
24namespace {
25class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> {
26public:
27 static void *getTag();
28 void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng);
29
30private:
31 llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
32};
33}
34
35void *AnalyzerStatsChecker::getTag() {
36 static int x = 0;
37 return &x;
38}
39
40void clang::RegisterAnalyzerStatsChecker(GRExprEngine &Eng) {
41 Eng.registerCheck(new AnalyzerStatsChecker());
42}
43
44void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
45 BugReporter &B,
46 GRExprEngine &Eng) {
47 const CFG *C = 0;
48 const Decl *D = 0;
49 const LocationContext *LC = 0;
50 const SourceManager &SM = B.getSourceManager();
51
52 // Iterate over explodedgraph
53 for (ExplodedGraph::node_iterator I = G.nodes_begin();
54 I != G.nodes_end(); ++I) {
55 const ProgramPoint &P = I->getLocation();
56 // Save the LocationContext if we don't have it already
57 if (!LC)
58 LC = P.getLocationContext();
59
Tom Care2cb55202010-09-29 23:48:34 +000060 if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
61 const CFGBlock *CB = BE->getBlock();
Tom Care52d861c2010-09-10 00:44:44 +000062 reachable.insert(CB);
63 }
64 }
65
66 // Get the CFG and the Decl of this block
67 C = LC->getCFG();
68 D = LC->getAnalysisContext()->getDecl();
69
70 unsigned total = 0, unreachable = 0;
71
72 // Find CFGBlocks that were not covered by any node
73 for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
74 const CFGBlock *CB = *I;
75 ++total;
76 // Check if the block is unreachable
77 if (!reachable.count(CB)) {
78 ++unreachable;
79 }
80 }
81
82 // We never 'reach' the entry block, so correct the unreachable count
83 unreachable--;
84
85 // Generate the warning string
86 llvm::SmallString<128> buf;
87 llvm::raw_svector_ostream output(buf);
88 PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
Douglas Gregorcb7b1e12010-11-12 07:15:47 +000089 if (Loc.isValid()) {
90 output << Loc.getFilename() << " : ";
Tom Care52d861c2010-09-10 00:44:44 +000091
Douglas Gregorcb7b1e12010-11-12 07:15:47 +000092 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
93 const NamedDecl *ND = cast<NamedDecl>(D);
94 output << ND;
95 }
96 else if (isa<BlockDecl>(D)) {
97 output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
98 }
Tom Care52d861c2010-09-10 00:44:44 +000099 }
Douglas Gregorcb7b1e12010-11-12 07:15:47 +0000100
Tom Care52d861c2010-09-10 00:44:44 +0000101 output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
102 << unreachable << " | Aborted Block: "
Tom Care0e1cd942010-09-22 21:07:51 +0000103 << (Eng.wasBlockAborted() ? "yes" : "no")
Tom Care52d861c2010-09-10 00:44:44 +0000104 << " | Empty WorkList: "
Tom Care0e1cd942010-09-22 21:07:51 +0000105 << (Eng.hasEmptyWorkList() ? "yes" : "no");
Tom Care52d861c2010-09-10 00:44:44 +0000106
107 B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
108 D->getLocation());
Tom Care2cb55202010-09-29 23:48:34 +0000109
110 // Emit warning for each block we bailed out on
111 typedef GRCoreEngine::BlocksAborted::const_iterator AbortedIterator;
112 const GRCoreEngine &CE = Eng.getCoreEngine();
113 for (AbortedIterator I = CE.blocks_aborted_begin(),
114 E = CE.blocks_aborted_end(); I != E; ++I) {
115 const BlockEdge &BE = I->first;
116 const CFGBlock *Exit = BE.getDst();
117 const CFGElement &CE = Exit->front();
118 if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
119 B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
120 "stopped analyzing at this point", CS->getStmt()->getLocStart());
121 }
Tom Care52d861c2010-09-10 00:44:44 +0000122}