Move the rest of the unreachable code analysis from libSema
to libAnalysis (with only the error reporting in libSema).

llvm-svn: 96893
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 269aaf0..f959e5c 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -14,29 +14,188 @@
 
 #include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/SmallVector.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.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;
 
-/// ScanReachableFromBlock - Mark all blocks reachable from Start.
-/// Returns the total number of blocks that were marked reachable.
-unsigned clang::ScanReachableFromBlock(const CFGBlock &Start,
-                                       llvm::BitVector &Reachable) {
-  unsigned count = 0;
-  llvm::SmallVector<const CFGBlock*, 12> WL;
-  
-  // Prep work queue
-  Reachable.set(Start.getBlockID());
-  ++count;
-  WL.push_back(&Start);
-  
-  // Find the reachable blocks from 'Start'.
+static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
+                                        SourceRange &R2) {
+  const Stmt *S = 0;
+  unsigned sn = 0;
+  R1 = R2 = SourceRange();
+
+top:
+  if (sn < b.size())
+    S = b[sn].getStmt();
+  else if (b.getTerminator())
+    S = b.getTerminator();
+  else
+    return SourceLocation();
+
+  switch (S->getStmtClass()) {
+    case Expr::BinaryOperatorClass: {
+      const BinaryOperator *BO = cast<BinaryOperator>(S);
+      if (BO->getOpcode() == BinaryOperator::Comma) {
+        if (sn+1 < b.size())
+          return b[sn+1].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].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::ConditionalOperatorClass: {
+      const ConditionalOperator *CO = cast<ConditionalOperator>(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 Expr::ImplicitCastExprClass:
+      ++sn;
+      goto top;
+    case Stmt::CXXTryStmtClass: {
+      return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
+    }
+    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
   while (!WL.empty()) {
     const CFGBlock *item = WL.back();
     WL.pop_back();
-    
-    // Look at the successors and mark then reachable.
+
+    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::const_succ_iterator I=item->succ_begin(), E=item->succ_end();
+         I != E; ++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'.
+  while (!WL.empty()) {
+    const CFGBlock *item = WL.back();
+    WL.pop_back();
+
+      // Look at the successors and mark then reachable.
     for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end();
          I != E; ++I)
       if (const CFGBlock *B = *I) {
@@ -50,3 +209,70 @@
   }
   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())) {
+            // 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