123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- //=- ReachableCodePathInsensitive.cpp ---------------------------*- 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 flow-sensitive, path-insensitive analysis of
- // determining reachable blocks within a CFG.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/BitVector.h"
- #include "llvm/ADT/SmallVector.h"
- #include "clang/AST/Expr.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/ExprObjC.h"
- #include "clang/AST/StmtCXX.h"
- #include "clang/Analysis/Analyses/ReachableCode.h"
- #include "clang/Analysis/CFG.h"
- #include "clang/Analysis/AnalysisContext.h"
- #include "clang/Basic/SourceManager.h"
- using namespace clang;
- static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
- SourceRange &R2) {
- const Stmt *S = 0;
- unsigned sn = 0;
- R1 = R2 = SourceRange();
- if (sn < b.size()) {
- const CFGStmt *CS = b[sn].getAs<CFGStmt>();
- if (!CS)
- return SourceLocation();
- S = CS->getStmt();
- } else if (b.getTerminator())
- S = b.getTerminator();
- else
- return SourceLocation();
- if (const Expr *Ex = dyn_cast<Expr>(S))
- S = Ex->IgnoreParenImpCasts();
- switch (S->getStmtClass()) {
- case Expr::BinaryOperatorClass: {
- const BinaryOperator *BO = cast<BinaryOperator>(S);
- if (BO->getOpcode() == BO_Comma) {
- if (sn+1 < b.size())
- return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart();
- const CFGBlock *n = &b;
- while (1) {
- if (n->getTerminator())
- return n->getTerminator()->getLocStart();
- if (n->succ_size() != 1)
- return SourceLocation();
- n = n[0].succ_begin()[0];
- if (n->pred_size() != 1)
- return SourceLocation();
- if (!n->empty())
- return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart();
- }
- }
- R1 = BO->getLHS()->getSourceRange();
- R2 = BO->getRHS()->getSourceRange();
- return BO->getOperatorLoc();
- }
- case Expr::UnaryOperatorClass: {
- const UnaryOperator *UO = cast<UnaryOperator>(S);
- R1 = UO->getSubExpr()->getSourceRange();
- return UO->getOperatorLoc();
- }
- case Expr::CompoundAssignOperatorClass: {
- const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
- R1 = CAO->getLHS()->getSourceRange();
- R2 = CAO->getRHS()->getSourceRange();
- return CAO->getOperatorLoc();
- }
- case Expr::BinaryConditionalOperatorClass:
- case Expr::ConditionalOperatorClass: {
- const AbstractConditionalOperator *CO =
- cast<AbstractConditionalOperator>(S);
- return CO->getQuestionLoc();
- }
- case Expr::MemberExprClass: {
- const MemberExpr *ME = cast<MemberExpr>(S);
- R1 = ME->getSourceRange();
- return ME->getMemberLoc();
- }
- case Expr::ArraySubscriptExprClass: {
- const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
- R1 = ASE->getLHS()->getSourceRange();
- R2 = ASE->getRHS()->getSourceRange();
- return ASE->getRBracketLoc();
- }
- case Expr::CStyleCastExprClass: {
- const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
- R1 = CSC->getSubExpr()->getSourceRange();
- return CSC->getLParenLoc();
- }
- case Expr::CXXFunctionalCastExprClass: {
- const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
- R1 = CE->getSubExpr()->getSourceRange();
- return CE->getTypeBeginLoc();
- }
- case Stmt::CXXTryStmtClass: {
- return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
- }
- case Expr::ObjCBridgedCastExprClass: {
- const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
- R1 = CSC->getSubExpr()->getSourceRange();
- return CSC->getLParenLoc();
- }
- default: ;
- }
- R1 = S->getSourceRange();
- return S->getLocStart();
- }
- static SourceLocation MarkLiveTop(const CFGBlock *Start,
- llvm::BitVector &reachable,
- SourceManager &SM) {
- // Prep work worklist.
- llvm::SmallVector<const CFGBlock*, 32> WL;
- WL.push_back(Start);
- SourceRange R1, R2;
- SourceLocation top = GetUnreachableLoc(*Start, R1, R2);
- bool FromMainFile = false;
- bool FromSystemHeader = false;
- bool TopValid = false;
- if (top.isValid()) {
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- TopValid = true;
- }
- // Solve
- CFGBlock::FilterOptions FO;
- FO.IgnoreDefaultsWithCoveredEnums = 1;
- while (!WL.empty()) {
- const CFGBlock *item = WL.back();
- WL.pop_back();
- SourceLocation c = GetUnreachableLoc(*item, R1, R2);
- if (c.isValid()
- && (!TopValid
- || (SM.isFromMainFile(c) && !FromMainFile)
- || (FromSystemHeader && !SM.isInSystemHeader(c))
- || SM.isBeforeInTranslationUnit(c, top))) {
- top = c;
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- }
- reachable.set(item->getBlockID());
- for (CFGBlock::filtered_succ_iterator I =
- item->filtered_succ_start_end(FO); I.hasMore(); ++I)
- if (const CFGBlock *B = *I) {
- unsigned blockID = B->getBlockID();
- if (!reachable[blockID]) {
- reachable.set(blockID);
- WL.push_back(B);
- }
- }
- }
- return top;
- }
- static int LineCmp(const void *p1, const void *p2) {
- SourceLocation *Line1 = (SourceLocation *)p1;
- SourceLocation *Line2 = (SourceLocation *)p2;
- return !(*Line1 < *Line2);
- }
- namespace {
- struct ErrLoc {
- SourceLocation Loc;
- SourceRange R1;
- SourceRange R2;
- ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
- : Loc(l), R1(r1), R2(r2) { }
- };
- }
- namespace clang { namespace reachable_code {
- /// ScanReachableFromBlock - Mark all blocks reachable from Start.
- /// Returns the total number of blocks that were marked reachable.
- unsigned ScanReachableFromBlock(const CFGBlock &Start,
- llvm::BitVector &Reachable) {
- unsigned count = 0;
- llvm::SmallVector<const CFGBlock*, 32> WL;
- // Prep work queue
- Reachable.set(Start.getBlockID());
- ++count;
- WL.push_back(&Start);
- // Find the reachable blocks from 'Start'.
- CFGBlock::FilterOptions FO;
- FO.IgnoreDefaultsWithCoveredEnums = 1;
- while (!WL.empty()) {
- const CFGBlock *item = WL.back();
- WL.pop_back();
- // Look at the successors and mark then reachable.
- for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO);
- I.hasMore(); ++I)
- if (const CFGBlock *B = *I) {
- unsigned blockID = B->getBlockID();
- if (!Reachable[blockID]) {
- Reachable.set(blockID);
- ++count;
- WL.push_back(B);
- }
- }
- }
- return count;
- }
- void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
- CFG *cfg = AC.getCFG();
- if (!cfg)
- return;
- // Scan for reachable blocks.
- llvm::BitVector reachable(cfg->getNumBlockIDs());
- unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable);
- // If there are no unreachable blocks, we're done.
- if (numReachable == cfg->getNumBlockIDs())
- return;
- SourceRange R1, R2;
- llvm::SmallVector<ErrLoc, 24> lines;
- bool AddEHEdges = AC.getAddEHEdges();
- // First, give warnings for blocks with no predecessors, as they
- // can't be part of a loop.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!reachable[b.getBlockID()]) {
- if (b.pred_empty()) {
- if (!AddEHEdges
- && dyn_cast_or_null<CXXTryStmt>(b.getTerminator().getStmt())) {
- // When not adding EH edges from calls, catch clauses
- // can otherwise seem dead. Avoid noting them as dead.
- numReachable += ScanReachableFromBlock(b, reachable);
- continue;
- }
- SourceLocation c = GetUnreachableLoc(b, R1, R2);
- if (!c.isValid()) {
- // Blocks without a location can't produce a warning, so don't mark
- // reachable blocks from here as live.
- reachable.set(b.getBlockID());
- ++numReachable;
- continue;
- }
- lines.push_back(ErrLoc(c, R1, R2));
- // Avoid excessive errors by marking everything reachable from here
- numReachable += ScanReachableFromBlock(b, reachable);
- }
- }
- }
- if (numReachable < cfg->getNumBlockIDs()) {
- // And then give warnings for the tops of loops.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!reachable[b.getBlockID()])
- // Avoid excessive errors by marking everything reachable from here
- lines.push_back(ErrLoc(MarkLiveTop(&b, reachable,
- AC.getASTContext().getSourceManager()),
- SourceRange(), SourceRange()));
- }
- }
- llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
- for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end();
- I != E; ++I)
- if (I->Loc.isValid())
- CB.HandleUnreachable(I->Loc, I->R1, I->R2);
- }
- }} // end namespace clang::reachable_code
|