clang API Documentation

ReachableCode.cpp
Go to the documentation of this file.
00001 //=- ReachableCodePathInsensitive.cpp ---------------------------*- C++ --*-==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements a flow-sensitive, path-insensitive analysis of
00011 // determining reachable blocks within a CFG.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/ADT/BitVector.h"
00016 #include "llvm/ADT/SmallVector.h"
00017 #include "clang/AST/Expr.h"
00018 #include "clang/AST/ExprCXX.h"
00019 #include "clang/AST/ExprObjC.h"
00020 #include "clang/AST/StmtCXX.h"
00021 #include "clang/Analysis/Analyses/ReachableCode.h"
00022 #include "clang/Analysis/CFG.h"
00023 #include "clang/Analysis/AnalysisContext.h"
00024 #include "clang/Basic/SourceManager.h"
00025 
00026 using namespace clang;
00027 
00028 namespace {
00029 class DeadCodeScan {
00030   llvm::BitVector Visited;
00031   llvm::BitVector &Reachable;
00032   llvm::SmallVector<const CFGBlock *, 10> WorkList;
00033   
00034   typedef llvm::SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
00035       DeferredLocsTy;
00036   
00037   DeferredLocsTy DeferredLocs;
00038   
00039 public:
00040   DeadCodeScan(llvm::BitVector &reachable)
00041     : Visited(reachable.size()),
00042       Reachable(reachable) {}
00043   
00044   void enqueue(const CFGBlock *block);  
00045   unsigned scanBackwards(const CFGBlock *Start,
00046                          clang::reachable_code::Callback &CB);
00047   
00048   bool isDeadCodeRoot(const CFGBlock *Block);
00049   
00050   const Stmt *findDeadCode(const CFGBlock *Block);
00051   
00052   void reportDeadCode(const Stmt *S,
00053                       clang::reachable_code::Callback &CB);
00054 };
00055 }
00056 
00057 void DeadCodeScan::enqueue(const CFGBlock *block) {  
00058   unsigned blockID = block->getBlockID();
00059   if (Reachable[blockID] || Visited[blockID])
00060     return;
00061   Visited[blockID] = true;
00062   WorkList.push_back(block);
00063 }
00064 
00065 bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
00066   bool isDeadRoot = true;
00067   
00068   for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
00069         E = Block->pred_end(); I != E; ++I) {
00070     if (const CFGBlock *PredBlock = *I) {
00071       unsigned blockID = PredBlock->getBlockID();
00072       if (Visited[blockID]) {
00073         isDeadRoot = false;
00074         continue;
00075       }
00076       if (!Reachable[blockID]) {
00077         isDeadRoot = false;
00078         Visited[blockID] = true;
00079         WorkList.push_back(PredBlock);
00080         continue;
00081       }
00082     }
00083   }
00084   
00085   return isDeadRoot;
00086 }
00087 
00088 static bool isValidDeadStmt(const Stmt *S) {
00089   if (S->getLocStart().isInvalid())
00090     return false;
00091   if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
00092     return BO->getOpcode() != BO_Comma;
00093   return true;
00094 }
00095 
00096 const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
00097   for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
00098     if (const CFGStmt *CS = I->getAs<CFGStmt>()) {
00099       const Stmt *S = CS->getStmt();
00100       if (isValidDeadStmt(S))
00101         return S;
00102     }
00103   
00104   if (CFGTerminator T = Block->getTerminator()) {
00105     const Stmt *S = T.getStmt();
00106     if (isValidDeadStmt(S))
00107       return S;    
00108   }
00109 
00110   return 0;
00111 }
00112 
00113 static int SrcCmp(const void *p1, const void *p2) {
00114   return
00115     ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
00116     ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
00117 }
00118 
00119 unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
00120                                      clang::reachable_code::Callback &CB) {
00121 
00122   unsigned count = 0;
00123   enqueue(Start);
00124   
00125   while (!WorkList.empty()) {
00126     const CFGBlock *Block = WorkList.pop_back_val();
00127 
00128     // It is possible that this block has been marked reachable after
00129     // it was enqueued.
00130     if (Reachable[Block->getBlockID()])
00131       continue;
00132 
00133     // Look for any dead code within the block.
00134     const Stmt *S = findDeadCode(Block);
00135     
00136     if (!S) {
00137       // No dead code.  Possibly an empty block.  Look at dead predecessors.
00138       for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
00139            E = Block->pred_end(); I != E; ++I) {
00140         if (const CFGBlock *predBlock = *I)
00141           enqueue(predBlock);
00142       }
00143       continue;
00144     }
00145     
00146     // Specially handle macro-expanded code.
00147     if (S->getLocStart().isMacroID()) {
00148       count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
00149       continue;
00150     }
00151 
00152     if (isDeadCodeRoot(Block)) {
00153       reportDeadCode(S, CB);
00154       count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
00155     }
00156     else {
00157       // Record this statement as the possibly best location in a
00158       // strongly-connected component of dead code for emitting a
00159       // warning.
00160       DeferredLocs.push_back(std::make_pair(Block, S));
00161     }
00162   }
00163 
00164   // If we didn't find a dead root, then report the dead code with the
00165   // earliest location.
00166   if (!DeferredLocs.empty()) {
00167     llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
00168     for (DeferredLocsTy::iterator I = DeferredLocs.begin(),
00169           E = DeferredLocs.end(); I != E; ++I) {
00170       const CFGBlock *block = I->first;
00171       if (Reachable[block->getBlockID()])
00172         continue;
00173       reportDeadCode(I->second, CB);
00174       count += clang::reachable_code::ScanReachableFromBlock(block, Reachable);
00175     }
00176   }
00177     
00178   return count;
00179 }
00180 
00181 static SourceLocation GetUnreachableLoc(const Stmt *S,
00182                                         SourceRange &R1,
00183                                         SourceRange &R2) {
00184   R1 = R2 = SourceRange();
00185 
00186   if (const Expr *Ex = dyn_cast<Expr>(S))
00187     S = Ex->IgnoreParenImpCasts();
00188 
00189   switch (S->getStmtClass()) {
00190     case Expr::BinaryOperatorClass: {
00191       const BinaryOperator *BO = cast<BinaryOperator>(S);
00192       return BO->getOperatorLoc();
00193     }
00194     case Expr::UnaryOperatorClass: {
00195       const UnaryOperator *UO = cast<UnaryOperator>(S);
00196       R1 = UO->getSubExpr()->getSourceRange();
00197       return UO->getOperatorLoc();
00198     }
00199     case Expr::CompoundAssignOperatorClass: {
00200       const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
00201       R1 = CAO->getLHS()->getSourceRange();
00202       R2 = CAO->getRHS()->getSourceRange();
00203       return CAO->getOperatorLoc();
00204     }
00205     case Expr::BinaryConditionalOperatorClass:
00206     case Expr::ConditionalOperatorClass: {
00207       const AbstractConditionalOperator *CO =
00208         cast<AbstractConditionalOperator>(S);
00209       return CO->getQuestionLoc();
00210     }
00211     case Expr::MemberExprClass: {
00212       const MemberExpr *ME = cast<MemberExpr>(S);
00213       R1 = ME->getSourceRange();
00214       return ME->getMemberLoc();
00215     }
00216     case Expr::ArraySubscriptExprClass: {
00217       const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
00218       R1 = ASE->getLHS()->getSourceRange();
00219       R2 = ASE->getRHS()->getSourceRange();
00220       return ASE->getRBracketLoc();
00221     }
00222     case Expr::CStyleCastExprClass: {
00223       const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
00224       R1 = CSC->getSubExpr()->getSourceRange();
00225       return CSC->getLParenLoc();
00226     }
00227     case Expr::CXXFunctionalCastExprClass: {
00228       const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
00229       R1 = CE->getSubExpr()->getSourceRange();
00230       return CE->getTypeBeginLoc();
00231     }
00232     case Stmt::CXXTryStmtClass: {
00233       return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
00234     }
00235     case Expr::ObjCBridgedCastExprClass: {
00236       const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
00237       R1 = CSC->getSubExpr()->getSourceRange();
00238       return CSC->getLParenLoc();
00239     }
00240     default: ;
00241   }
00242   R1 = S->getSourceRange();
00243   return S->getLocStart();
00244 }
00245 
00246 void DeadCodeScan::reportDeadCode(const Stmt *S,
00247                                   clang::reachable_code::Callback &CB) {
00248   SourceRange R1, R2;
00249   SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
00250   CB.HandleUnreachable(Loc, R1, R2);
00251 }
00252 
00253 namespace clang { namespace reachable_code {
00254 
00255 void Callback::anchor() { }  
00256 
00257 unsigned ScanReachableFromBlock(const CFGBlock *Start,
00258                                 llvm::BitVector &Reachable) {
00259   unsigned count = 0;
00260   
00261   // Prep work queue
00262   SmallVector<const CFGBlock*, 32> WL;
00263   
00264   // The entry block may have already been marked reachable
00265   // by the caller.
00266   if (!Reachable[Start->getBlockID()]) {
00267     ++count;
00268     Reachable[Start->getBlockID()] = true;
00269   }
00270   
00271   WL.push_back(Start);
00272   
00273   // Find the reachable blocks from 'Start'.
00274   while (!WL.empty()) {
00275     const CFGBlock *item = WL.pop_back_val();
00276     
00277     // Look at the successors and mark then reachable.
00278     for (CFGBlock::const_succ_iterator I = item->succ_begin(), 
00279          E = item->succ_end(); I != E; ++I)
00280       if (const CFGBlock *B = *I) {
00281         unsigned blockID = B->getBlockID();
00282         if (!Reachable[blockID]) {
00283           Reachable.set(blockID);
00284           WL.push_back(B);
00285           ++count;
00286         }
00287       }
00288   }
00289   return count;
00290 }
00291   
00292 void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB) {
00293   CFG *cfg = AC.getCFG();
00294   if (!cfg)
00295     return;
00296 
00297   // Scan for reachable blocks from the entrance of the CFG.  
00298   // If there are no unreachable blocks, we're done.
00299   llvm::BitVector reachable(cfg->getNumBlockIDs());
00300   unsigned numReachable = ScanReachableFromBlock(&cfg->getEntry(), reachable);
00301   if (numReachable == cfg->getNumBlockIDs())
00302     return;
00303   
00304   // If there aren't explicit EH edges, we should include the 'try' dispatch
00305   // blocks as roots.
00306   if (!AC.getCFGBuildOptions().AddEHEdges) {
00307     for (CFG::try_block_iterator I = cfg->try_blocks_begin(),
00308          E = cfg->try_blocks_end() ; I != E; ++I) {
00309       numReachable += ScanReachableFromBlock(*I, reachable);
00310     }
00311     if (numReachable == cfg->getNumBlockIDs())
00312       return;
00313   }
00314 
00315   // There are some unreachable blocks.  We need to find the root blocks that
00316   // contain code that should be considered unreachable.  
00317   for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
00318     const CFGBlock *block = *I;
00319     // A block may have been marked reachable during this loop.
00320     if (reachable[block->getBlockID()])
00321       continue;
00322     
00323     DeadCodeScan DS(reachable);
00324     numReachable += DS.scanBackwards(block, CB);
00325     
00326     if (numReachable == cfg->getNumBlockIDs())
00327       return;
00328   }
00329 }
00330 
00331 }} // end namespace clang::reachable_code