AnalyzerStatsChecker.cpp revision 1d26f48dc2eea1c07431ca1519d7034a21b9bcff
152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//
352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//                     The LLVM Compiler Infrastructure
452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//
552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care// This file is distributed under the University of Illinois Open Source
652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care// License. See LICENSE.TXT for details.
752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//
852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//===----------------------------------------------------------------------===//
952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care// This file reports various statistics about analyzer visitation.
1052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care//===----------------------------------------------------------------------===//
1152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
1258f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis#include "ClangSACheckers.h"
13ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
1458f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
159b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
1658f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
179b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18a7af5ea88a6c5bdf87497cca6c20831e8c546751Argyrios Kyrtzidis
1952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care#include "clang/Basic/SourceManager.h"
2052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care#include "llvm/ADT/SmallPtrSet.h"
2152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
2252d861ce41ce84d8389495ea78d97bcc962ac5baTom Careusing namespace clang;
239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
2452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
2552d861ce41ce84d8389495ea78d97bcc962ac5baTom Carenamespace {
26ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
2752d861ce41ce84d8389495ea78d97bcc962ac5baTom Carepublic:
2858f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis  void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
2952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care};
3052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care}
3152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
3258f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidisvoid AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
3352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care                                            BugReporter &B,
3458f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis                                            ExprEngine &Eng) const {
3552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const CFG *C  = 0;
3652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const Decl *D = 0;
3752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const LocationContext *LC = 0;
3852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const SourceManager &SM = B.getSourceManager();
3958f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis  llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
4052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
4152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Iterate over explodedgraph
4252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  for (ExplodedGraph::node_iterator I = G.nodes_begin();
4352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      I != G.nodes_end(); ++I) {
4452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    const ProgramPoint &P = I->getLocation();
4552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    // Save the LocationContext if we don't have it already
4652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    if (!LC)
4752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      LC = P.getLocationContext();
4852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
492cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
502cb5520f62e52f09175f546af12b8b8fb05b81adTom Care      const CFGBlock *CB = BE->getBlock();
5152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      reachable.insert(CB);
5252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    }
5352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  }
5452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
5552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Get the CFG and the Decl of this block
5652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  C = LC->getCFG();
571d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek  D = LC->getAnalysisDeclContext()->getDecl();
5852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
5952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  unsigned total = 0, unreachable = 0;
6052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
6152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Find CFGBlocks that were not covered by any node
6252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
6352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    const CFGBlock *CB = *I;
6452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    ++total;
6552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    // Check if the block is unreachable
6652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    if (!reachable.count(CB)) {
6752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      ++unreachable;
6852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    }
6952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  }
7052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
7152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // We never 'reach' the entry block, so correct the unreachable count
7252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  unreachable--;
7352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
7452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Generate the warning string
7552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  llvm::SmallString<128> buf;
7652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  llvm::raw_svector_ostream output(buf);
7752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
78cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor  if (Loc.isValid()) {
79cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    output << Loc.getFilename() << " : ";
8052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
81cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
82cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor      const NamedDecl *ND = cast<NamedDecl>(D);
83b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer      output << *ND;
84cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    }
85cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    else if (isa<BlockDecl>(D)) {
86cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor      output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
87cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    }
8852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  }
89cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor
9052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
91422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek      << unreachable << " | Exhausted Block: "
92422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek      << (Eng.wasBlocksExhausted() ? "yes" : "no")
9352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      << " | Empty WorkList: "
940e1cd944398c9e9a3d4c0cf5273a126be91830e8Tom Care      << (Eng.hasEmptyWorkList() ? "yes" : "no");
9552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
9652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
97590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      PathDiagnosticLocation(D, SM));
982cb5520f62e52f09175f546af12b8b8fb05b81adTom Care
992cb5520f62e52f09175f546af12b8b8fb05b81adTom Care  // Emit warning for each block we bailed out on
100422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek  typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
101d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis  const CoreEngine &CE = Eng.getCoreEngine();
102422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek  for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
103422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek      E = CE.blocks_exhausted_end(); I != E; ++I) {
1042cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    const BlockEdge &BE =  I->first;
1052cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    const CFGBlock *Exit = BE.getDst();
1062cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    const CFGElement &CE = Exit->front();
1072cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
1082cb5520f62e52f09175f546af12b8b8fb05b81adTom Care      B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
109590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks          "stopped analyzing at this point",
110590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks          PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
1112cb5520f62e52f09175f546af12b8b8fb05b81adTom Care  }
11252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care}
11358f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis
11458f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidisvoid ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
11558f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis  mgr.registerChecker<AnalyzerStatsChecker>();
11658f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis}
117