AnalyzerStatsChecker.cpp revision 58f2e7c3c3860e410fa3d8252862ef10be7cdc70
1//==--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 12#include "ClangSACheckers.h" 13#include "clang/StaticAnalyzer/Core/CheckerV2.h" 14#include "clang/StaticAnalyzer/Core/CheckerManager.h" 15#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 16#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 17#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 18 19#include "clang/Basic/SourceManager.h" 20#include "llvm/ADT/SmallPtrSet.h" 21 22using namespace clang; 23using namespace ento; 24 25namespace { 26class AnalyzerStatsChecker : public CheckerV2<check::EndAnalysis> { 27public: 28 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const; 29}; 30} 31 32void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, 33 BugReporter &B, 34 ExprEngine &Eng) const { 35 const CFG *C = 0; 36 const Decl *D = 0; 37 const LocationContext *LC = 0; 38 const SourceManager &SM = B.getSourceManager(); 39 llvm::SmallPtrSet<const CFGBlock*, 256> reachable; 40 41 // Iterate over explodedgraph 42 for (ExplodedGraph::node_iterator I = G.nodes_begin(); 43 I != G.nodes_end(); ++I) { 44 const ProgramPoint &P = I->getLocation(); 45 // Save the LocationContext if we don't have it already 46 if (!LC) 47 LC = P.getLocationContext(); 48 49 if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { 50 const CFGBlock *CB = BE->getBlock(); 51 reachable.insert(CB); 52 } 53 } 54 55 // Get the CFG and the Decl of this block 56 C = LC->getCFG(); 57 D = LC->getAnalysisContext()->getDecl(); 58 59 unsigned total = 0, unreachable = 0; 60 61 // Find CFGBlocks that were not covered by any node 62 for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) { 63 const CFGBlock *CB = *I; 64 ++total; 65 // Check if the block is unreachable 66 if (!reachable.count(CB)) { 67 ++unreachable; 68 } 69 } 70 71 // We never 'reach' the entry block, so correct the unreachable count 72 unreachable--; 73 74 // Generate the warning string 75 llvm::SmallString<128> buf; 76 llvm::raw_svector_ostream output(buf); 77 PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); 78 if (Loc.isValid()) { 79 output << Loc.getFilename() << " : "; 80 81 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 82 const NamedDecl *ND = cast<NamedDecl>(D); 83 output << ND; 84 } 85 else if (isa<BlockDecl>(D)) { 86 output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn(); 87 } 88 } 89 90 output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: " 91 << unreachable << " | Aborted Block: " 92 << (Eng.wasBlockAborted() ? "yes" : "no") 93 << " | Empty WorkList: " 94 << (Eng.hasEmptyWorkList() ? "yes" : "no"); 95 96 B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(), 97 D->getLocation()); 98 99 // Emit warning for each block we bailed out on 100 typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; 101 const CoreEngine &CE = Eng.getCoreEngine(); 102 for (AbortedIterator I = CE.blocks_aborted_begin(), 103 E = CE.blocks_aborted_end(); I != E; ++I) { 104 const BlockEdge &BE = I->first; 105 const CFGBlock *Exit = BE.getDst(); 106 const CFGElement &CE = Exit->front(); 107 if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) 108 B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer " 109 "stopped analyzing at this point", CS->getStmt()->getLocStart()); 110 } 111} 112 113void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) { 114 mgr.registerChecker<AnalyzerStatsChecker>(); 115} 116