diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index 459ee65..5a13ed0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -24,7 +24,7 @@ #include "clang/AST/ParentMap.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" // The number of CFGBlock pointers we want to reserve memory for. This is used // once for each function we analyze. @@ -54,10 +54,11 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; - + if (Eng.hasWorkRemaining()) return; + const Decl *D = 0; CFG *C = 0; ParentMap *PM = 0; const LocationContext *LC = 0; @@ -67,9 +68,11 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, const ProgramPoint &P = I->getLocation(); LC = P.getLocationContext(); + if (!D) + D = LC->getAnalysisDeclContext()->getDecl(); // Save the CFG if we don't have it already if (!C) - C = LC->getAnalysisContext()->getUnoptimizedCFG(); + C = LC->getAnalysisDeclContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); @@ -80,10 +83,15 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, } // Bail out if we didn't get the CFG or the ParentMap. - if (!C || !PM) + if (!D || !C || !PM) return; - - ASTContext &Ctx = B.getContext(); + + // Don't do anything for template instantiations. Proving that code + // in a template instantiation is unreachable means proving that it is + // unreachable in all instantiations. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isTemplateInstantiation()) + return; // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { @@ -108,6 +116,14 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, if (CB->size() > 0 && isInvalidPath(CB, *PM)) continue; + // It is good practice to always have a "default" label in a "switch", even + // if we should never get there. It can be used to detect errors, for + // instance. Unreachable code directly under a "default" label is therefore + // likely to be a false positive. + if (const Stmt *label = CB->getLabel()) + if (label->getStmtClass() == Stmt::DefaultStmtClass) + continue; + // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. @@ -117,7 +133,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, ci != ce; ++ci) { if (const CFGStmt *S = (*ci).getAs<CFGStmt>()) if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { - if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) { + if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) { foundUnreachable = true; break; } @@ -146,8 +162,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; - B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" - " executed", DL, SR); + B.EmitBasicReport(D, "Unreachable code", "Dead code", + "This statement is never executed", DL, SR); } } |