forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			291 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //=- 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/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();
 | |
|     }
 | |
|     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
 |