blob: 9ee3d02d2663d2c4cfa5cb9ca2d9ac2744f83aee [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//
Jordy Rose5e04bdd2010-07-27 03:39:53 +000013// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
Tom Carec4b5bd82010-07-23 23:04:53 +000014//===----------------------------------------------------------------------===//
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"
Jordy Rose5e04bdd2010-07-27 03:39:53 +000022#include "clang/Basic/Builtins.h"
Tom Carec4b5bd82010-07-23 23:04:53 +000023#include "llvm/ADT/SmallPtrSet.h"
24
25// The number of CFGBlock pointers we want to reserve memory for. This is used
26// once for each function we analyze.
27#define DEFAULT_CFGBLOCKS 256
28
29using namespace clang;
30
31namespace {
32class UnreachableCodeChecker : public CheckerVisitor<UnreachableCodeChecker> {
33public:
34 static void *getTag();
35 void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
36 bool hasWorkRemaining);
37private:
38 static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R);
39 void FindUnreachableEntryPoints(const CFGBlock *CB);
40 void MarkSuccessorsReachable(const CFGBlock *CB);
41
42 llvm::SmallPtrSet<const CFGBlock*, DEFAULT_CFGBLOCKS> reachable;
43 llvm::SmallPtrSet<const CFGBlock*, DEFAULT_CFGBLOCKS> visited;
44};
45}
46
47void *UnreachableCodeChecker::getTag() {
48 static int x = 0;
49 return &x;
50}
51
52void clang::RegisterUnreachableCodeChecker(GRExprEngine &Eng) {
53 Eng.registerCheck(new UnreachableCodeChecker());
54}
55
56void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
57 BugReporter &B,
58 bool hasWorkRemaining) {
59 // Bail out if we didn't cover all paths
60 if (hasWorkRemaining)
61 return;
62
63 CFG *C = 0;
64 // Iterate over ExplodedGraph
65 for (ExplodedGraph::node_iterator I = G.nodes_begin(); I != G.nodes_end();
66 ++I) {
67 const ProgramPoint &P = I->getLocation();
68
69 // Save the CFG if we don't have it already
70 if (!C)
71 C = P.getLocationContext()->getCFG();
72
73 if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
74 const CFGBlock *CB = BE->getBlock();
75 reachable.insert(CB);
76 }
77 }
78
79 // Bail out if we didn't get the CFG
80 if (!C)
81 return;
82
Jordy Rose5e04bdd2010-07-27 03:39:53 +000083 ASTContext &Ctx = B.getContext();
84
Tom Carec4b5bd82010-07-23 23:04:53 +000085 // Find CFGBlocks that were not covered by any node
86 for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
87 const CFGBlock *CB = *I;
88 // Check if the block is unreachable
89 if (!reachable.count(CB)) {
90 // Find the entry points for this block
91 FindUnreachableEntryPoints(CB);
92 // This block may have been pruned; check if we still want to report it
93 if (reachable.count(CB))
94 continue;
95
96 // We found a statement that wasn't covered
97 SourceRange S;
98 SourceLocation SL = GetUnreachableLoc(*CB, S);
99 if (S.getBegin().isMacroID() || S.getEnd().isMacroID() || S.isInvalid()
100 || SL.isInvalid())
101 continue;
Jordy Rose5e04bdd2010-07-27 03:39:53 +0000102
103 // Special case for __builtin_unreachable.
104 // FIXME: This should be extended to include other unreachable markers,
105 // such as llvm_unreachable.
106 if (!CB->empty()) {
107 const Stmt *First = CB->front();
108 if (const CallExpr *CE = dyn_cast<CallExpr>(First)) {
109 if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
110 continue;
111 }
112 }
113
Tom Carec4b5bd82010-07-23 23:04:53 +0000114 B.EmitBasicReport("Unreachable code", "This statement is never executed",
115 SL, S);
116 }
117 }
118}
119
120// Recursively finds the entry point(s) for this dead CFGBlock.
121void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
122 bool allPredecessorsReachable = true;
123
124 visited.insert(CB);
125
126 for (CFGBlock::const_pred_iterator I = CB->pred_begin(); I != CB->pred_end();
127 ++I) {
128 // Recurse over all unreachable blocks
129 if (!reachable.count(*I) && !visited.count(*I)) {
130 FindUnreachableEntryPoints(*I);
131 allPredecessorsReachable = false;
132 }
133 }
134
135 // If at least one predecessor is unreachable, mark this block as reachable
136 // so we don't report this block.
137 if (!allPredecessorsReachable) {
138 reachable.insert(CB);
139 }
140}
141
142// Find the SourceLocation and SourceRange to report this CFGBlock
143SourceLocation UnreachableCodeChecker::GetUnreachableLoc(const CFGBlock &b,
144 SourceRange &R) {
145 const Stmt *S = 0;
146 unsigned sn = 0;
147 R = SourceRange();
148
149 if (sn < b.size())
150 S = b[sn].getStmt();
151 else if (b.getTerminator())
152 S = b.getTerminator();
153 else
154 return SourceLocation();
155
156 R = S->getSourceRange();
157 return S->getLocStart();
158}