Home | History | Annotate | Line # | Download | only in Checkers
      1      1.1  joerg //==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
      2      1.1  joerg //
      3      1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4      1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5      1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6      1.1  joerg //
      7      1.1  joerg //===----------------------------------------------------------------------===//
      8      1.1  joerg // This file reports various statistics about analyzer visitation.
      9      1.1  joerg //===----------------------------------------------------------------------===//
     10      1.1  joerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
     11      1.1  joerg #include "clang/AST/DeclObjC.h"
     12      1.1  joerg #include "clang/Basic/SourceManager.h"
     13      1.1  joerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
     14      1.1  joerg #include "clang/StaticAnalyzer/Core/Checker.h"
     15      1.1  joerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     16      1.1  joerg #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
     17      1.1  joerg #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
     18      1.1  joerg #include "llvm/ADT/SmallPtrSet.h"
     19      1.1  joerg #include "llvm/ADT/SmallString.h"
     20      1.1  joerg #include "llvm/ADT/Statistic.h"
     21      1.1  joerg #include "llvm/Support/raw_ostream.h"
     22      1.1  joerg 
     23      1.1  joerg using namespace clang;
     24      1.1  joerg using namespace ento;
     25      1.1  joerg 
     26      1.1  joerg #define DEBUG_TYPE "StatsChecker"
     27      1.1  joerg 
     28      1.1  joerg STATISTIC(NumBlocks,
     29      1.1  joerg           "The # of blocks in top level functions");
     30      1.1  joerg STATISTIC(NumBlocksUnreachable,
     31      1.1  joerg           "The # of unreachable blocks in analyzing top level functions");
     32      1.1  joerg 
     33      1.1  joerg namespace {
     34      1.1  joerg class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
     35      1.1  joerg public:
     36      1.1  joerg   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
     37      1.1  joerg };
     38      1.1  joerg }
     39      1.1  joerg 
     40      1.1  joerg void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
     41      1.1  joerg                                             BugReporter &B,
     42      1.1  joerg                                             ExprEngine &Eng) const {
     43      1.1  joerg   const CFG *C = nullptr;
     44      1.1  joerg   const SourceManager &SM = B.getSourceManager();
     45      1.1  joerg   llvm::SmallPtrSet<const CFGBlock*, 32> reachable;
     46      1.1  joerg 
     47      1.1  joerg   // Root node should have the location context of the top most function.
     48      1.1  joerg   const ExplodedNode *GraphRoot = *G.roots_begin();
     49      1.1  joerg   const LocationContext *LC = GraphRoot->getLocation().getLocationContext();
     50      1.1  joerg 
     51      1.1  joerg   const Decl *D = LC->getDecl();
     52      1.1  joerg 
     53      1.1  joerg   // Iterate over the exploded graph.
     54      1.1  joerg   for (ExplodedGraph::node_iterator I = G.nodes_begin();
     55      1.1  joerg       I != G.nodes_end(); ++I) {
     56      1.1  joerg     const ProgramPoint &P = I->getLocation();
     57      1.1  joerg 
     58      1.1  joerg     // Only check the coverage in the top level function (optimization).
     59      1.1  joerg     if (D != P.getLocationContext()->getDecl())
     60      1.1  joerg       continue;
     61      1.1  joerg 
     62      1.1  joerg     if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
     63      1.1  joerg       const CFGBlock *CB = BE->getBlock();
     64      1.1  joerg       reachable.insert(CB);
     65      1.1  joerg     }
     66      1.1  joerg   }
     67      1.1  joerg 
     68      1.1  joerg   // Get the CFG and the Decl of this block.
     69      1.1  joerg   C = LC->getCFG();
     70      1.1  joerg 
     71      1.1  joerg   unsigned total = 0, unreachable = 0;
     72      1.1  joerg 
     73      1.1  joerg   // Find CFGBlocks that were not covered by any node
     74      1.1  joerg   for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
     75      1.1  joerg     const CFGBlock *CB = *I;
     76      1.1  joerg     ++total;
     77      1.1  joerg     // Check if the block is unreachable
     78      1.1  joerg     if (!reachable.count(CB)) {
     79      1.1  joerg       ++unreachable;
     80      1.1  joerg     }
     81      1.1  joerg   }
     82      1.1  joerg 
     83      1.1  joerg   // We never 'reach' the entry block, so correct the unreachable count
     84      1.1  joerg   unreachable--;
     85      1.1  joerg   // There is no BlockEntrance corresponding to the exit block as well, so
     86      1.1  joerg   // assume it is reached as well.
     87      1.1  joerg   unreachable--;
     88      1.1  joerg 
     89      1.1  joerg   // Generate the warning string
     90      1.1  joerg   SmallString<128> buf;
     91      1.1  joerg   llvm::raw_svector_ostream output(buf);
     92      1.1  joerg   PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
     93      1.1  joerg   if (!Loc.isValid())
     94      1.1  joerg     return;
     95      1.1  joerg 
     96      1.1  joerg   if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
     97      1.1  joerg     const NamedDecl *ND = cast<NamedDecl>(D);
     98      1.1  joerg     output << *ND;
     99      1.1  joerg   }
    100      1.1  joerg   else if (isa<BlockDecl>(D)) {
    101      1.1  joerg     output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
    102      1.1  joerg   }
    103      1.1  joerg 
    104      1.1  joerg   NumBlocksUnreachable += unreachable;
    105      1.1  joerg   NumBlocks += total;
    106  1.1.1.2  joerg   std::string NameOfRootFunction = std::string(output.str());
    107      1.1  joerg 
    108      1.1  joerg   output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
    109      1.1  joerg       << unreachable << " | Exhausted Block: "
    110      1.1  joerg       << (Eng.wasBlocksExhausted() ? "yes" : "no")
    111      1.1  joerg       << " | Empty WorkList: "
    112      1.1  joerg       << (Eng.hasEmptyWorkList() ? "yes" : "no");
    113      1.1  joerg 
    114      1.1  joerg   B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics",
    115      1.1  joerg                     output.str(), PathDiagnosticLocation(D, SM));
    116      1.1  joerg 
    117      1.1  joerg   // Emit warning for each block we bailed out on.
    118      1.1  joerg   typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
    119      1.1  joerg   const CoreEngine &CE = Eng.getCoreEngine();
    120      1.1  joerg   for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
    121      1.1  joerg       E = CE.blocks_exhausted_end(); I != E; ++I) {
    122      1.1  joerg     const BlockEdge &BE =  I->first;
    123      1.1  joerg     const CFGBlock *Exit = BE.getDst();
    124      1.1  joerg     if (Exit->empty())
    125      1.1  joerg       continue;
    126      1.1  joerg     const CFGElement &CE = Exit->front();
    127      1.1  joerg     if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
    128      1.1  joerg       SmallString<128> bufI;
    129      1.1  joerg       llvm::raw_svector_ostream outputI(bufI);
    130      1.1  joerg       outputI << "(" << NameOfRootFunction << ")" <<
    131      1.1  joerg                  ": The analyzer generated a sink at this point";
    132      1.1  joerg       B.EmitBasicReport(
    133      1.1  joerg           D, this, "Sink Point", "Internal Statistics", outputI.str(),
    134      1.1  joerg           PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
    135      1.1  joerg     }
    136      1.1  joerg   }
    137      1.1  joerg }
    138      1.1  joerg 
    139      1.1  joerg void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
    140      1.1  joerg   mgr.registerChecker<AnalyzerStatsChecker>();
    141      1.1  joerg }
    142      1.1  joerg 
    143  1.1.1.2  joerg bool ento::shouldRegisterAnalyzerStatsChecker(const CheckerManager &mgr) {
    144      1.1  joerg   return true;
    145      1.1  joerg }
    146