summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Checker/UnreachableCodeChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Checker/UnreachableCodeChecker.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Checker/UnreachableCodeChecker.cpp226
1 files changed, 0 insertions, 226 deletions
diff --git a/contrib/llvm/tools/clang/lib/Checker/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/Checker/UnreachableCodeChecker.cpp
deleted file mode 100644
index 7a56c7f..0000000
--- a/contrib/llvm/tools/clang/lib/Checker/UnreachableCodeChecker.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-//==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// This file implements a generalized unreachable code checker using a
-// path-sensitive analysis. We mark any path visited, and then walk the CFG as a
-// post-analysis to determine what was never visited.
-//
-// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/PathSensitive/ExplodedGraph.h"
-#include "clang/Checker/PathSensitive/SVals.h"
-#include "clang/Checker/PathSensitive/CheckerHelpers.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "GRExprEngineExperimentalChecks.h"
-#include "llvm/ADT/SmallPtrSet.h"
-
-// The number of CFGBlock pointers we want to reserve memory for. This is used
-// once for each function we analyze.
-#define DEFAULT_CFGBLOCKS 256
-
-using namespace clang;
-
-namespace {
-class UnreachableCodeChecker : public CheckerVisitor<UnreachableCodeChecker> {
-public:
- static void *getTag();
- void VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- GRExprEngine &Eng);
-private:
- static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
- void FindUnreachableEntryPoints(const CFGBlock *CB);
- static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
- static inline bool isEmptyCFGBlock(const CFGBlock *CB);
-
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> reachable;
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> visited;
-};
-}
-
-void *UnreachableCodeChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-void clang::RegisterUnreachableCodeChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new UnreachableCodeChecker());
-}
-
-void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- GRExprEngine &Eng) {
- // Bail out if we didn't cover all paths
- if (Eng.hasWorkRemaining())
- return;
-
- CFG *C = 0;
- ParentMap *PM = 0;
- // Iterate over ExplodedGraph
- for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
- I != E; ++I) {
- const ProgramPoint &P = I->getLocation();
- const LocationContext *LC = P.getLocationContext();
-
- // Save the CFG if we don't have it already
- if (!C)
- C = LC->getAnalysisContext()->getUnoptimizedCFG();
- if (!PM)
- PM = &LC->getParentMap();
-
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- const CFGBlock *CB = BE->getBlock();
- reachable.insert(CB->getBlockID());
- }
- }
-
- // Bail out if we didn't get the CFG or the ParentMap.
- if (!C || !PM)
- return;
-
- ASTContext &Ctx = B.getContext();
-
- // Find CFGBlocks that were not covered by any node
- for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
- const CFGBlock *CB = *I;
- // Check if the block is unreachable
- if (reachable.count(CB->getBlockID()))
- continue;
-
- // Check if the block is empty (an artificial block)
- if (isEmptyCFGBlock(CB))
- continue;
-
- // Find the entry points for this block
- FindUnreachableEntryPoints(CB);
-
- // This block may have been pruned; check if we still want to report it
- if (reachable.count(CB->getBlockID()))
- continue;
-
- // Check for false positives
- if (CB->size() > 0 && isInvalidPath(CB, *PM))
- continue;
-
- // Special case for __builtin_unreachable.
- // FIXME: This should be extended to include other unreachable markers,
- // such as llvm_unreachable.
- if (!CB->empty()) {
- const Stmt *First = CB->front();
- if (const CallExpr *CE = dyn_cast<CallExpr>(First)) {
- if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
- continue;
- }
- }
-
- // We found a block that wasn't covered - find the statement to report
- SourceRange SR;
- SourceLocation SL;
- if (const Stmt *S = getUnreachableStmt(CB)) {
- SR = S->getSourceRange();
- SL = S->getLocStart();
- if (SR.isInvalid() || SL.isInvalid())
- continue;
- }
- else
- continue;
-
- // Check if the SourceLocation is in a system header
- const SourceManager &SM = B.getSourceManager();
- if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
- continue;
-
- B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
- " executed", SL, SR);
- }
-}
-
-// Recursively finds the entry point(s) for this dead CFGBlock.
-void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
- bool allPredecessorsReachable = true;
-
- visited.insert(CB->getBlockID());
-
- for (CFGBlock::const_pred_iterator I = CB->pred_begin(); I != CB->pred_end();
- ++I) {
- // Recurse over all unreachable blocks
- if (!reachable.count((*I)->getBlockID())) {
- // At least one predeccessor was unreachable
- allPredecessorsReachable = false;
-
- // Only visit the block once
- if (!visited.count((*I)->getBlockID()))
- FindUnreachableEntryPoints(*I);
- }
- }
-
- // If at least one predecessor is unreachable, mark this block as reachable
- // so we don't report this block.
- if (!allPredecessorsReachable) {
- reachable.insert(CB->getBlockID());
- }
-}
-
-// Find the Stmt* in a CFGBlock for reporting a warning
-const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
- if (CB->size() > 0)
- return CB->front().getStmt();
- else if (const Stmt *S = CB->getTerminator())
- return S;
- else
- return 0;
-}
-
-// Determines if the path to this CFGBlock contained an element that infers this
-// block is a false positive. We assume that FindUnreachableEntryPoints has
-// already marked only the entry points to any dead code, so we need only to
-// find the condition that led to this block (the predecessor of this block.)
-// There will never be more than one predecessor.
-bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
- const ParentMap &PM) {
- // We only expect a predecessor size of 0 or 1. If it is >1, then an external
- // condition has broken our assumption (for example, a sink being placed by
- // another check). In these cases, we choose not to report.
- if (CB->pred_size() > 1)
- return true;
-
- // If there are no predecessors, then this block is trivially unreachable
- if (CB->pred_size() == 0)
- return false;
-
- const CFGBlock *pred = *CB->pred_begin();
-
- // Get the predecessor block's terminator conditon
- const Stmt *cond = pred->getTerminatorCondition();
-
- //assert(cond && "CFGBlock's predecessor has a terminator condition");
- // The previous assertion is invalid in some cases (eg do/while). Leaving
- // reporting of these situations on at the moment to help triage these cases.
- if (!cond)
- return false;
-
- // Run each of the checks on the conditions
- if (containsMacro(cond) || containsEnum(cond)
- || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
- || containsStmt<SizeOfAlignOfExpr>(cond))
- return true;
-
- return false;
-}
-
-// Returns true if the given CFGBlock is empty
-bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
- return CB->getLabel() == 0 // No labels
- && CB->size() == 0 // No statements
- && CB->getTerminator() == 0; // No terminator
-}
OpenPOWER on IntegriCloud