blob: 0af49a33fb0cb2ba66c1b70b4fe667f038b9cbd1 [file] [log] [blame]
Tom Carec4b5bd82010-07-23 23:04:53 +00001//==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- 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 implements a generalized unreachable code checker using a
10// path-sensitive analysis. We mark any path visited, and then walk the CFG as a
11// post-analysis to determine what was never visited.
12//
13// A similar flow-sensitive only check exists in Analysis/UnreachableCode.cpp
14//===----------------------------------------------------------------------===//
15
16#include "clang/Checker/PathSensitive/CheckerVisitor.h"
17#include "clang/Checker/PathSensitive/ExplodedGraph.h"
18#include "clang/Checker/PathSensitive/SVals.h"
19#include "clang/Checker/BugReporter/BugReporter.h"
20#include "GRExprEngineExperimentalChecks.h"
21#include "clang/AST/StmtCXX.h"
22#include "llvm/ADT/SmallPtrSet.h"
23
24// The number of CFGBlock pointers we want to reserve memory for. This is used
25// once for each function we analyze.
26#define DEFAULT_CFGBLOCKS 256
27
28using namespace clang;
29
30namespace {
31class UnreachableCodeChecker : public CheckerVisitor<UnreachableCodeChecker> {
32public:
33 static void *getTag();
34 void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
35 bool hasWorkRemaining);
36private:
37 static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R);
38 void FindUnreachableEntryPoints(const CFGBlock *CB);
39 void MarkSuccessorsReachable(const CFGBlock *CB);
40
41 llvm::SmallPtrSet<const CFGBlock*, DEFAULT_CFGBLOCKS> reachable;
42 llvm::SmallPtrSet<const CFGBlock*, DEFAULT_CFGBLOCKS> visited;
43};
44}
45
46void *UnreachableCodeChecker::getTag() {
47 static int x = 0;
48 return &x;
49}
50
51void clang::RegisterUnreachableCodeChecker(GRExprEngine &Eng) {
52 Eng.registerCheck(new UnreachableCodeChecker());
53}
54
55void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
56 BugReporter &B,
57 bool hasWorkRemaining) {
58 // Bail out if we didn't cover all paths
59 if (hasWorkRemaining)
60 return;
61
62 CFG *C = 0;
63 // Iterate over ExplodedGraph
64 for (ExplodedGraph::node_iterator I = G.nodes_begin(); I != G.nodes_end();
65 ++I) {
66 const ProgramPoint &P = I->getLocation();
67
68 // Save the CFG if we don't have it already
69 if (!C)
70 C = P.getLocationContext()->getCFG();
71
72 if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
73 const CFGBlock *CB = BE->getBlock();
74 reachable.insert(CB);
75 }
76 }
77
78 // Bail out if we didn't get the CFG
79 if (!C)
80 return;
81
82 // Find CFGBlocks that were not covered by any node
83 for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
84 const CFGBlock *CB = *I;
85 // Check if the block is unreachable
86 if (!reachable.count(CB)) {
87 // Find the entry points for this block
88 FindUnreachableEntryPoints(CB);
89 // This block may have been pruned; check if we still want to report it
90 if (reachable.count(CB))
91 continue;
92
93 // We found a statement that wasn't covered
94 SourceRange S;
95 SourceLocation SL = GetUnreachableLoc(*CB, S);
96 if (S.getBegin().isMacroID() || S.getEnd().isMacroID() || S.isInvalid()
97 || SL.isInvalid())
98 continue;
99 B.EmitBasicReport("Unreachable code", "This statement is never executed",
100 SL, S);
101 }
102 }
103}
104
105// Recursively finds the entry point(s) for this dead CFGBlock.
106void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
107 bool allPredecessorsReachable = true;
108
109 visited.insert(CB);
110
111 for (CFGBlock::const_pred_iterator I = CB->pred_begin(); I != CB->pred_end();
112 ++I) {
113 // Recurse over all unreachable blocks
114 if (!reachable.count(*I) && !visited.count(*I)) {
115 FindUnreachableEntryPoints(*I);
116 allPredecessorsReachable = false;
117 }
118 }
119
120 // If at least one predecessor is unreachable, mark this block as reachable
121 // so we don't report this block.
122 if (!allPredecessorsReachable) {
123 reachable.insert(CB);
124 }
125}
126
127// Find the SourceLocation and SourceRange to report this CFGBlock
128SourceLocation UnreachableCodeChecker::GetUnreachableLoc(const CFGBlock &b,
129 SourceRange &R) {
130 const Stmt *S = 0;
131 unsigned sn = 0;
132 R = SourceRange();
133
134 if (sn < b.size())
135 S = b[sn].getStmt();
136 else if (b.getTerminator())
137 S = b.getTerminator();
138 else
139 return SourceLocation();
140
141 R = S->getSourceRange();
142 return S->getLocStart();
143}