AnalyzerStatsChecker.cpp revision 64394e2cc57d597eafe980bd94b060e2967a1cbd
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
19c35fb7d67d515659ad2325b4f6ec97c9fe64fb63Benjamin Kramer#include "clang/AST/DeclObjC.h"
2052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care#include "clang/Basic/SourceManager.h"
2152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care#include "llvm/ADT/SmallPtrSet.h"
228fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
2352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
2452d861ce41ce84d8389495ea78d97bcc962ac5baTom Careusing namespace clang;
259ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
2652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
2752d861ce41ce84d8389495ea78d97bcc962ac5baTom Carenamespace {
28ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
2952d861ce41ce84d8389495ea78d97bcc962ac5baTom Carepublic:
3058f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis  void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
3152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care};
3252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care}
3352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
3458f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidisvoid AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
3552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care                                            BugReporter &B,
3658f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis                                            ExprEngine &Eng) const {
3752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const CFG *C  = 0;
3852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const Decl *D = 0;
3952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  const SourceManager &SM = B.getSourceManager();
4058f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis  llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
4152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
4264394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  // Root node should have the location context of the top most function.
4364394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  const ExplodedNode *GraphRoot = *G.roots_begin();
4464394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  const LocationContext *LC = GraphRoot->getLocation().getLocationContext();
4564394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks
4664394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  // Iterate over the exploded graph.
4752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  for (ExplodedGraph::node_iterator I = G.nodes_begin();
4852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      I != G.nodes_end(); ++I) {
4952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    const ProgramPoint &P = I->getLocation();
5064394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks
5164394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks    // Only check the coverage in the top level function.
5264394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks    if (LC != P.getLocationContext())
5364394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks      continue;
5452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
552cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
562cb5520f62e52f09175f546af12b8b8fb05b81adTom Care      const CFGBlock *CB = BE->getBlock();
5752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      reachable.insert(CB);
5852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    }
5952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  }
6052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
6152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Get the CFG and the Decl of this block
6252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  C = LC->getCFG();
631d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek  D = LC->getAnalysisDeclContext()->getDecl();
6452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
6552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  unsigned total = 0, unreachable = 0;
6652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
6752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Find CFGBlocks that were not covered by any node
6852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
6952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    const CFGBlock *CB = *I;
7052d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    ++total;
7152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    // Check if the block is unreachable
7252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    if (!reachable.count(CB)) {
7352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      ++unreachable;
7452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care    }
7552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  }
7652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
7752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // We never 'reach' the entry block, so correct the unreachable count
7852d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  unreachable--;
7964394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  // There is no BlockEntrance corresponding to the exit block as well, so
8064394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  // assume it is reached as well.
8164394e2cc57d597eafe980bd94b060e2967a1cbdAnna Zaks  unreachable--;
8252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
8352d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  // Generate the warning string
84f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith  SmallString<128> buf;
8552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  llvm::raw_svector_ostream output(buf);
8652d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
87cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor  if (Loc.isValid()) {
88cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    output << Loc.getFilename() << " : ";
8952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
90cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
91cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor      const NamedDecl *ND = cast<NamedDecl>(D);
92b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer      output << *ND;
93cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    }
94cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    else if (isa<BlockDecl>(D)) {
95cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor      output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
96cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor    }
9752d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  }
98cb7b1e17b63967317ab5cc55682168cf0380519aDouglas Gregor
9952d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
100422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek      << unreachable << " | Exhausted Block: "
101422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek      << (Eng.wasBlocksExhausted() ? "yes" : "no")
10252d861ce41ce84d8389495ea78d97bcc962ac5baTom Care      << " | Empty WorkList: "
1030e1cd944398c9e9a3d4c0cf5273a126be91830e8Tom Care      << (Eng.hasEmptyWorkList() ? "yes" : "no");
10452d861ce41ce84d8389495ea78d97bcc962ac5baTom Care
10552d861ce41ce84d8389495ea78d97bcc962ac5baTom Care  B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
106590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      PathDiagnosticLocation(D, SM));
1072cb5520f62e52f09175f546af12b8b8fb05b81adTom Care
1082cb5520f62e52f09175f546af12b8b8fb05b81adTom Care  // Emit warning for each block we bailed out on
109422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek  typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
110d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis  const CoreEngine &CE = Eng.getCoreEngine();
111422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek  for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
112422ab7a49a9a4252dbc6350e49d7a5708337b9c7Ted Kremenek      E = CE.blocks_exhausted_end(); I != E; ++I) {
1132cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    const BlockEdge &BE =  I->first;
1142cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    const CFGBlock *Exit = BE.getDst();
1152cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    const CFGElement &CE = Exit->front();
1162cb5520f62e52f09175f546af12b8b8fb05b81adTom Care    if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
1172cb5520f62e52f09175f546af12b8b8fb05b81adTom Care      B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
118590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks          "stopped analyzing at this point",
119590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks          PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
1202cb5520f62e52f09175f546af12b8b8fb05b81adTom Care  }
12152d861ce41ce84d8389495ea78d97bcc962ac5baTom Care}
12258f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis
12358f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidisvoid ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
12458f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis  mgr.registerChecker<AnalyzerStatsChecker>();
12558f2e7c3c3860e410fa3d8252862ef10be7cdc70Argyrios Kyrtzidis}
126