27 #include "llvm/ADT/SmallSet.h" 29 using namespace clang;
33 class UnreachableCodeChecker :
public Checker<check::EndAnalysis> {
35 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
36 ExprEngine &Eng)
const;
38 typedef llvm::SmallSet<unsigned, 32> CFGBlocksSet;
40 static inline const Stmt *getUnreachableStmt(
const CFGBlock *CB);
41 static void FindUnreachableEntryPoints(
const CFGBlock *CB,
42 CFGBlocksSet &reachable,
43 CFGBlocksSet &visited);
45 static inline bool isEmptyCFGBlock(
const CFGBlock *CB);
49 void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
51 ExprEngine &Eng)
const {
52 CFGBlocksSet reachable, visited;
54 if (Eng.hasWorkRemaining())
57 const Decl *D =
nullptr;
92 if (FD->isTemplateInstantiation())
103 if (isEmptyCFGBlock(CB))
108 FindUnreachableEntryPoints(CB, reachable, visited);
115 if (isInvalidPath(CB, *PM))
123 if (label->getStmtClass() == Stmt::DefaultStmtClass)
130 bool foundUnreachable =
false;
134 if (
const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
135 if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable ||
136 CE->isBuiltinAssumeFalse(Eng.getContext())) {
137 foundUnreachable =
true;
142 if (foundUnreachable)
148 PathDiagnosticLocation DL;
150 if (
const Stmt *S = getUnreachableStmt(CB)) {
153 if (S->getBeginLoc().isMacroID())
154 if (
const auto *I = dyn_cast<IntegerLiteral>(S))
155 if (I->getValue() == 0ULL)
159 SR = S->getSourceRange();
161 SL = DL.asLocation();
173 B.EmitBasicReport(D,
this,
"Unreachable code",
"Dead code",
174 "This statement is never executed", DL, SR);
179 void UnreachableCodeChecker::FindUnreachableEntryPoints(
const CFGBlock *CB,
180 CFGBlocksSet &reachable,
181 CFGBlocksSet &visited) {
189 if (!reachable.count((*I)->getBlockID())) {
193 if (!visited.count((*I)->getBlockID()))
195 FindUnreachableEntryPoints(*I, reachable, visited);
201 const Stmt *UnreachableCodeChecker::getUnreachableStmt(
const CFGBlock *CB) {
204 if (!isa<DeclStmt>(S->getStmt()))
219 bool UnreachableCodeChecker::isInvalidPath(
const CFGBlock *CB,
247 containsStmt<UnaryExprOrTypeTraitExpr>(cond);
251 bool UnreachableCodeChecker::isEmptyCFGBlock(
const CFGBlock *CB) {
257 void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
258 mgr.registerChecker<UnreachableCodeChecker>();
Represents a function declaration or definition.
bool containsStaticLocal(const Stmt *S)
AdjacentBlocks::const_iterator const_pred_iterator
Stmt - This represents one statement.
Defines the SourceManager interface.
unsigned getBlockID() const
Decl - This represents one declaration (or definition), e.g.
Stmt * getParent(Stmt *) const
bool containsBuiltinOffsetOf(const Stmt *S)
virtual bool inTopFrame() const
Return true if the current LocationContext has no caller context.
CFGBlockListTy::const_iterator const_iterator
Represents a single basic block in a source-level CFG.
AllNodesTy::iterator node_iterator
Stmt * getTerminatorCondition(bool StripParens=true)
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
ElementList::const_iterator const_iterator
ParentMap & getParentMap() const
CFG * getUnoptimizedCFG()
Return a version of the CFG without any edges pruned.
CFGTerminator getTerminator()
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Encodes a location in the source.
const Decl * getDecl() const
bool isInExternCSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in an "extern C" system header.
pred_iterator pred_begin()
Dataflow Directional Tag Classes.
unsigned pred_size() const
const LocationContext * getLocationContext() const
bool containsMacro(const Stmt *S)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A trivial tuple used to represent a source range.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
AnalysisDeclContext * getAnalysisDeclContext() const
bool containsEnum(const Stmt *S)
This class handles loading and caching of source files into memory.
Defines enum values for all the target-independent builtin functions.