diff options
Diffstat (limited to 'clang/lib/Analysis')
26 files changed, 10855 insertions, 0 deletions
diff --git a/clang/lib/Analysis/.#CMakeLists.txt b/clang/lib/Analysis/.#CMakeLists.txt new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/lib/Analysis/.#CMakeLists.txt @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/lib/Analysis/.#Interval.cpp b/clang/lib/Analysis/.#Interval.cpp new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/lib/Analysis/.#Interval.cpp @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/lib/Analysis/.#Interval_flymake.cpp b/clang/lib/Analysis/.#Interval_flymake.cpp new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/lib/Analysis/.#Interval_flymake.cpp @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/lib/Analysis/.#LiveVariables.cpp b/clang/lib/Analysis/.#LiveVariables.cpp new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/lib/Analysis/.#LiveVariables.cpp @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/lib/Analysis/.#LiveVariables_flymake.cpp b/clang/lib/Analysis/.#LiveVariables_flymake.cpp new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/lib/Analysis/.#LiveVariables_flymake.cpp @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp new file mode 100644 index 0000000..659cc6d --- /dev/null +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -0,0 +1,463 @@ +//== AnalysisDeclContext.cpp - Analysis context for Path Sens analysis -*- C++ -*-// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisDeclContext, a class that manages the analysis context +// data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ParentMap.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" +#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap; + +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, +                                 const Decl *d, +                                 idx::TranslationUnit *tu, +                                 const CFG::BuildOptions &buildOptions) +  : Manager(Mgr), +    D(d), +    TU(tu), +    cfgBuildOptions(buildOptions), +    forcedBlkExprs(0), +    builtCFG(false), +    builtCompleteCFG(false), +    ReferencedBlockVars(0), +    ManagedAnalyses(0) +{   +  cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; +} + +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, +                                 const Decl *d, +                                 idx::TranslationUnit *tu) +: Manager(Mgr), +  D(d), +  TU(tu), +  forcedBlkExprs(0), +  builtCFG(false), +  builtCompleteCFG(false), +  ReferencedBlockVars(0), +  ManagedAnalyses(0) +{   +  cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; +} + +AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, +                                               bool addImplicitDtors, +                                               bool addInitializers) { +  cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; +  cfgBuildOptions.AddImplicitDtors = addImplicitDtors; +  cfgBuildOptions.AddInitializers = addInitializers; +} + +void AnalysisDeclContextManager::clear() { +  for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) +    delete I->second; +  Contexts.clear(); +} + +Stmt *AnalysisDeclContext::getBody() const { +  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) +    return FD->getBody(); +  else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) +    return MD->getBody(); +  else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) +    return BD->getBody(); +  else if (const FunctionTemplateDecl *FunTmpl +           = dyn_cast_or_null<FunctionTemplateDecl>(D)) +    return FunTmpl->getTemplatedDecl()->getBody(); + +  llvm_unreachable("unknown code decl"); +} + +const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const { +  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) +    return MD->getSelfDecl(); +  if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { +    // See if 'self' was captured by the block. +    for (BlockDecl::capture_const_iterator it = BD->capture_begin(), +         et = BD->capture_end(); it != et; ++it) { +      const VarDecl *VD = it->getVariable(); +      if (VD->getName() == "self") +        return dyn_cast<ImplicitParamDecl>(VD); +    }     +  } + +  return NULL; +} + +void AnalysisDeclContext::registerForcedBlockExpression(const Stmt *stmt) { +  if (!forcedBlkExprs) +    forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs(); +  // Default construct an entry for 'stmt'. +  if (const Expr *e = dyn_cast<Expr>(stmt)) +    stmt = e->IgnoreParens(); +  (void) (*forcedBlkExprs)[stmt]; +} + +const CFGBlock * +AnalysisDeclContext::getBlockForRegisteredExpression(const Stmt *stmt) { +  assert(forcedBlkExprs); +  if (const Expr *e = dyn_cast<Expr>(stmt)) +    stmt = e->IgnoreParens(); +  CFG::BuildOptions::ForcedBlkExprs::const_iterator itr =  +    forcedBlkExprs->find(stmt); +  assert(itr != forcedBlkExprs->end()); +  return itr->second; +} + +CFG *AnalysisDeclContext::getCFG() { +  if (!cfgBuildOptions.PruneTriviallyFalseEdges) +    return getUnoptimizedCFG(); + +  if (!builtCFG) { +    cfg.reset(CFG::buildCFG(D, getBody(), +                            &D->getASTContext(), cfgBuildOptions)); +    // Even when the cfg is not successfully built, we don't +    // want to try building it again. +    builtCFG = true; +  } +  return cfg.get(); +} + +CFG *AnalysisDeclContext::getUnoptimizedCFG() { +  if (!builtCompleteCFG) { +    SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges, +                                  false); +    completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), +                                    cfgBuildOptions)); +    // Even when the cfg is not successfully built, we don't +    // want to try building it again. +    builtCompleteCFG = true; +  } +  return completeCFG.get(); +} + +CFGStmtMap *AnalysisDeclContext::getCFGStmtMap() { +  if (cfgStmtMap) +    return cfgStmtMap.get(); +   +  if (CFG *c = getCFG()) { +    cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap())); +    return cfgStmtMap.get(); +  } +     +  return 0; +} + +CFGReverseBlockReachabilityAnalysis *AnalysisDeclContext::getCFGReachablityAnalysis() { +  if (CFA) +    return CFA.get(); +   +  if (CFG *c = getCFG()) { +    CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c)); +    return CFA.get(); +  } +   +  return 0; +} + +void AnalysisDeclContext::dumpCFG(bool ShowColors) { +    getCFG()->dump(getASTContext().getLangOpts(), ShowColors); +} + +ParentMap &AnalysisDeclContext::getParentMap() { +  if (!PM) +    PM.reset(new ParentMap(getBody())); +  return *PM; +} + +PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() { +  if (!PCA) +    PCA.reset(new PseudoConstantAnalysis(getBody())); +  return PCA.get(); +} + +AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D, +                                                    idx::TranslationUnit *TU) { +  AnalysisDeclContext *&AC = Contexts[D]; +  if (!AC) +    AC = new AnalysisDeclContext(this, D, TU, cfgBuildOptions); +  return AC; +} + +const StackFrameContext * +AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S, +                               const CFGBlock *Blk, unsigned Idx) { +  return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx); +} + +LocationContextManager & AnalysisDeclContext::getLocationContextManager() { +  assert(Manager && +         "Cannot create LocationContexts without an AnalysisDeclContextManager!"); +  return Manager->getLocationContextManager();   +} + +//===----------------------------------------------------------------------===// +// FoldingSet profiling. +//===----------------------------------------------------------------------===// + +void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, +                                    ContextKind ck, +                                    AnalysisDeclContext *ctx, +                                    const LocationContext *parent, +                                    const void *data) { +  ID.AddInteger(ck); +  ID.AddPointer(ctx); +  ID.AddPointer(parent); +  ID.AddPointer(data); +} + +void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { +  Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block, Index); +} + +void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { +  Profile(ID, getAnalysisDeclContext(), getParent(), Enter); +} + +void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { +  Profile(ID, getAnalysisDeclContext(), getParent(), BD); +} + +//===----------------------------------------------------------------------===// +// LocationContext creation. +//===----------------------------------------------------------------------===// + +template <typename LOC, typename DATA> +const LOC* +LocationContextManager::getLocationContext(AnalysisDeclContext *ctx, +                                           const LocationContext *parent, +                                           const DATA *d) { +  llvm::FoldingSetNodeID ID; +  LOC::Profile(ID, ctx, parent, d); +  void *InsertPos; + +  LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + +  if (!L) { +    L = new LOC(ctx, parent, d); +    Contexts.InsertNode(L, InsertPos); +  } +  return L; +} + +const StackFrameContext* +LocationContextManager::getStackFrame(AnalysisDeclContext *ctx, +                                      const LocationContext *parent, +                                      const Stmt *s, +                                      const CFGBlock *blk, unsigned idx) { +  llvm::FoldingSetNodeID ID; +  StackFrameContext::Profile(ID, ctx, parent, s, blk, idx); +  void *InsertPos; +  StackFrameContext *L = +   cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); +  if (!L) { +    L = new StackFrameContext(ctx, parent, s, blk, idx); +    Contexts.InsertNode(L, InsertPos); +  } +  return L; +} + +const ScopeContext * +LocationContextManager::getScope(AnalysisDeclContext *ctx, +                                 const LocationContext *parent, +                                 const Stmt *s) { +  return getLocationContext<ScopeContext, Stmt>(ctx, parent, s); +} + +//===----------------------------------------------------------------------===// +// LocationContext methods. +//===----------------------------------------------------------------------===// + +const StackFrameContext *LocationContext::getCurrentStackFrame() const { +  const LocationContext *LC = this; +  while (LC) { +    if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) +      return SFC; +    LC = LC->getParent(); +  } +  return NULL; +} + +const StackFrameContext * +LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const { +  const LocationContext *LC = this; +  while (LC) { +    if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) { +      if (cast<DeclContext>(SFC->getDecl()) == DC) +        return SFC; +    } +    LC = LC->getParent(); +  } +  return NULL; +} + +bool LocationContext::isParentOf(const LocationContext *LC) const { +  do { +    const LocationContext *Parent = LC->getParent(); +    if (Parent == this) +      return true; +    else +      LC = Parent; +  } while (LC); + +  return false; +} + +//===----------------------------------------------------------------------===// +// Lazily generated map to query the external variables referenced by a Block. +//===----------------------------------------------------------------------===// + +namespace { +class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{ +  BumpVector<const VarDecl*> &BEVals; +  BumpVectorContext &BC; +  llvm::SmallPtrSet<const VarDecl*, 4> Visited; +  llvm::SmallPtrSet<const DeclContext*, 4> IgnoredContexts; +public: +  FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals, +                            BumpVectorContext &bc) +  : BEVals(bevals), BC(bc) {} + +  bool IsTrackedDecl(const VarDecl *VD) { +    const DeclContext *DC = VD->getDeclContext(); +    return IgnoredContexts.count(DC) == 0; +  } + +  void VisitStmt(Stmt *S) { +    for (Stmt::child_range I = S->children(); I; ++I) +      if (Stmt *child = *I) +        Visit(child); +  } + +  void VisitDeclRefExpr(DeclRefExpr *DR) { +    // Non-local variables are also directly modified. +    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { +      if (!VD->hasLocalStorage()) { +        if (Visited.insert(VD)) +          BEVals.push_back(VD, BC); +      } else if (DR->refersToEnclosingLocal()) { +        if (Visited.insert(VD) && IsTrackedDecl(VD)) +          BEVals.push_back(VD, BC); +      } +    } +  } + +  void VisitBlockExpr(BlockExpr *BR) { +    // Blocks containing blocks can transitively capture more variables. +    IgnoredContexts.insert(BR->getBlockDecl()); +    Visit(BR->getBlockDecl()->getBody()); +  } +   +  void VisitPseudoObjectExpr(PseudoObjectExpr *PE) { +    for (PseudoObjectExpr::semantics_iterator it = PE->semantics_begin(),  +         et = PE->semantics_end(); it != et; ++it) { +      Expr *Semantic = *it; +      if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic)) +        Semantic = OVE->getSourceExpr(); +      Visit(Semantic); +    } +  } +}; +} // end anonymous namespace + +typedef BumpVector<const VarDecl*> DeclVec; + +static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, +                                              void *&Vec, +                                              llvm::BumpPtrAllocator &A) { +  if (Vec) +    return (DeclVec*) Vec; + +  BumpVectorContext BC(A); +  DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>(); +  new (BV) DeclVec(BC, 10); + +  // Find the referenced variables. +  FindBlockDeclRefExprsVals F(*BV, BC); +  F.Visit(BD->getBody()); + +  Vec = BV; +  return BV; +} + +std::pair<AnalysisDeclContext::referenced_decls_iterator, +          AnalysisDeclContext::referenced_decls_iterator> +AnalysisDeclContext::getReferencedBlockVars(const BlockDecl *BD) { +  if (!ReferencedBlockVars) +    ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>(); + +  DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); +  return std::make_pair(V->begin(), V->end()); +} + +ManagedAnalysis *&AnalysisDeclContext::getAnalysisImpl(const void *tag) { +  if (!ManagedAnalyses) +    ManagedAnalyses = new ManagedAnalysisMap(); +  ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses; +  return (*M)[tag]; +} + +//===----------------------------------------------------------------------===// +// Cleanup. +//===----------------------------------------------------------------------===// + +ManagedAnalysis::~ManagedAnalysis() {} + +AnalysisDeclContext::~AnalysisDeclContext() { +  delete forcedBlkExprs; +  delete ReferencedBlockVars; +  // Release the managed analyses. +  if (ManagedAnalyses) { +    ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses; +    for (ManagedAnalysisMap::iterator I = M->begin(), E = M->end(); I!=E; ++I) +      delete I->second;   +    delete M; +  } +} + +AnalysisDeclContextManager::~AnalysisDeclContextManager() { +  for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) +    delete I->second; +} + +LocationContext::~LocationContext() {} + +LocationContextManager::~LocationContextManager() { +  clear(); +} + +void LocationContextManager::clear() { +  for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), +       E = Contexts.end(); I != E; ) { +    LocationContext *LC = &*I; +    ++I; +    delete LC; +  } + +  Contexts.clear(); +} + diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp new file mode 100644 index 0000000..2f1f1cb --- /dev/null +++ b/clang/lib/Analysis/CFG.cpp @@ -0,0 +1,3977 @@ +//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file defines the CFG and CFGBuilder classes for representing and +//  building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/SaveAndRestore.h" +#include "clang/Analysis/CFG.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/CharUnits.h" +#include "clang/Basic/AttrKinds.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Format.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" + +using namespace clang; + +namespace { + +static SourceLocation GetEndLoc(Decl *D) { +  if (VarDecl *VD = dyn_cast<VarDecl>(D)) +    if (Expr *Ex = VD->getInit()) +      return Ex->getSourceRange().getEnd(); +  return D->getLocation(); +} + +class CFGBuilder; +   +/// The CFG builder uses a recursive algorithm to build the CFG.  When +///  we process an expression, sometimes we know that we must add the +///  subexpressions as block-level expressions.  For example: +/// +///    exp1 || exp2 +/// +///  When processing the '||' expression, we know that exp1 and exp2 +///  need to be added as block-level expressions, even though they +///  might not normally need to be.  AddStmtChoice records this +///  contextual information.  If AddStmtChoice is 'NotAlwaysAdd', then +///  the builder has an option not to add a subexpression as a +///  block-level expression. +/// +class AddStmtChoice { +public: +  enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 }; + +  AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {} + +  bool alwaysAdd(CFGBuilder &builder, +                 const Stmt *stmt) const; + +  /// Return a copy of this object, except with the 'always-add' bit +  ///  set as specified. +  AddStmtChoice withAlwaysAdd(bool alwaysAdd) const { +    return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd); +  } + +private: +  Kind kind; +}; + +/// LocalScope - Node in tree of local scopes created for C++ implicit +/// destructor calls generation. It contains list of automatic variables +/// declared in the scope and link to position in previous scope this scope +/// began in. +/// +/// The process of creating local scopes is as follows: +/// - Init CFGBuilder::ScopePos with invalid position (equivalent for null), +/// - Before processing statements in scope (e.g. CompoundStmt) create +///   LocalScope object using CFGBuilder::ScopePos as link to previous scope +///   and set CFGBuilder::ScopePos to the end of new scope, +/// - On every occurrence of VarDecl increase CFGBuilder::ScopePos if it points +///   at this VarDecl, +/// - For every normal (without jump) end of scope add to CFGBlock destructors +///   for objects in the current scope, +/// - For every jump add to CFGBlock destructors for objects +///   between CFGBuilder::ScopePos and local scope position saved for jump +///   target. Thanks to C++ restrictions on goto jumps we can be sure that +///   jump target position will be on the path to root from CFGBuilder::ScopePos +///   (adding any variable that doesn't need constructor to be called to +///   LocalScope can break this assumption), +/// +class LocalScope { +public: +  typedef BumpVector<VarDecl*> AutomaticVarsTy; + +  /// const_iterator - Iterates local scope backwards and jumps to previous +  /// scope on reaching the beginning of currently iterated scope. +  class const_iterator { +    const LocalScope* Scope; + +    /// VarIter is guaranteed to be greater then 0 for every valid iterator. +    /// Invalid iterator (with null Scope) has VarIter equal to 0. +    unsigned VarIter; + +  public: +    /// Create invalid iterator. Dereferencing invalid iterator is not allowed. +    /// Incrementing invalid iterator is allowed and will result in invalid +    /// iterator. +    const_iterator() +        : Scope(NULL), VarIter(0) {} + +    /// Create valid iterator. In case when S.Prev is an invalid iterator and +    /// I is equal to 0, this will create invalid iterator. +    const_iterator(const LocalScope& S, unsigned I) +        : Scope(&S), VarIter(I) { +      // Iterator to "end" of scope is not allowed. Handle it by going up +      // in scopes tree possibly up to invalid iterator in the root. +      if (VarIter == 0 && Scope) +        *this = Scope->Prev; +    } + +    VarDecl *const* operator->() const { +      assert (Scope && "Dereferencing invalid iterator is not allowed"); +      assert (VarIter != 0 && "Iterator has invalid value of VarIter member"); +      return &Scope->Vars[VarIter - 1]; +    } +    VarDecl *operator*() const { +      return *this->operator->(); +    } + +    const_iterator &operator++() { +      if (!Scope) +        return *this; + +      assert (VarIter != 0 && "Iterator has invalid value of VarIter member"); +      --VarIter; +      if (VarIter == 0) +        *this = Scope->Prev; +      return *this; +    } +    const_iterator operator++(int) { +      const_iterator P = *this; +      ++*this; +      return P; +    } + +    bool operator==(const const_iterator &rhs) const { +      return Scope == rhs.Scope && VarIter == rhs.VarIter; +    } +    bool operator!=(const const_iterator &rhs) const { +      return !(*this == rhs); +    } + +    operator bool() const { +      return *this != const_iterator(); +    } + +    int distance(const_iterator L); +  }; + +  friend class const_iterator; + +private: +  BumpVectorContext ctx; +   +  /// Automatic variables in order of declaration. +  AutomaticVarsTy Vars; +  /// Iterator to variable in previous scope that was declared just before +  /// begin of this scope. +  const_iterator Prev; + +public: +  /// Constructs empty scope linked to previous scope in specified place. +  LocalScope(BumpVectorContext &ctx, const_iterator P) +      : ctx(ctx), Vars(ctx, 4), Prev(P) {} + +  /// Begin of scope in direction of CFG building (backwards). +  const_iterator begin() const { return const_iterator(*this, Vars.size()); } + +  void addVar(VarDecl *VD) { +    Vars.push_back(VD, ctx); +  } +}; + +/// distance - Calculates distance from this to L. L must be reachable from this +/// (with use of ++ operator). Cost of calculating the distance is linear w.r.t. +/// number of scopes between this and L. +int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { +  int D = 0; +  const_iterator F = *this; +  while (F.Scope != L.Scope) { +    assert (F != const_iterator() +        && "L iterator is not reachable from F iterator."); +    D += F.VarIter; +    F = F.Scope->Prev; +  } +  D += F.VarIter - L.VarIter; +  return D; +} + +/// BlockScopePosPair - Structure for specifying position in CFG during its +/// build process. It consists of CFGBlock that specifies position in CFG graph +/// and  LocalScope::const_iterator that specifies position in LocalScope graph. +struct BlockScopePosPair { +  BlockScopePosPair() : block(0) {} +  BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos) +      : block(b), scopePosition(scopePos) {} + +  CFGBlock *block; +  LocalScope::const_iterator scopePosition; +}; + +/// TryResult - a class representing a variant over the values +///  'true', 'false', or 'unknown'.  This is returned by tryEvaluateBool, +///  and is used by the CFGBuilder to decide if a branch condition +///  can be decided up front during CFG construction. +class TryResult { +  int X; +public: +  TryResult(bool b) : X(b ? 1 : 0) {} +  TryResult() : X(-1) {} +   +  bool isTrue() const { return X == 1; } +  bool isFalse() const { return X == 0; } +  bool isKnown() const { return X >= 0; } +  void negate() { +    assert(isKnown()); +    X ^= 0x1; +  } +}; + +/// CFGBuilder - This class implements CFG construction from an AST. +///   The builder is stateful: an instance of the builder should be used to only +///   construct a single CFG. +/// +///   Example usage: +/// +///     CFGBuilder builder; +///     CFG* cfg = builder.BuildAST(stmt1); +/// +///  CFG construction is done via a recursive walk of an AST.  We actually parse +///  the AST in reverse order so that the successor of a basic block is +///  constructed prior to its predecessor.  This allows us to nicely capture +///  implicit fall-throughs without extra basic blocks. +/// +class CFGBuilder { +  typedef BlockScopePosPair JumpTarget; +  typedef BlockScopePosPair JumpSource; + +  ASTContext *Context; +  OwningPtr<CFG> cfg; + +  CFGBlock *Block; +  CFGBlock *Succ; +  JumpTarget ContinueJumpTarget; +  JumpTarget BreakJumpTarget; +  CFGBlock *SwitchTerminatedBlock; +  CFGBlock *DefaultCaseBlock; +  CFGBlock *TryTerminatedBlock; +   +  // Current position in local scope. +  LocalScope::const_iterator ScopePos; + +  // LabelMap records the mapping from Label expressions to their jump targets. +  typedef llvm::DenseMap<LabelDecl*, JumpTarget> LabelMapTy; +  LabelMapTy LabelMap; + +  // A list of blocks that end with a "goto" that must be backpatched to their +  // resolved targets upon completion of CFG construction. +  typedef std::vector<JumpSource> BackpatchBlocksTy; +  BackpatchBlocksTy BackpatchBlocks; + +  // A list of labels whose address has been taken (for indirect gotos). +  typedef llvm::SmallPtrSet<LabelDecl*, 5> LabelSetTy; +  LabelSetTy AddressTakenLabels; + +  bool badCFG; +  const CFG::BuildOptions &BuildOpts; +   +  // State to track for building switch statements. +  bool switchExclusivelyCovered; +  Expr::EvalResult *switchCond; +   +  CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry; +  const Stmt *lastLookup; + +  // Caches boolean evaluations of expressions to avoid multiple re-evaluations +  // during construction of branches for chained logical operators. +  typedef llvm::DenseMap<Expr *, TryResult> CachedBoolEvalsTy; +  CachedBoolEvalsTy CachedBoolEvals; + +public: +  explicit CFGBuilder(ASTContext *astContext, +                      const CFG::BuildOptions &buildOpts)  +    : Context(astContext), cfg(new CFG()), // crew a new CFG +      Block(NULL), Succ(NULL), +      SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL), +      TryTerminatedBlock(NULL), badCFG(false), BuildOpts(buildOpts),  +      switchExclusivelyCovered(false), switchCond(0), +      cachedEntry(0), lastLookup(0) {} + +  // buildCFG - Used by external clients to construct the CFG. +  CFG* buildCFG(const Decl *D, Stmt *Statement); + +  bool alwaysAdd(const Stmt *stmt); +   +private: +  // Visitors to walk an AST and construct the CFG. +  CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); +  CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); +  CFGBlock *VisitBreakStmt(BreakStmt *B); +  CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); +  CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, +      AddStmtChoice asc); +  CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); +  CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); +  CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S); +  CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,  +                                      AddStmtChoice asc); +  CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc); +  CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E, +                                       AddStmtChoice asc); +  CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,  +                                        AddStmtChoice asc); +  CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); +  CFGBlock *VisitCaseStmt(CaseStmt *C); +  CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); +  CFGBlock *VisitCompoundStmt(CompoundStmt *C); +  CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *C, +                                     AddStmtChoice asc); +  CFGBlock *VisitContinueStmt(ContinueStmt *C); +  CFGBlock *VisitDeclStmt(DeclStmt *DS); +  CFGBlock *VisitDeclSubExpr(DeclStmt *DS); +  CFGBlock *VisitDefaultStmt(DefaultStmt *D); +  CFGBlock *VisitDoStmt(DoStmt *D); +  CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc); +  CFGBlock *VisitForStmt(ForStmt *F); +  CFGBlock *VisitGotoStmt(GotoStmt *G); +  CFGBlock *VisitIfStmt(IfStmt *I); +  CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc); +  CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); +  CFGBlock *VisitLabelStmt(LabelStmt *L); +  CFGBlock *VisitLambdaExpr(LambdaExpr *L); +  CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); +  CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); +  CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); +  CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); +  CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); +  CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); +  CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); +  CFGBlock *VisitReturnStmt(ReturnStmt *R); +  CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E); +  CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, +                                          AddStmtChoice asc); +  CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); +  CFGBlock *VisitSwitchStmt(SwitchStmt *S); +  CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); +  CFGBlock *VisitWhileStmt(WhileStmt *W); + +  CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd); +  CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc); +  CFGBlock *VisitChildren(Stmt *S); +  CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc); + +  // Visitors to walk an AST and generate destructors of temporaries in +  // full expression. +  CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary = false); +  CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E); +  CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E); +  CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(CXXBindTemporaryExpr *E, +      bool BindToTemporary); +  CFGBlock * +  VisitConditionalOperatorForTemporaryDtors(AbstractConditionalOperator *E, +                                            bool BindToTemporary); + +  // NYS == Not Yet Supported +  CFGBlock *NYS() { +    badCFG = true; +    return Block; +  } + +  void autoCreateBlock() { if (!Block) Block = createBlock(); } +  CFGBlock *createBlock(bool add_successor = true); +  CFGBlock *createNoReturnBlock(); + +  CFGBlock *addStmt(Stmt *S) { +    return Visit(S, AddStmtChoice::AlwaysAdd); +  } +  CFGBlock *addInitializer(CXXCtorInitializer *I); +  void addAutomaticObjDtors(LocalScope::const_iterator B, +                            LocalScope::const_iterator E, Stmt *S); +  void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); + +  // Local scopes creation. +  LocalScope* createOrReuseLocalScope(LocalScope* Scope); + +  void addLocalScopeForStmt(Stmt *S); +  LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope = NULL); +  LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = NULL); + +  void addLocalScopeAndDtors(Stmt *S); + +  // Interface to CFGBlock - adding CFGElements. +  void appendStmt(CFGBlock *B, const Stmt *S) { +    if (alwaysAdd(S) && cachedEntry) +      cachedEntry->second = B; + +    // All block-level expressions should have already been IgnoreParens()ed. +    assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S); +    B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext()); +  } +  void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) { +    B->appendInitializer(I, cfg->getBumpVectorContext()); +  } +  void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) { +    B->appendBaseDtor(BS, cfg->getBumpVectorContext()); +  } +  void appendMemberDtor(CFGBlock *B, FieldDecl *FD) { +    B->appendMemberDtor(FD, cfg->getBumpVectorContext()); +  } +  void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) { +    B->appendTemporaryDtor(E, cfg->getBumpVectorContext()); +  } +  void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) { +    B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext()); +  } + +  void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, +      LocalScope::const_iterator B, LocalScope::const_iterator E); + +  void addSuccessor(CFGBlock *B, CFGBlock *S) { +    B->addSuccessor(S, cfg->getBumpVectorContext()); +  } + +  /// Try and evaluate an expression to an integer constant. +  bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) { +    if (!BuildOpts.PruneTriviallyFalseEdges) +      return false; +    return !S->isTypeDependent() &&  +           !S->isValueDependent() && +           S->EvaluateAsRValue(outResult, *Context); +  } + +  /// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1 +  /// if we can evaluate to a known value, otherwise return -1. +  TryResult tryEvaluateBool(Expr *S) { +    if (!BuildOpts.PruneTriviallyFalseEdges || +        S->isTypeDependent() || S->isValueDependent()) +      return TryResult(); + +    if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) { +      if (Bop->isLogicalOp()) { +        // Check the cache first. +        CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S); +        if (I != CachedBoolEvals.end()) +          return I->second; // already in map; + +        // Retrieve result at first, or the map might be updated. +        TryResult Result = evaluateAsBooleanConditionNoCache(S); +        CachedBoolEvals[S] = Result; // update or insert +        return Result; +      } +    } + +    return evaluateAsBooleanConditionNoCache(S); +  } + +  /// \brief Evaluate as boolean \param E without using the cache. +  TryResult evaluateAsBooleanConditionNoCache(Expr *E) { +    if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E)) { +      if (Bop->isLogicalOp()) { +        TryResult LHS = tryEvaluateBool(Bop->getLHS()); +        if (LHS.isKnown()) { +          // We were able to evaluate the LHS, see if we can get away with not +          // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 +          if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr)) +            return LHS.isTrue(); + +          TryResult RHS = tryEvaluateBool(Bop->getRHS()); +          if (RHS.isKnown()) { +            if (Bop->getOpcode() == BO_LOr) +              return LHS.isTrue() || RHS.isTrue(); +            else +              return LHS.isTrue() && RHS.isTrue(); +          } +        } else { +          TryResult RHS = tryEvaluateBool(Bop->getRHS()); +          if (RHS.isKnown()) { +            // We can't evaluate the LHS; however, sometimes the result +            // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. +            if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr)) +              return RHS.isTrue(); +          } +        } + +        return TryResult(); +      } +    } + +    bool Result; +    if (E->EvaluateAsBooleanCondition(Result, *Context)) +      return Result; + +    return TryResult(); +  } +   +}; + +inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder, +                                     const Stmt *stmt) const { +  return builder.alwaysAdd(stmt) || kind == AlwaysAdd; +} + +bool CFGBuilder::alwaysAdd(const Stmt *stmt) { +  bool shouldAdd = BuildOpts.alwaysAdd(stmt); +   +  if (!BuildOpts.forcedBlkExprs) +    return shouldAdd; + +  if (lastLookup == stmt) {   +    if (cachedEntry) { +      assert(cachedEntry->first == stmt); +      return true; +    } +    return shouldAdd; +  } +   +  lastLookup = stmt; + +  // Perform the lookup! +  CFG::BuildOptions::ForcedBlkExprs *fb = *BuildOpts.forcedBlkExprs; + +  if (!fb) { +    // No need to update 'cachedEntry', since it will always be null. +    assert(cachedEntry == 0); +    return shouldAdd; +  } + +  CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt); +  if (itr == fb->end()) { +    cachedEntry = 0; +    return shouldAdd; +  } + +  cachedEntry = &*itr; +  return true; +} +   +// FIXME: Add support for dependent-sized array types in C++? +// Does it even make sense to build a CFG for an uninstantiated template? +static const VariableArrayType *FindVA(const Type *t) { +  while (const ArrayType *vt = dyn_cast<ArrayType>(t)) { +    if (const VariableArrayType *vat = dyn_cast<VariableArrayType>(vt)) +      if (vat->getSizeExpr()) +        return vat; + +    t = vt->getElementType().getTypePtr(); +  } + +  return 0; +} + +/// BuildCFG - Constructs a CFG from an AST (a Stmt*).  The AST can represent an +///  arbitrary statement.  Examples include a single expression or a function +///  body (compound statement).  The ownership of the returned CFG is +///  transferred to the caller.  If CFG construction fails, this method returns +///  NULL. +CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { +  assert(cfg.get()); +  if (!Statement) +    return NULL; + +  // Create an empty block that will serve as the exit block for the CFG.  Since +  // this is the first block added to the CFG, it will be implicitly registered +  // as the exit block. +  Succ = createBlock(); +  assert(Succ == &cfg->getExit()); +  Block = NULL;  // the EXIT block is empty.  Create all other blocks lazily. + +  if (BuildOpts.AddImplicitDtors) +    if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D)) +      addImplicitDtorsForDestructor(DD); + +  // Visit the statements and create the CFG. +  CFGBlock *B = addStmt(Statement); + +  if (badCFG) +    return NULL; + +  // For C++ constructor add initializers to CFG. +  if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) { +    for (CXXConstructorDecl::init_const_reverse_iterator I = CD->init_rbegin(), +        E = CD->init_rend(); I != E; ++I) { +      B = addInitializer(*I); +      if (badCFG) +        return NULL; +    } +  } + +  if (B) +    Succ = B; + +  // Backpatch the gotos whose label -> block mappings we didn't know when we +  // encountered them. +  for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), +                                   E = BackpatchBlocks.end(); I != E; ++I ) { + +    CFGBlock *B = I->block; +    GotoStmt *G = cast<GotoStmt>(B->getTerminator()); +    LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); + +    // If there is no target for the goto, then we are looking at an +    // incomplete AST.  Handle this by not registering a successor. +    if (LI == LabelMap.end()) continue; + +    JumpTarget JT = LI->second; +    prependAutomaticObjDtorsWithTerminator(B, I->scopePosition, +                                           JT.scopePosition); +    addSuccessor(B, JT.block); +  } + +  // Add successors to the Indirect Goto Dispatch block (if we have one). +  if (CFGBlock *B = cfg->getIndirectGotoBlock()) +    for (LabelSetTy::iterator I = AddressTakenLabels.begin(), +                              E = AddressTakenLabels.end(); I != E; ++I ) { +       +      // Lookup the target block. +      LabelMapTy::iterator LI = LabelMap.find(*I); + +      // If there is no target block that contains label, then we are looking +      // at an incomplete AST.  Handle this by not registering a successor. +      if (LI == LabelMap.end()) continue; +       +      addSuccessor(B, LI->second.block); +    } + +  // Create an empty entry block that has no predecessors. +  cfg->setEntry(createBlock()); + +  return cfg.take(); +} + +/// createBlock - Used to lazily create blocks that are connected +///  to the current (global) succcessor. +CFGBlock *CFGBuilder::createBlock(bool add_successor) { +  CFGBlock *B = cfg->createBlock(); +  if (add_successor && Succ) +    addSuccessor(B, Succ); +  return B; +} + +/// createNoReturnBlock - Used to create a block is a 'noreturn' point in the +/// CFG. It is *not* connected to the current (global) successor, and instead +/// directly tied to the exit block in order to be reachable. +CFGBlock *CFGBuilder::createNoReturnBlock() { +  CFGBlock *B = createBlock(false); +  B->setHasNoReturnElement(); +  addSuccessor(B, &cfg->getExit()); +  return B; +} + +/// addInitializer - Add C++ base or member initializer element to CFG. +CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { +  if (!BuildOpts.AddInitializers) +    return Block; + +  bool IsReference = false; +  bool HasTemporaries = false; + +  // Destructors of temporaries in initialization expression should be called +  // after initialization finishes. +  Expr *Init = I->getInit(); +  if (Init) { +    if (FieldDecl *FD = I->getAnyMember()) +      IsReference = FD->getType()->isReferenceType(); +    HasTemporaries = isa<ExprWithCleanups>(Init); + +    if (BuildOpts.AddImplicitDtors && HasTemporaries) { +      // Generate destructors for temporaries in initialization expression. +      VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), +          IsReference); +    } +  } + +  autoCreateBlock(); +  appendInitializer(Block, I); + +  if (Init) { +    if (HasTemporaries) { +      // For expression with temporaries go directly to subexpression to omit +      // generating destructors for the second time. +      return Visit(cast<ExprWithCleanups>(Init)->getSubExpr()); +    } +    return Visit(Init); +  } + +  return Block; +} + +/// \brief Retrieve the type of the temporary object whose lifetime was  +/// extended by a local reference with the given initializer. +static QualType getReferenceInitTemporaryType(ASTContext &Context, +                                              const Expr *Init) { +  while (true) { +    // Skip parentheses. +    Init = Init->IgnoreParens(); +     +    // Skip through cleanups. +    if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init)) { +      Init = EWC->getSubExpr(); +      continue; +    } +     +    // Skip through the temporary-materialization expression. +    if (const MaterializeTemporaryExpr *MTE +          = dyn_cast<MaterializeTemporaryExpr>(Init)) { +      Init = MTE->GetTemporaryExpr(); +      continue; +    } +     +    // Skip derived-to-base and no-op casts. +    if (const CastExpr *CE = dyn_cast<CastExpr>(Init)) { +      if ((CE->getCastKind() == CK_DerivedToBase || +           CE->getCastKind() == CK_UncheckedDerivedToBase || +           CE->getCastKind() == CK_NoOp) && +          Init->getType()->isRecordType()) { +        Init = CE->getSubExpr(); +        continue; +      } +    } +     +    // Skip member accesses into rvalues. +    if (const MemberExpr *ME = dyn_cast<MemberExpr>(Init)) { +      if (!ME->isArrow() && ME->getBase()->isRValue()) { +        Init = ME->getBase(); +        continue; +      } +    } +     +    break; +  } + +  return Init->getType(); +} +   +/// addAutomaticObjDtors - Add to current block automatic objects destructors +/// for objects in range of local scope positions. Use S as trigger statement +/// for destructors. +void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, +                                      LocalScope::const_iterator E, Stmt *S) { +  if (!BuildOpts.AddImplicitDtors) +    return; + +  if (B == E) +    return; + +  // We need to append the destructors in reverse order, but any one of them +  // may be a no-return destructor which changes the CFG. As a result, buffer +  // this sequence up and replay them in reverse order when appending onto the +  // CFGBlock(s). +  SmallVector<VarDecl*, 10> Decls; +  Decls.reserve(B.distance(E)); +  for (LocalScope::const_iterator I = B; I != E; ++I) +    Decls.push_back(*I); + +  for (SmallVectorImpl<VarDecl*>::reverse_iterator I = Decls.rbegin(), +                                                   E = Decls.rend(); +       I != E; ++I) { +    // If this destructor is marked as a no-return destructor, we need to +    // create a new block for the destructor which does not have as a successor +    // anything built thus far: control won't flow out of this block. +    QualType Ty; +    if ((*I)->getType()->isReferenceType()) { +      Ty = getReferenceInitTemporaryType(*Context, (*I)->getInit()); +    } else { +      Ty = Context->getBaseElementType((*I)->getType()); +    } +     +    const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); +    if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) +      Block = createNoReturnBlock(); +    else +      autoCreateBlock(); + +    appendAutomaticObjDtor(Block, *I, S); +  } +} + +/// addImplicitDtorsForDestructor - Add implicit destructors generated for +/// base and member objects in destructor. +void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) { +  assert (BuildOpts.AddImplicitDtors +      && "Can be called only when dtors should be added"); +  const CXXRecordDecl *RD = DD->getParent(); + +  // At the end destroy virtual base objects. +  for (CXXRecordDecl::base_class_const_iterator VI = RD->vbases_begin(), +      VE = RD->vbases_end(); VI != VE; ++VI) { +    const CXXRecordDecl *CD = VI->getType()->getAsCXXRecordDecl(); +    if (!CD->hasTrivialDestructor()) { +      autoCreateBlock(); +      appendBaseDtor(Block, VI); +    } +  } + +  // Before virtual bases destroy direct base objects. +  for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(), +      BE = RD->bases_end(); BI != BE; ++BI) { +    if (!BI->isVirtual()) { +      const CXXRecordDecl *CD = BI->getType()->getAsCXXRecordDecl(); +      if (!CD->hasTrivialDestructor()) { +        autoCreateBlock(); +        appendBaseDtor(Block, BI); +      } +    } +  } + +  // First destroy member objects. +  for (CXXRecordDecl::field_iterator FI = RD->field_begin(), +      FE = RD->field_end(); FI != FE; ++FI) { +    // Check for constant size array. Set type to array element type. +    QualType QT = FI->getType(); +    if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { +      if (AT->getSize() == 0) +        continue; +      QT = AT->getElementType(); +    } + +    if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl()) +      if (!CD->hasTrivialDestructor()) { +        autoCreateBlock(); +        appendMemberDtor(Block, *FI); +      } +  } +} + +/// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either +/// way return valid LocalScope object. +LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { +  if (!Scope) { +    llvm::BumpPtrAllocator &alloc = cfg->getAllocator(); +    Scope = alloc.Allocate<LocalScope>(); +    BumpVectorContext ctx(alloc); +    new (Scope) LocalScope(ctx, ScopePos); +  } +  return Scope; +} + +/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement +/// that should create implicit scope (e.g. if/else substatements).  +void CFGBuilder::addLocalScopeForStmt(Stmt *S) { +  if (!BuildOpts.AddImplicitDtors) +    return; + +  LocalScope *Scope = 0; + +  // For compound statement we will be creating explicit scope. +  if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { +    for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end() +        ; BI != BE; ++BI) { +      Stmt *SI = (*BI)->stripLabelLikeStatements(); +      if (DeclStmt *DS = dyn_cast<DeclStmt>(SI)) +        Scope = addLocalScopeForDeclStmt(DS, Scope); +    } +    return; +  } + +  // For any other statement scope will be implicit and as such will be +  // interesting only for DeclStmt. +  if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements())) +    addLocalScopeForDeclStmt(DS); +} + +/// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will +/// reuse Scope if not NULL. +LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, +                                                 LocalScope* Scope) { +  if (!BuildOpts.AddImplicitDtors) +    return Scope; + +  for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end() +      ; DI != DE; ++DI) { +    if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) +      Scope = addLocalScopeForVarDecl(VD, Scope); +  } +  return Scope; +} + +/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will +/// create add scope for automatic objects and temporary objects bound to +/// const reference. Will reuse Scope if not NULL. +LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, +                                                LocalScope* Scope) { +  if (!BuildOpts.AddImplicitDtors) +    return Scope; + +  // Check if variable is local. +  switch (VD->getStorageClass()) { +  case SC_None: +  case SC_Auto: +  case SC_Register: +    break; +  default: return Scope; +  } + +  // Check for const references bound to temporary. Set type to pointee. +  QualType QT = VD->getType(); +  if (QT.getTypePtr()->isReferenceType()) { +    if (!VD->extendsLifetimeOfTemporary()) +      return Scope; + +    QT = getReferenceInitTemporaryType(*Context, VD->getInit()); +  } + +  // Check for constant size array. Set type to array element type. +  while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { +    if (AT->getSize() == 0) +      return Scope; +    QT = AT->getElementType(); +  } + +  // Check if type is a C++ class with non-trivial destructor. +  if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl()) +    if (!CD->hasTrivialDestructor()) { +      // Add the variable to scope +      Scope = createOrReuseLocalScope(Scope); +      Scope->addVar(VD); +      ScopePos = Scope->begin(); +    } +  return Scope; +} + +/// addLocalScopeAndDtors - For given statement add local scope for it and +/// add destructors that will cleanup the scope. Will reuse Scope if not NULL. +void CFGBuilder::addLocalScopeAndDtors(Stmt *S) { +  if (!BuildOpts.AddImplicitDtors) +    return; + +  LocalScope::const_iterator scopeBeginPos = ScopePos; +  addLocalScopeForStmt(S); +  addAutomaticObjDtors(ScopePos, scopeBeginPos, S); +} + +/// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for +/// variables with automatic storage duration to CFGBlock's elements vector. +/// Elements will be prepended to physical beginning of the vector which +/// happens to be logical end. Use blocks terminator as statement that specifies +/// destructors call site. +/// FIXME: This mechanism for adding automatic destructors doesn't handle +/// no-return destructors properly. +void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, +    LocalScope::const_iterator B, LocalScope::const_iterator E) { +  BumpVectorContext &C = cfg->getBumpVectorContext(); +  CFGBlock::iterator InsertPos +    = Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C); +  for (LocalScope::const_iterator I = B; I != E; ++I) +    InsertPos = Blk->insertAutomaticObjDtor(InsertPos, *I, +                                            Blk->getTerminator()); +} + +/// Visit - Walk the subtree of a statement and add extra +///   blocks for ternary operators, &&, and ||.  We also process "," and +///   DeclStmts (which may contain nested control-flow). +CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { +  if (!S) { +    badCFG = true; +    return 0; +  } + +  if (Expr *E = dyn_cast<Expr>(S)) +    S = E->IgnoreParens(); + +  switch (S->getStmtClass()) { +    default: +      return VisitStmt(S, asc); + +    case Stmt::AddrLabelExprClass: +      return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc); + +    case Stmt::BinaryConditionalOperatorClass: +      return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc); + +    case Stmt::BinaryOperatorClass: +      return VisitBinaryOperator(cast<BinaryOperator>(S), asc); + +    case Stmt::BlockExprClass: +      return VisitNoRecurse(cast<Expr>(S), asc); + +    case Stmt::BreakStmtClass: +      return VisitBreakStmt(cast<BreakStmt>(S)); + +    case Stmt::CallExprClass: +    case Stmt::CXXOperatorCallExprClass: +    case Stmt::CXXMemberCallExprClass: +    case Stmt::UserDefinedLiteralClass: +      return VisitCallExpr(cast<CallExpr>(S), asc); + +    case Stmt::CaseStmtClass: +      return VisitCaseStmt(cast<CaseStmt>(S)); + +    case Stmt::ChooseExprClass: +      return VisitChooseExpr(cast<ChooseExpr>(S), asc); + +    case Stmt::CompoundStmtClass: +      return VisitCompoundStmt(cast<CompoundStmt>(S)); + +    case Stmt::ConditionalOperatorClass: +      return VisitConditionalOperator(cast<ConditionalOperator>(S), asc); + +    case Stmt::ContinueStmtClass: +      return VisitContinueStmt(cast<ContinueStmt>(S)); + +    case Stmt::CXXCatchStmtClass: +      return VisitCXXCatchStmt(cast<CXXCatchStmt>(S)); + +    case Stmt::ExprWithCleanupsClass: +      return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc); + +    case Stmt::CXXBindTemporaryExprClass: +      return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc); + +    case Stmt::CXXConstructExprClass: +      return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc); + +    case Stmt::CXXFunctionalCastExprClass: +      return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc); + +    case Stmt::CXXTemporaryObjectExprClass: +      return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc); + +    case Stmt::CXXThrowExprClass: +      return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); + +    case Stmt::CXXTryStmtClass: +      return VisitCXXTryStmt(cast<CXXTryStmt>(S)); + +    case Stmt::CXXForRangeStmtClass: +      return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S)); + +    case Stmt::DeclStmtClass: +      return VisitDeclStmt(cast<DeclStmt>(S)); + +    case Stmt::DefaultStmtClass: +      return VisitDefaultStmt(cast<DefaultStmt>(S)); + +    case Stmt::DoStmtClass: +      return VisitDoStmt(cast<DoStmt>(S)); + +    case Stmt::ForStmtClass: +      return VisitForStmt(cast<ForStmt>(S)); + +    case Stmt::GotoStmtClass: +      return VisitGotoStmt(cast<GotoStmt>(S)); + +    case Stmt::IfStmtClass: +      return VisitIfStmt(cast<IfStmt>(S)); + +    case Stmt::ImplicitCastExprClass: +      return VisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc); + +    case Stmt::IndirectGotoStmtClass: +      return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S)); + +    case Stmt::LabelStmtClass: +      return VisitLabelStmt(cast<LabelStmt>(S)); + +    case Stmt::LambdaExprClass: +      return VisitLambdaExpr(cast<LambdaExpr>(S), asc); + +    case Stmt::AttributedStmtClass: +      return Visit(cast<AttributedStmt>(S)->getSubStmt(), asc); + +    case Stmt::MemberExprClass: +      return VisitMemberExpr(cast<MemberExpr>(S), asc); + +    case Stmt::NullStmtClass: +      return Block; + +    case Stmt::ObjCAtCatchStmtClass: +      return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S)); + +    case Stmt::ObjCAutoreleasePoolStmtClass: +    return VisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S)); + +    case Stmt::ObjCAtSynchronizedStmtClass: +      return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S)); + +    case Stmt::ObjCAtThrowStmtClass: +      return VisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S)); + +    case Stmt::ObjCAtTryStmtClass: +      return VisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S)); + +    case Stmt::ObjCForCollectionStmtClass: +      return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S)); + +    case Stmt::OpaqueValueExprClass: +      return Block; + +    case Stmt::PseudoObjectExprClass: +      return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S)); + +    case Stmt::ReturnStmtClass: +      return VisitReturnStmt(cast<ReturnStmt>(S)); + +    case Stmt::UnaryExprOrTypeTraitExprClass: +      return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), +                                           asc); + +    case Stmt::StmtExprClass: +      return VisitStmtExpr(cast<StmtExpr>(S), asc); + +    case Stmt::SwitchStmtClass: +      return VisitSwitchStmt(cast<SwitchStmt>(S)); + +    case Stmt::UnaryOperatorClass: +      return VisitUnaryOperator(cast<UnaryOperator>(S), asc); + +    case Stmt::WhileStmtClass: +      return VisitWhileStmt(cast<WhileStmt>(S)); +  } +} + +CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, S)) { +    autoCreateBlock(); +    appendStmt(Block, S); +  } + +  return VisitChildren(S); +} + +/// VisitChildren - Visit the children of a Stmt. +CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) { +  CFGBlock *lastBlock = Block; +  for (Stmt::child_range I = Terminator->children(); I; ++I) +    if (Stmt *child = *I) +      if (CFGBlock *b = Visit(child)) +        lastBlock = b; + +  return lastBlock; +} + +CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, +                                         AddStmtChoice asc) { +  AddressTakenLabels.insert(A->getLabel()); + +  if (asc.alwaysAdd(*this, A)) { +    autoCreateBlock(); +    appendStmt(Block, A); +  } + +  return Block; +} + +CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, +           AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, U)) { +    autoCreateBlock(); +    appendStmt(Block, U); +  } + +  return Visit(U->getSubExpr(), AddStmtChoice()); +} + +CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, +                                          AddStmtChoice asc) { +  if (B->isLogicalOp()) { // && or || +    CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); +    appendStmt(ConfluenceBlock, B); + +    if (badCFG) +      return 0; + +    // create the block evaluating the LHS +    CFGBlock *LHSBlock = createBlock(false); +    LHSBlock->setTerminator(B); + +    // create the block evaluating the RHS +    Succ = ConfluenceBlock; +    Block = NULL; +    CFGBlock *RHSBlock = addStmt(B->getRHS()); + +    if (RHSBlock) { +      if (badCFG) +        return 0; +    } else { +      // Create an empty block for cases where the RHS doesn't require +      // any explicit statements in the CFG. +      RHSBlock = createBlock(); +    } + +    // Generate the blocks for evaluating the LHS. +    Block = LHSBlock; +    CFGBlock *EntryLHSBlock = addStmt(B->getLHS()); + +    // See if this is a known constant. +    TryResult KnownVal = tryEvaluateBool(B->getLHS()); +    if (KnownVal.isKnown() && (B->getOpcode() == BO_LOr)) +      KnownVal.negate(); + +    // Now link the LHSBlock with RHSBlock. +    if (B->getOpcode() == BO_LOr) { +      addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); +      addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); +    } else { +      assert(B->getOpcode() == BO_LAnd); +      addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); +      addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); +    } + +    return EntryLHSBlock; +  } + +  if (B->getOpcode() == BO_Comma) { // , +    autoCreateBlock(); +    appendStmt(Block, B); +    addStmt(B->getRHS()); +    return addStmt(B->getLHS()); +  } + +  if (B->isAssignmentOp()) { +    if (asc.alwaysAdd(*this, B)) { +      autoCreateBlock(); +      appendStmt(Block, B); +    } +    Visit(B->getLHS()); +    return Visit(B->getRHS()); +  } + +  if (asc.alwaysAdd(*this, B)) { +    autoCreateBlock(); +    appendStmt(Block, B); +  } + +  CFGBlock *RBlock = Visit(B->getRHS()); +  CFGBlock *LBlock = Visit(B->getLHS()); +  // If visiting RHS causes us to finish 'Block', e.g. the RHS is a StmtExpr +  // containing a DoStmt, and the LHS doesn't create a new block, then we should +  // return RBlock.  Otherwise we'll incorrectly return NULL. +  return (LBlock ? LBlock : RBlock); +} + +CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, E)) { +    autoCreateBlock(); +    appendStmt(Block, E); +  } +  return Block; +} + +CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { +  // "break" is a control-flow statement.  Thus we stop processing the current +  // block. +  if (badCFG) +    return 0; + +  // Now create a new block that ends with the break statement. +  Block = createBlock(false); +  Block->setTerminator(B); + +  // If there is no target for the break, then we are looking at an incomplete +  // AST.  This means that the CFG cannot be constructed. +  if (BreakJumpTarget.block) { +    addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B); +    addSuccessor(Block, BreakJumpTarget.block); +  } else +    badCFG = true; + + +  return Block; +} + +static bool CanThrow(Expr *E, ASTContext &Ctx) { +  QualType Ty = E->getType(); +  if (Ty->isFunctionPointerType()) +    Ty = Ty->getAs<PointerType>()->getPointeeType(); +  else if (Ty->isBlockPointerType()) +    Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); + +  const FunctionType *FT = Ty->getAs<FunctionType>(); +  if (FT) { +    if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) +      if (Proto->getExceptionSpecType() != EST_Uninstantiated && +          Proto->isNothrow(Ctx)) +        return false; +  } +  return true; +} + +CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { +  // Compute the callee type. +  QualType calleeType = C->getCallee()->getType(); +  if (calleeType == Context->BoundMemberTy) { +    QualType boundType = Expr::findBoundMemberType(C->getCallee()); + +    // We should only get a null bound type if processing a dependent +    // CFG.  Recover by assuming nothing. +    if (!boundType.isNull()) calleeType = boundType; +  } + +  // If this is a call to a no-return function, this stops the block here. +  bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn(); + +  bool AddEHEdge = false; + +  // Languages without exceptions are assumed to not throw. +  if (Context->getLangOpts().Exceptions) { +    if (BuildOpts.AddEHEdges) +      AddEHEdge = true; +  } + +  if (FunctionDecl *FD = C->getDirectCallee()) { +    if (FD->hasAttr<NoReturnAttr>()) +      NoReturn = true; +    if (FD->hasAttr<NoThrowAttr>()) +      AddEHEdge = false; +  } + +  if (!CanThrow(C->getCallee(), *Context)) +    AddEHEdge = false; + +  if (!NoReturn && !AddEHEdge) +    return VisitStmt(C, asc.withAlwaysAdd(true)); + +  if (Block) { +    Succ = Block; +    if (badCFG) +      return 0; +  } + +  if (NoReturn) +    Block = createNoReturnBlock(); +  else +    Block = createBlock(); + +  appendStmt(Block, C); + +  if (AddEHEdge) { +    // Add exceptional edges. +    if (TryTerminatedBlock) +      addSuccessor(Block, TryTerminatedBlock); +    else +      addSuccessor(Block, &cfg->getExit()); +  } + +  return VisitChildren(C); +} + +CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, +                                      AddStmtChoice asc) { +  CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); +  appendStmt(ConfluenceBlock, C); +  if (badCFG) +    return 0; + +  AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true); +  Succ = ConfluenceBlock; +  Block = NULL; +  CFGBlock *LHSBlock = Visit(C->getLHS(), alwaysAdd); +  if (badCFG) +    return 0; + +  Succ = ConfluenceBlock; +  Block = NULL; +  CFGBlock *RHSBlock = Visit(C->getRHS(), alwaysAdd); +  if (badCFG) +    return 0; + +  Block = createBlock(false); +  // See if this is a known constant. +  const TryResult& KnownVal = tryEvaluateBool(C->getCond()); +  addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock); +  addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock); +  Block->setTerminator(C); +  return addStmt(C->getCond()); +} + + +CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) { +  addLocalScopeAndDtors(C); +  CFGBlock *LastBlock = Block; + +  for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); +       I != E; ++I ) { +    // If we hit a segment of code just containing ';' (NullStmts), we can +    // get a null block back.  In such cases, just use the LastBlock +    if (CFGBlock *newBlock = addStmt(*I)) +      LastBlock = newBlock; + +    if (badCFG) +      return NULL; +  } + +  return LastBlock; +} + +CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, +                                               AddStmtChoice asc) { +  const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(C); +  const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : NULL); + +  // Create the confluence block that will "merge" the results of the ternary +  // expression. +  CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); +  appendStmt(ConfluenceBlock, C); +  if (badCFG) +    return 0; + +  AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true); + +  // Create a block for the LHS expression if there is an LHS expression.  A +  // GCC extension allows LHS to be NULL, causing the condition to be the +  // value that is returned instead. +  //  e.g: x ?: y is shorthand for: x ? x : y; +  Succ = ConfluenceBlock; +  Block = NULL; +  CFGBlock *LHSBlock = 0; +  const Expr *trueExpr = C->getTrueExpr(); +  if (trueExpr != opaqueValue) { +    LHSBlock = Visit(C->getTrueExpr(), alwaysAdd); +    if (badCFG) +      return 0; +    Block = NULL; +  } +  else +    LHSBlock = ConfluenceBlock; + +  // Create the block for the RHS expression. +  Succ = ConfluenceBlock; +  CFGBlock *RHSBlock = Visit(C->getFalseExpr(), alwaysAdd); +  if (badCFG) +    return 0; + +  // Create the block that will contain the condition. +  Block = createBlock(false); + +  // See if this is a known constant. +  const TryResult& KnownVal = tryEvaluateBool(C->getCond()); +  addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock); +  addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock); +  Block->setTerminator(C); +  Expr *condExpr = C->getCond(); + +  if (opaqueValue) { +    // Run the condition expression if it's not trivially expressed in +    // terms of the opaque value (or if there is no opaque value). +    if (condExpr != opaqueValue) +      addStmt(condExpr); + +    // Before that, run the common subexpression if there was one. +    // At least one of this or the above will be run. +    return addStmt(BCO->getCommon()); +  } +   +  return addStmt(condExpr); +} + +CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { +  // Check if the Decl is for an __label__.  If so, elide it from the +  // CFG entirely. +  if (isa<LabelDecl>(*DS->decl_begin())) +    return Block; +   +  // This case also handles static_asserts. +  if (DS->isSingleDecl()) +    return VisitDeclSubExpr(DS); + +  CFGBlock *B = 0; + +  // FIXME: Add a reverse iterator for DeclStmt to avoid this extra copy. +  typedef SmallVector<Decl*,10> BufTy; +  BufTy Buf(DS->decl_begin(), DS->decl_end()); + +  for (BufTy::reverse_iterator I = Buf.rbegin(), E = Buf.rend(); I != E; ++I) { +    // Get the alignment of the new DeclStmt, padding out to >=8 bytes. +    unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8 +               ? 8 : llvm::AlignOf<DeclStmt>::Alignment; + +    // Allocate the DeclStmt using the BumpPtrAllocator.  It will get +    // automatically freed with the CFG. +    DeclGroupRef DG(*I); +    Decl *D = *I; +    void *Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A); +    DeclStmt *DSNew = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D)); + +    // Append the fake DeclStmt to block. +    B = VisitDeclSubExpr(DSNew); +  } + +  return B; +} + +/// VisitDeclSubExpr - Utility method to add block-level expressions for +/// DeclStmts and initializers in them. +CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { +  assert(DS->isSingleDecl() && "Can handle single declarations only."); +  Decl *D = DS->getSingleDecl(); +  +  if (isa<StaticAssertDecl>(D)) { +    // static_asserts aren't added to the CFG because they do not impact +    // runtime semantics. +    return Block; +  } +   +  VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + +  if (!VD) { +    autoCreateBlock(); +    appendStmt(Block, DS); +    return Block; +  } + +  bool IsReference = false; +  bool HasTemporaries = false; + +  // Destructors of temporaries in initialization expression should be called +  // after initialization finishes. +  Expr *Init = VD->getInit(); +  if (Init) { +    IsReference = VD->getType()->isReferenceType(); +    HasTemporaries = isa<ExprWithCleanups>(Init); + +    if (BuildOpts.AddImplicitDtors && HasTemporaries) { +      // Generate destructors for temporaries in initialization expression. +      VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), +          IsReference); +    } +  } + +  autoCreateBlock(); +  appendStmt(Block, DS); +   +  // Keep track of the last non-null block, as 'Block' can be nulled out +  // if the initializer expression is something like a 'while' in a +  // statement-expression. +  CFGBlock *LastBlock = Block; + +  if (Init) { +    if (HasTemporaries) { +      // For expression with temporaries go directly to subexpression to omit +      // generating destructors for the second time. +      ExprWithCleanups *EC = cast<ExprWithCleanups>(Init); +      if (CFGBlock *newBlock = Visit(EC->getSubExpr())) +        LastBlock = newBlock; +    } +    else { +      if (CFGBlock *newBlock = Visit(Init)) +        LastBlock = newBlock; +    } +  } + +  // If the type of VD is a VLA, then we must process its size expressions. +  for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); +       VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) +    Block = addStmt(VA->getSizeExpr()); + +  // Remove variable from local scope. +  if (ScopePos && VD == *ScopePos) +    ++ScopePos; + +  return Block ? Block : LastBlock; +} + +CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { +  // We may see an if statement in the middle of a basic block, or it may be the +  // first statement we are processing.  In either case, we create a new basic +  // block.  First, we create the blocks for the then...else statements, and +  // then we create the block containing the if statement.  If we were in the +  // middle of a block, we stop processing that block.  That block is then the +  // implicit successor for the "then" and "else" clauses. + +  // Save local scope position because in case of condition variable ScopePos +  // won't be restored when traversing AST. +  SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + +  // Create local scope for possible condition variable. +  // Store scope position. Add implicit destructor. +  if (VarDecl *VD = I->getConditionVariable()) { +    LocalScope::const_iterator BeginScopePos = ScopePos; +    addLocalScopeForVarDecl(VD); +    addAutomaticObjDtors(ScopePos, BeginScopePos, I); +  } + +  // The block we were processing is now finished.  Make it the successor +  // block. +  if (Block) { +    Succ = Block; +    if (badCFG) +      return 0; +  } + +  // Process the false branch. +  CFGBlock *ElseBlock = Succ; + +  if (Stmt *Else = I->getElse()) { +    SaveAndRestore<CFGBlock*> sv(Succ); + +    // NULL out Block so that the recursive call to Visit will +    // create a new basic block. +    Block = NULL; + +    // If branch is not a compound statement create implicit scope +    // and add destructors. +    if (!isa<CompoundStmt>(Else)) +      addLocalScopeAndDtors(Else); + +    ElseBlock = addStmt(Else); + +    if (!ElseBlock) // Can occur when the Else body has all NullStmts. +      ElseBlock = sv.get(); +    else if (Block) { +      if (badCFG) +        return 0; +    } +  } + +  // Process the true branch. +  CFGBlock *ThenBlock; +  { +    Stmt *Then = I->getThen(); +    assert(Then); +    SaveAndRestore<CFGBlock*> sv(Succ); +    Block = NULL; + +    // If branch is not a compound statement create implicit scope +    // and add destructors. +    if (!isa<CompoundStmt>(Then)) +      addLocalScopeAndDtors(Then); + +    ThenBlock = addStmt(Then); + +    if (!ThenBlock) { +      // We can reach here if the "then" body has all NullStmts. +      // Create an empty block so we can distinguish between true and false +      // branches in path-sensitive analyses. +      ThenBlock = createBlock(false); +      addSuccessor(ThenBlock, sv.get()); +    } else if (Block) { +      if (badCFG) +        return 0; +    } +  } + +  // Now create a new block containing the if statement. +  Block = createBlock(false); + +  // Set the terminator of the new block to the If statement. +  Block->setTerminator(I); + +  // See if this is a known constant. +  const TryResult &KnownVal = tryEvaluateBool(I->getCond()); + +  // Now add the successors. +  addSuccessor(Block, KnownVal.isFalse() ? NULL : ThenBlock); +  addSuccessor(Block, KnownVal.isTrue()? NULL : ElseBlock); + +  // Add the condition as the last statement in the new block.  This may create +  // new blocks as the condition may contain control-flow.  Any newly created +  // blocks will be pointed to be "Block". +  Block = addStmt(I->getCond()); + +  // Finally, if the IfStmt contains a condition variable, add both the IfStmt +  // and the condition variable initialization to the CFG. +  if (VarDecl *VD = I->getConditionVariable()) { +    if (Expr *Init = VD->getInit()) { +      autoCreateBlock(); +      appendStmt(Block, I->getConditionVariableDeclStmt()); +      addStmt(Init); +    } +  } + +  return Block; +} + + +CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { +  // If we were in the middle of a block we stop processing that block. +  // +  // NOTE: If a "return" appears in the middle of a block, this means that the +  //       code afterwards is DEAD (unreachable).  We still keep a basic block +  //       for that code; a simple "mark-and-sweep" from the entry block will be +  //       able to report such dead blocks. + +  // Create the new block. +  Block = createBlock(false); + +  // The Exit block is the only successor. +  addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R); +  addSuccessor(Block, &cfg->getExit()); + +  // Add the return statement to the block.  This may create new blocks if R +  // contains control-flow (short-circuit operations). +  return VisitStmt(R, AddStmtChoice::AlwaysAdd); +} + +CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) { +  // Get the block of the labeled statement.  Add it to our map. +  addStmt(L->getSubStmt()); +  CFGBlock *LabelBlock = Block; + +  if (!LabelBlock)              // This can happen when the body is empty, i.e. +    LabelBlock = createBlock(); // scopes that only contains NullStmts. + +  assert(LabelMap.find(L->getDecl()) == LabelMap.end() && +         "label already in map"); +  LabelMap[L->getDecl()] = JumpTarget(LabelBlock, ScopePos); + +  // Labels partition blocks, so this is the end of the basic block we were +  // processing (L is the block's label).  Because this is label (and we have +  // already processed the substatement) there is no extra control-flow to worry +  // about. +  LabelBlock->setLabel(L); +  if (badCFG) +    return 0; + +  // We set Block to NULL to allow lazy creation of a new block (if necessary); +  Block = NULL; + +  // This block is now the implicit successor of other blocks. +  Succ = LabelBlock; + +  return LabelBlock; +} + +CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) { +  CFGBlock *LastBlock = VisitNoRecurse(E, asc); +  for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(), +       et = E->capture_init_end(); it != et; ++it) { +    if (Expr *Init = *it) { +      CFGBlock *Tmp = Visit(Init); +      if (Tmp != 0) +        LastBlock = Tmp; +    } +  } +  return LastBlock; +} +   +CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) { +  // Goto is a control-flow statement.  Thus we stop processing the current +  // block and create a new one. + +  Block = createBlock(false); +  Block->setTerminator(G); + +  // If we already know the mapping to the label block add the successor now. +  LabelMapTy::iterator I = LabelMap.find(G->getLabel()); + +  if (I == LabelMap.end()) +    // We will need to backpatch this block later. +    BackpatchBlocks.push_back(JumpSource(Block, ScopePos)); +  else { +    JumpTarget JT = I->second; +    addAutomaticObjDtors(ScopePos, JT.scopePosition, G); +    addSuccessor(Block, JT.block); +  } + +  return Block; +} + +CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { +  CFGBlock *LoopSuccessor = NULL; + +  // Save local scope position because in case of condition variable ScopePos +  // won't be restored when traversing AST. +  SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + +  // Create local scope for init statement and possible condition variable. +  // Add destructor for init statement and condition variable. +  // Store scope position for continue statement. +  if (Stmt *Init = F->getInit()) +    addLocalScopeForStmt(Init); +  LocalScope::const_iterator LoopBeginScopePos = ScopePos; + +  if (VarDecl *VD = F->getConditionVariable()) +    addLocalScopeForVarDecl(VD); +  LocalScope::const_iterator ContinueScopePos = ScopePos; + +  addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F); + +  // "for" is a control-flow statement.  Thus we stop processing the current +  // block. +  if (Block) { +    if (badCFG) +      return 0; +    LoopSuccessor = Block; +  } else +    LoopSuccessor = Succ; + +  // Save the current value for the break targets. +  // All breaks should go to the code following the loop. +  SaveAndRestore<JumpTarget> save_break(BreakJumpTarget); +  BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); + +  // Because of short-circuit evaluation, the condition of the loop can span +  // multiple basic blocks.  Thus we need the "Entry" and "Exit" blocks that +  // evaluate the condition. +  CFGBlock *ExitConditionBlock = createBlock(false); +  CFGBlock *EntryConditionBlock = ExitConditionBlock; + +  // Set the terminator for the "exit" condition block. +  ExitConditionBlock->setTerminator(F); + +  // Now add the actual condition to the condition block.  Because the condition +  // itself may contain control-flow, new blocks may be created. +  if (Stmt *C = F->getCond()) { +    Block = ExitConditionBlock; +    EntryConditionBlock = addStmt(C); +    if (badCFG) +      return 0; +    assert(Block == EntryConditionBlock || +           (Block == 0 && EntryConditionBlock == Succ)); + +    // If this block contains a condition variable, add both the condition +    // variable and initializer to the CFG. +    if (VarDecl *VD = F->getConditionVariable()) { +      if (Expr *Init = VD->getInit()) { +        autoCreateBlock(); +        appendStmt(Block, F->getConditionVariableDeclStmt()); +        EntryConditionBlock = addStmt(Init); +        assert(Block == EntryConditionBlock); +      } +    } + +    if (Block) { +      if (badCFG) +        return 0; +    } +  } + +  // The condition block is the implicit successor for the loop body as well as +  // any code above the loop. +  Succ = EntryConditionBlock; + +  // See if this is a known constant. +  TryResult KnownVal(true); + +  if (F->getCond()) +    KnownVal = tryEvaluateBool(F->getCond()); + +  // Now create the loop body. +  { +    assert(F->getBody()); + +   // Save the current values for Block, Succ, and continue targets. +   SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); +   SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget); + +    // Create a new block to contain the (bottom) of the loop body. +    Block = NULL; +     +    // Loop body should end with destructor of Condition variable (if any). +    addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F); + +    if (Stmt *I = F->getInc()) { +      // Generate increment code in its own basic block.  This is the target of +      // continue statements. +      Succ = addStmt(I); +    } else { +      // No increment code.  Create a special, empty, block that is used as the +      // target block for "looping back" to the start of the loop. +      assert(Succ == EntryConditionBlock); +      Succ = Block ? Block : createBlock(); +    } + +    // Finish up the increment (or empty) block if it hasn't been already. +    if (Block) { +      assert(Block == Succ); +      if (badCFG) +        return 0; +      Block = 0; +    } + +    ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos); + +    // The starting block for the loop increment is the block that should +    // represent the 'loop target' for looping back to the start of the loop. +    ContinueJumpTarget.block->setLoopTarget(F); + +    // If body is not a compound statement create implicit scope +    // and add destructors. +    if (!isa<CompoundStmt>(F->getBody())) +      addLocalScopeAndDtors(F->getBody()); + +    // Now populate the body block, and in the process create new blocks as we +    // walk the body of the loop. +    CFGBlock *BodyBlock = addStmt(F->getBody()); + +    if (!BodyBlock) +      BodyBlock = ContinueJumpTarget.block;//can happen for "for (...;...;...);" +    else if (badCFG) +      return 0; + +    // This new body block is a successor to our "exit" condition block. +    addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock); +  } + +  // Link up the condition block with the code that follows the loop.  (the +  // false branch). +  addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + +  // If the loop contains initialization, create a new block for those +  // statements.  This block can also contain statements that precede the loop. +  if (Stmt *I = F->getInit()) { +    Block = createBlock(); +    return addStmt(I); +  } + +  // There is no loop initialization.  We are thus basically a while loop. +  // NULL out Block to force lazy block construction. +  Block = NULL; +  Succ = EntryConditionBlock; +  return EntryConditionBlock; +} + +CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, M)) { +    autoCreateBlock(); +    appendStmt(Block, M); +  } +  return Visit(M->getBase()); +} + +CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { +  // Objective-C fast enumeration 'for' statements: +  //  http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC +  // +  //  for ( Type newVariable in collection_expression ) { statements } +  // +  //  becomes: +  // +  //   prologue: +  //     1. collection_expression +  //     T. jump to loop_entry +  //   loop_entry: +  //     1. side-effects of element expression +  //     1. ObjCForCollectionStmt [performs binding to newVariable] +  //     T. ObjCForCollectionStmt  TB, FB  [jumps to TB if newVariable != nil] +  //   TB: +  //     statements +  //     T. jump to loop_entry +  //   FB: +  //     what comes after +  // +  //  and +  // +  //  Type existingItem; +  //  for ( existingItem in expression ) { statements } +  // +  //  becomes: +  // +  //   the same with newVariable replaced with existingItem; the binding works +  //   the same except that for one ObjCForCollectionStmt::getElement() returns +  //   a DeclStmt and the other returns a DeclRefExpr. +  // + +  CFGBlock *LoopSuccessor = 0; + +  if (Block) { +    if (badCFG) +      return 0; +    LoopSuccessor = Block; +    Block = 0; +  } else +    LoopSuccessor = Succ; + +  // Build the condition blocks. +  CFGBlock *ExitConditionBlock = createBlock(false); + +  // Set the terminator for the "exit" condition block. +  ExitConditionBlock->setTerminator(S); + +  // The last statement in the block should be the ObjCForCollectionStmt, which +  // performs the actual binding to 'element' and determines if there are any +  // more items in the collection. +  appendStmt(ExitConditionBlock, S); +  Block = ExitConditionBlock; + +  // Walk the 'element' expression to see if there are any side-effects.  We +  // generate new blocks as necessary.  We DON'T add the statement by default to +  // the CFG unless it contains control-flow. +  CFGBlock *EntryConditionBlock = Visit(S->getElement(), +                                        AddStmtChoice::NotAlwaysAdd); +  if (Block) { +    if (badCFG) +      return 0; +    Block = 0; +  } + +  // The condition block is the implicit successor for the loop body as well as +  // any code above the loop. +  Succ = EntryConditionBlock; + +  // Now create the true branch. +  { +    // Save the current values for Succ, continue and break targets. +    SaveAndRestore<CFGBlock*> save_Succ(Succ); +    SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget), +        save_break(BreakJumpTarget); + +    BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); +    ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos); + +    CFGBlock *BodyBlock = addStmt(S->getBody()); + +    if (!BodyBlock) +      BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;" +    else if (Block) { +      if (badCFG) +        return 0; +    } + +    // This new body block is a successor to our "exit" condition block. +    addSuccessor(ExitConditionBlock, BodyBlock); +  } + +  // Link up the condition block with the code that follows the loop. +  // (the false branch). +  addSuccessor(ExitConditionBlock, LoopSuccessor); + +  // Now create a prologue block to contain the collection expression. +  Block = createBlock(); +  return addStmt(S->getCollection()); +} + +CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { +  // Inline the body. +  return addStmt(S->getSubStmt()); +  // TODO: consider adding cleanups for the end of @autoreleasepool scope. +} + +CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { +  // FIXME: Add locking 'primitives' to CFG for @synchronized. + +  // Inline the body. +  CFGBlock *SyncBlock = addStmt(S->getSynchBody()); + +  // The sync body starts its own basic block.  This makes it a little easier +  // for diagnostic clients. +  if (SyncBlock) { +    if (badCFG) +      return 0; + +    Block = 0; +    Succ = SyncBlock; +  } + +  // Add the @synchronized to the CFG. +  autoCreateBlock(); +  appendStmt(Block, S); + +  // Inline the sync expression. +  return addStmt(S->getSynchExpr()); +} + +CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { +  // FIXME +  return NYS(); +} + +CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) { +  autoCreateBlock(); + +  // Add the PseudoObject as the last thing. +  appendStmt(Block, E); + +  CFGBlock *lastBlock = Block;   + +  // Before that, evaluate all of the semantics in order.  In +  // CFG-land, that means appending them in reverse order. +  for (unsigned i = E->getNumSemanticExprs(); i != 0; ) { +    Expr *Semantic = E->getSemanticExpr(--i); + +    // If the semantic is an opaque value, we're being asked to bind +    // it to its source expression. +    if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic)) +      Semantic = OVE->getSourceExpr(); + +    if (CFGBlock *B = Visit(Semantic)) +      lastBlock = B; +  } + +  return lastBlock; +} + +CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { +  CFGBlock *LoopSuccessor = NULL; + +  // Save local scope position because in case of condition variable ScopePos +  // won't be restored when traversing AST. +  SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + +  // Create local scope for possible condition variable. +  // Store scope position for continue statement. +  LocalScope::const_iterator LoopBeginScopePos = ScopePos; +  if (VarDecl *VD = W->getConditionVariable()) { +    addLocalScopeForVarDecl(VD); +    addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); +  } + +  // "while" is a control-flow statement.  Thus we stop processing the current +  // block. +  if (Block) { +    if (badCFG) +      return 0; +    LoopSuccessor = Block; +    Block = 0; +  } else +    LoopSuccessor = Succ; + +  // Because of short-circuit evaluation, the condition of the loop can span +  // multiple basic blocks.  Thus we need the "Entry" and "Exit" blocks that +  // evaluate the condition. +  CFGBlock *ExitConditionBlock = createBlock(false); +  CFGBlock *EntryConditionBlock = ExitConditionBlock; + +  // Set the terminator for the "exit" condition block. +  ExitConditionBlock->setTerminator(W); + +  // Now add the actual condition to the condition block.  Because the condition +  // itself may contain control-flow, new blocks may be created.  Thus we update +  // "Succ" after adding the condition. +  if (Stmt *C = W->getCond()) { +    Block = ExitConditionBlock; +    EntryConditionBlock = addStmt(C); +    // The condition might finish the current 'Block'. +    Block = EntryConditionBlock; + +    // If this block contains a condition variable, add both the condition +    // variable and initializer to the CFG. +    if (VarDecl *VD = W->getConditionVariable()) { +      if (Expr *Init = VD->getInit()) { +        autoCreateBlock(); +        appendStmt(Block, W->getConditionVariableDeclStmt());         +        EntryConditionBlock = addStmt(Init); +        assert(Block == EntryConditionBlock); +      } +    } + +    if (Block) { +      if (badCFG) +        return 0; +    } +  } + +  // The condition block is the implicit successor for the loop body as well as +  // any code above the loop. +  Succ = EntryConditionBlock; + +  // See if this is a known constant. +  const TryResult& KnownVal = tryEvaluateBool(W->getCond()); + +  // Process the loop body. +  { +    assert(W->getBody()); + +    // Save the current values for Block, Succ, and continue and break targets +    SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); +    SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget), +        save_break(BreakJumpTarget); + +    // Create an empty block to represent the transition block for looping back +    // to the head of the loop. +    Block = 0; +    assert(Succ == EntryConditionBlock); +    Succ = createBlock(); +    Succ->setLoopTarget(W); +    ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos); + +    // All breaks should go to the code following the loop. +    BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); + +    // NULL out Block to force lazy instantiation of blocks for the body. +    Block = NULL; + +    // Loop body should end with destructor of Condition variable (if any). +    addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); + +    // If body is not a compound statement create implicit scope +    // and add destructors. +    if (!isa<CompoundStmt>(W->getBody())) +      addLocalScopeAndDtors(W->getBody()); + +    // Create the body.  The returned block is the entry to the loop body. +    CFGBlock *BodyBlock = addStmt(W->getBody()); + +    if (!BodyBlock) +      BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;" +    else if (Block) { +      if (badCFG) +        return 0; +    } + +    // Add the loop body entry as a successor to the condition. +    addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock); +  } + +  // Link up the condition block with the code that follows the loop.  (the +  // false branch). +  addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + +  // There can be no more statements in the condition block since we loop back +  // to this block.  NULL out Block to force lazy creation of another block. +  Block = NULL; + +  // Return the condition block, which is the dominating block for the loop. +  Succ = EntryConditionBlock; +  return EntryConditionBlock; +} + + +CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { +  // FIXME: For now we pretend that @catch and the code it contains does not +  //  exit. +  return Block; +} + +CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { +  // FIXME: This isn't complete.  We basically treat @throw like a return +  //  statement. + +  // If we were in the middle of a block we stop processing that block. +  if (badCFG) +    return 0; + +  // Create the new block. +  Block = createBlock(false); + +  // The Exit block is the only successor. +  addSuccessor(Block, &cfg->getExit()); + +  // Add the statement to the block.  This may create new blocks if S contains +  // control-flow (short-circuit operations). +  return VisitStmt(S, AddStmtChoice::AlwaysAdd); +} + +CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) { +  // If we were in the middle of a block we stop processing that block. +  if (badCFG) +    return 0; + +  // Create the new block. +  Block = createBlock(false); + +  if (TryTerminatedBlock) +    // The current try statement is the only successor. +    addSuccessor(Block, TryTerminatedBlock); +  else +    // otherwise the Exit block is the only successor. +    addSuccessor(Block, &cfg->getExit()); + +  // Add the statement to the block.  This may create new blocks if S contains +  // control-flow (short-circuit operations). +  return VisitStmt(T, AddStmtChoice::AlwaysAdd); +} + +CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) { +  CFGBlock *LoopSuccessor = NULL; + +  // "do...while" is a control-flow statement.  Thus we stop processing the +  // current block. +  if (Block) { +    if (badCFG) +      return 0; +    LoopSuccessor = Block; +  } else +    LoopSuccessor = Succ; + +  // Because of short-circuit evaluation, the condition of the loop can span +  // multiple basic blocks.  Thus we need the "Entry" and "Exit" blocks that +  // evaluate the condition. +  CFGBlock *ExitConditionBlock = createBlock(false); +  CFGBlock *EntryConditionBlock = ExitConditionBlock; + +  // Set the terminator for the "exit" condition block. +  ExitConditionBlock->setTerminator(D); + +  // Now add the actual condition to the condition block.  Because the condition +  // itself may contain control-flow, new blocks may be created. +  if (Stmt *C = D->getCond()) { +    Block = ExitConditionBlock; +    EntryConditionBlock = addStmt(C); +    if (Block) { +      if (badCFG) +        return 0; +    } +  } + +  // The condition block is the implicit successor for the loop body. +  Succ = EntryConditionBlock; + +  // See if this is a known constant. +  const TryResult &KnownVal = tryEvaluateBool(D->getCond()); + +  // Process the loop body. +  CFGBlock *BodyBlock = NULL; +  { +    assert(D->getBody()); + +    // Save the current values for Block, Succ, and continue and break targets +    SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); +    SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget), +        save_break(BreakJumpTarget); + +    // All continues within this loop should go to the condition block +    ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos); + +    // All breaks should go to the code following the loop. +    BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); + +    // NULL out Block to force lazy instantiation of blocks for the body. +    Block = NULL; + +    // If body is not a compound statement create implicit scope +    // and add destructors. +    if (!isa<CompoundStmt>(D->getBody())) +      addLocalScopeAndDtors(D->getBody()); + +    // Create the body.  The returned block is the entry to the loop body. +    BodyBlock = addStmt(D->getBody()); + +    if (!BodyBlock) +      BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)" +    else if (Block) { +      if (badCFG) +        return 0; +    } + +    if (!KnownVal.isFalse()) { +      // Add an intermediate block between the BodyBlock and the +      // ExitConditionBlock to represent the "loop back" transition.  Create an +      // empty block to represent the transition block for looping back to the +      // head of the loop. +      // FIXME: Can we do this more efficiently without adding another block? +      Block = NULL; +      Succ = BodyBlock; +      CFGBlock *LoopBackBlock = createBlock(); +      LoopBackBlock->setLoopTarget(D); + +      // Add the loop body entry as a successor to the condition. +      addSuccessor(ExitConditionBlock, LoopBackBlock); +    } +    else +      addSuccessor(ExitConditionBlock, NULL); +  } + +  // Link up the condition block with the code that follows the loop. +  // (the false branch). +  addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + +  // There can be no more statements in the body block(s) since we loop back to +  // the body.  NULL out Block to force lazy creation of another block. +  Block = NULL; + +  // Return the loop body, which is the dominating block for the loop. +  Succ = BodyBlock; +  return BodyBlock; +} + +CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) { +  // "continue" is a control-flow statement.  Thus we stop processing the +  // current block. +  if (badCFG) +    return 0; + +  // Now create a new block that ends with the continue statement. +  Block = createBlock(false); +  Block->setTerminator(C); + +  // If there is no target for the continue, then we are looking at an +  // incomplete AST.  This means the CFG cannot be constructed. +  if (ContinueJumpTarget.block) { +    addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C); +    addSuccessor(Block, ContinueJumpTarget.block); +  } else +    badCFG = true; + +  return Block; +} + +CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, +                                                    AddStmtChoice asc) { + +  if (asc.alwaysAdd(*this, E)) { +    autoCreateBlock(); +    appendStmt(Block, E); +  } + +  // VLA types have expressions that must be evaluated. +  CFGBlock *lastBlock = Block; +   +  if (E->isArgumentType()) { +    for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr()); +         VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) +      lastBlock = addStmt(VA->getSizeExpr()); +  } +  return lastBlock; +} + +/// VisitStmtExpr - Utility method to handle (nested) statement +///  expressions (a GCC extension). +CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, SE)) { +    autoCreateBlock(); +    appendStmt(Block, SE); +  } +  return VisitCompoundStmt(SE->getSubStmt()); +} + +CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) { +  // "switch" is a control-flow statement.  Thus we stop processing the current +  // block. +  CFGBlock *SwitchSuccessor = NULL; + +  // Save local scope position because in case of condition variable ScopePos +  // won't be restored when traversing AST. +  SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + +  // Create local scope for possible condition variable. +  // Store scope position. Add implicit destructor. +  if (VarDecl *VD = Terminator->getConditionVariable()) { +    LocalScope::const_iterator SwitchBeginScopePos = ScopePos; +    addLocalScopeForVarDecl(VD); +    addAutomaticObjDtors(ScopePos, SwitchBeginScopePos, Terminator); +  } + +  if (Block) { +    if (badCFG) +      return 0; +    SwitchSuccessor = Block; +  } else SwitchSuccessor = Succ; + +  // Save the current "switch" context. +  SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock), +                            save_default(DefaultCaseBlock); +  SaveAndRestore<JumpTarget> save_break(BreakJumpTarget); + +  // Set the "default" case to be the block after the switch statement.  If the +  // switch statement contains a "default:", this value will be overwritten with +  // the block for that code. +  DefaultCaseBlock = SwitchSuccessor; + +  // Create a new block that will contain the switch statement. +  SwitchTerminatedBlock = createBlock(false); + +  // Now process the switch body.  The code after the switch is the implicit +  // successor. +  Succ = SwitchSuccessor; +  BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos); + +  // When visiting the body, the case statements should automatically get linked +  // up to the switch.  We also don't keep a pointer to the body, since all +  // control-flow from the switch goes to case/default statements. +  assert(Terminator->getBody() && "switch must contain a non-NULL body"); +  Block = NULL; + +  // For pruning unreachable case statements, save the current state +  // for tracking the condition value. +  SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered, +                                                     false); + +  // Determine if the switch condition can be explicitly evaluated. +  assert(Terminator->getCond() && "switch condition must be non-NULL"); +  Expr::EvalResult result; +  bool b = tryEvaluate(Terminator->getCond(), result); +  SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond, +                                                    b ? &result : 0); + +  // If body is not a compound statement create implicit scope +  // and add destructors. +  if (!isa<CompoundStmt>(Terminator->getBody())) +    addLocalScopeAndDtors(Terminator->getBody()); + +  addStmt(Terminator->getBody()); +  if (Block) { +    if (badCFG) +      return 0; +  } + +  // If we have no "default:" case, the default transition is to the code +  // following the switch body.  Moreover, take into account if all the +  // cases of a switch are covered (e.g., switching on an enum value). +  addSuccessor(SwitchTerminatedBlock, +               switchExclusivelyCovered || Terminator->isAllEnumCasesCovered() +               ? 0 : DefaultCaseBlock); + +  // Add the terminator and condition in the switch block. +  SwitchTerminatedBlock->setTerminator(Terminator); +  Block = SwitchTerminatedBlock; +  Block = addStmt(Terminator->getCond()); + +  // Finally, if the SwitchStmt contains a condition variable, add both the +  // SwitchStmt and the condition variable initialization to the CFG. +  if (VarDecl *VD = Terminator->getConditionVariable()) { +    if (Expr *Init = VD->getInit()) { +      autoCreateBlock(); +      appendStmt(Block, Terminator->getConditionVariableDeclStmt()); +      addStmt(Init); +    } +  } + +  return Block; +} +   +static bool shouldAddCase(bool &switchExclusivelyCovered, +                          const Expr::EvalResult *switchCond, +                          const CaseStmt *CS, +                          ASTContext &Ctx) { +  if (!switchCond) +    return true; + +  bool addCase = false; + +  if (!switchExclusivelyCovered) { +    if (switchCond->Val.isInt()) { +      // Evaluate the LHS of the case value. +      const llvm::APSInt &lhsInt = CS->getLHS()->EvaluateKnownConstInt(Ctx); +      const llvm::APSInt &condInt = switchCond->Val.getInt(); +       +      if (condInt == lhsInt) { +        addCase = true; +        switchExclusivelyCovered = true; +      } +      else if (condInt < lhsInt) { +        if (const Expr *RHS = CS->getRHS()) { +          // Evaluate the RHS of the case value. +          const llvm::APSInt &V2 = RHS->EvaluateKnownConstInt(Ctx); +          if (V2 <= condInt) { +            addCase = true; +            switchExclusivelyCovered = true; +          } +        } +      } +    } +    else +      addCase = true; +  } +  return addCase;   +} + +CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) { +  // CaseStmts are essentially labels, so they are the first statement in a +  // block. +  CFGBlock *TopBlock = 0, *LastBlock = 0; + +  if (Stmt *Sub = CS->getSubStmt()) { +    // For deeply nested chains of CaseStmts, instead of doing a recursion +    // (which can blow out the stack), manually unroll and create blocks +    // along the way. +    while (isa<CaseStmt>(Sub)) { +      CFGBlock *currentBlock = createBlock(false); +      currentBlock->setLabel(CS); + +      if (TopBlock) +        addSuccessor(LastBlock, currentBlock); +      else +        TopBlock = currentBlock; + +      addSuccessor(SwitchTerminatedBlock, +                   shouldAddCase(switchExclusivelyCovered, switchCond, +                                 CS, *Context) +                   ? currentBlock : 0); + +      LastBlock = currentBlock; +      CS = cast<CaseStmt>(Sub); +      Sub = CS->getSubStmt(); +    } + +    addStmt(Sub); +  } + +  CFGBlock *CaseBlock = Block; +  if (!CaseBlock) +    CaseBlock = createBlock(); + +  // Cases statements partition blocks, so this is the top of the basic block we +  // were processing (the "case XXX:" is the label). +  CaseBlock->setLabel(CS); + +  if (badCFG) +    return 0; + +  // Add this block to the list of successors for the block with the switch +  // statement. +  assert(SwitchTerminatedBlock); +  addSuccessor(SwitchTerminatedBlock, +               shouldAddCase(switchExclusivelyCovered, switchCond, +                             CS, *Context) +               ? CaseBlock : 0); + +  // We set Block to NULL to allow lazy creation of a new block (if necessary) +  Block = NULL; + +  if (TopBlock) { +    addSuccessor(LastBlock, CaseBlock); +    Succ = TopBlock; +  } else { +    // This block is now the implicit successor of other blocks. +    Succ = CaseBlock; +  } + +  return Succ; +} + +CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) { +  if (Terminator->getSubStmt()) +    addStmt(Terminator->getSubStmt()); + +  DefaultCaseBlock = Block; + +  if (!DefaultCaseBlock) +    DefaultCaseBlock = createBlock(); + +  // Default statements partition blocks, so this is the top of the basic block +  // we were processing (the "default:" is the label). +  DefaultCaseBlock->setLabel(Terminator); + +  if (badCFG) +    return 0; + +  // Unlike case statements, we don't add the default block to the successors +  // for the switch statement immediately.  This is done when we finish +  // processing the switch statement.  This allows for the default case +  // (including a fall-through to the code after the switch statement) to always +  // be the last successor of a switch-terminated block. + +  // We set Block to NULL to allow lazy creation of a new block (if necessary) +  Block = NULL; + +  // This block is now the implicit successor of other blocks. +  Succ = DefaultCaseBlock; + +  return DefaultCaseBlock; +} + +CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { +  // "try"/"catch" is a control-flow statement.  Thus we stop processing the +  // current block. +  CFGBlock *TrySuccessor = NULL; + +  if (Block) { +    if (badCFG) +      return 0; +    TrySuccessor = Block; +  } else TrySuccessor = Succ; + +  CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock; + +  // Create a new block that will contain the try statement. +  CFGBlock *NewTryTerminatedBlock = createBlock(false); +  // Add the terminator in the try block. +  NewTryTerminatedBlock->setTerminator(Terminator); + +  bool HasCatchAll = false; +  for (unsigned h = 0; h <Terminator->getNumHandlers(); ++h) { +    // The code after the try is the implicit successor. +    Succ = TrySuccessor; +    CXXCatchStmt *CS = Terminator->getHandler(h); +    if (CS->getExceptionDecl() == 0) { +      HasCatchAll = true; +    } +    Block = NULL; +    CFGBlock *CatchBlock = VisitCXXCatchStmt(CS); +    if (CatchBlock == 0) +      return 0; +    // Add this block to the list of successors for the block with the try +    // statement. +    addSuccessor(NewTryTerminatedBlock, CatchBlock); +  } +  if (!HasCatchAll) { +    if (PrevTryTerminatedBlock) +      addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock); +    else +      addSuccessor(NewTryTerminatedBlock, &cfg->getExit()); +  } + +  // The code after the try is the implicit successor. +  Succ = TrySuccessor; + +  // Save the current "try" context. +  SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock, NewTryTerminatedBlock); +  cfg->addTryDispatchBlock(TryTerminatedBlock); + +  assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); +  Block = NULL; +  Block = addStmt(Terminator->getTryBlock()); +  return Block; +} + +CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { +  // CXXCatchStmt are treated like labels, so they are the first statement in a +  // block. + +  // Save local scope position because in case of exception variable ScopePos +  // won't be restored when traversing AST. +  SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + +  // Create local scope for possible exception variable. +  // Store scope position. Add implicit destructor. +  if (VarDecl *VD = CS->getExceptionDecl()) { +    LocalScope::const_iterator BeginScopePos = ScopePos; +    addLocalScopeForVarDecl(VD); +    addAutomaticObjDtors(ScopePos, BeginScopePos, CS); +  } + +  if (CS->getHandlerBlock()) +    addStmt(CS->getHandlerBlock()); + +  CFGBlock *CatchBlock = Block; +  if (!CatchBlock) +    CatchBlock = createBlock(); +   +  // CXXCatchStmt is more than just a label.  They have semantic meaning +  // as well, as they implicitly "initialize" the catch variable.  Add +  // it to the CFG as a CFGElement so that the control-flow of these +  // semantics gets captured. +  appendStmt(CatchBlock, CS); + +  // Also add the CXXCatchStmt as a label, to mirror handling of regular +  // labels. +  CatchBlock->setLabel(CS); + +  // Bail out if the CFG is bad. +  if (badCFG) +    return 0; + +  // We set Block to NULL to allow lazy creation of a new block (if necessary) +  Block = NULL; + +  return CatchBlock; +} + +CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { +  // C++0x for-range statements are specified as [stmt.ranged]: +  // +  // { +  //   auto && __range = range-init; +  //   for ( auto __begin = begin-expr, +  //         __end = end-expr; +  //         __begin != __end; +  //         ++__begin ) { +  //     for-range-declaration = *__begin; +  //     statement +  //   } +  // } + +  // Save local scope position before the addition of the implicit variables. +  SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + +  // Create local scopes and destructors for range, begin and end variables. +  if (Stmt *Range = S->getRangeStmt()) +    addLocalScopeForStmt(Range); +  if (Stmt *BeginEnd = S->getBeginEndStmt()) +    addLocalScopeForStmt(BeginEnd); +  addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S); + +  LocalScope::const_iterator ContinueScopePos = ScopePos; + +  // "for" is a control-flow statement.  Thus we stop processing the current +  // block. +  CFGBlock *LoopSuccessor = NULL; +  if (Block) { +    if (badCFG) +      return 0; +    LoopSuccessor = Block; +  } else +    LoopSuccessor = Succ; + +  // Save the current value for the break targets. +  // All breaks should go to the code following the loop. +  SaveAndRestore<JumpTarget> save_break(BreakJumpTarget); +  BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); + +  // The block for the __begin != __end expression. +  CFGBlock *ConditionBlock = createBlock(false); +  ConditionBlock->setTerminator(S); + +  // Now add the actual condition to the condition block. +  if (Expr *C = S->getCond()) { +    Block = ConditionBlock; +    CFGBlock *BeginConditionBlock = addStmt(C); +    if (badCFG) +      return 0; +    assert(BeginConditionBlock == ConditionBlock && +           "condition block in for-range was unexpectedly complex"); +    (void)BeginConditionBlock; +  } + +  // The condition block is the implicit successor for the loop body as well as +  // any code above the loop. +  Succ = ConditionBlock; + +  // See if this is a known constant. +  TryResult KnownVal(true); + +  if (S->getCond()) +    KnownVal = tryEvaluateBool(S->getCond()); + +  // Now create the loop body. +  { +    assert(S->getBody()); + +    // Save the current values for Block, Succ, and continue targets. +    SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); +    SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget); + +    // Generate increment code in its own basic block.  This is the target of +    // continue statements. +    Block = 0; +    Succ = addStmt(S->getInc()); +    ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos); + +    // The starting block for the loop increment is the block that should +    // represent the 'loop target' for looping back to the start of the loop. +    ContinueJumpTarget.block->setLoopTarget(S); + +    // Finish up the increment block and prepare to start the loop body. +    assert(Block); +    if (badCFG) +      return 0; +    Block = 0; + + +    // Add implicit scope and dtors for loop variable. +    addLocalScopeAndDtors(S->getLoopVarStmt()); + +    // Populate a new block to contain the loop body and loop variable. +    Block = addStmt(S->getBody()); +    if (badCFG) +      return 0; +    Block = addStmt(S->getLoopVarStmt()); +    if (badCFG) +      return 0; +     +    // This new body block is a successor to our condition block. +    addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block); +  } + +  // Link up the condition block with the code that follows the loop (the +  // false branch). +  addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor); + +  // Add the initialization statements. +  Block = createBlock(); +  addStmt(S->getBeginEndStmt()); +  return addStmt(S->getRangeStmt()); +} + +CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, +    AddStmtChoice asc) { +  if (BuildOpts.AddImplicitDtors) { +    // If adding implicit destructors visit the full expression for adding +    // destructors of temporaries. +    VisitForTemporaryDtors(E->getSubExpr()); + +    // Full expression has to be added as CFGStmt so it will be sequenced +    // before destructors of it's temporaries. +    asc = asc.withAlwaysAdd(true); +  } +  return Visit(E->getSubExpr(), asc); +} + +CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, +                                                AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, E)) { +    autoCreateBlock(); +    appendStmt(Block, E); + +    // We do not want to propagate the AlwaysAdd property. +    asc = asc.withAlwaysAdd(false); +  } +  return Visit(E->getSubExpr(), asc); +} + +CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C, +                                            AddStmtChoice asc) { +  autoCreateBlock(); +  appendStmt(Block, C); + +  return VisitChildren(C); +} + +CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E, +                                                 AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, E)) { +    autoCreateBlock(); +    appendStmt(Block, E); +    // We do not want to propagate the AlwaysAdd property. +    asc = asc.withAlwaysAdd(false); +  } +  return Visit(E->getSubExpr(), asc); +} + +CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, +                                                  AddStmtChoice asc) { +  autoCreateBlock(); +  appendStmt(Block, C); +  return VisitChildren(C); +} + +CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E, +                                            AddStmtChoice asc) { +  if (asc.alwaysAdd(*this, E)) { +    autoCreateBlock(); +    appendStmt(Block, E); +  } +  return Visit(E->getSubExpr(), AddStmtChoice()); +} + +CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) { +  // Lazily create the indirect-goto dispatch block if there isn't one already. +  CFGBlock *IBlock = cfg->getIndirectGotoBlock(); + +  if (!IBlock) { +    IBlock = createBlock(false); +    cfg->setIndirectGotoBlock(IBlock); +  } + +  // IndirectGoto is a control-flow statement.  Thus we stop processing the +  // current block and create a new one. +  if (badCFG) +    return 0; + +  Block = createBlock(false); +  Block->setTerminator(I); +  addSuccessor(Block, IBlock); +  return addStmt(I->getTarget()); +} + +CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) { +tryAgain: +  if (!E) { +    badCFG = true; +    return NULL; +  } +  switch (E->getStmtClass()) { +    default: +      return VisitChildrenForTemporaryDtors(E); + +    case Stmt::BinaryOperatorClass: +      return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E)); + +    case Stmt::CXXBindTemporaryExprClass: +      return VisitCXXBindTemporaryExprForTemporaryDtors( +          cast<CXXBindTemporaryExpr>(E), BindToTemporary); + +    case Stmt::BinaryConditionalOperatorClass: +    case Stmt::ConditionalOperatorClass: +      return VisitConditionalOperatorForTemporaryDtors( +          cast<AbstractConditionalOperator>(E), BindToTemporary); + +    case Stmt::ImplicitCastExprClass: +      // For implicit cast we want BindToTemporary to be passed further. +      E = cast<CastExpr>(E)->getSubExpr(); +      goto tryAgain; + +    case Stmt::ParenExprClass: +      E = cast<ParenExpr>(E)->getSubExpr(); +      goto tryAgain; +       +    case Stmt::MaterializeTemporaryExprClass: +      E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(); +      goto tryAgain; +  } +} + +CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) { +  // When visiting children for destructors we want to visit them in reverse +  // order. Because there's no reverse iterator for children must to reverse +  // them in helper vector. +  typedef SmallVector<Stmt *, 4> ChildrenVect; +  ChildrenVect ChildrenRev; +  for (Stmt::child_range I = E->children(); I; ++I) { +    if (*I) ChildrenRev.push_back(*I); +  } + +  CFGBlock *B = Block; +  for (ChildrenVect::reverse_iterator I = ChildrenRev.rbegin(), +      L = ChildrenRev.rend(); I != L; ++I) { +    if (CFGBlock *R = VisitForTemporaryDtors(*I)) +      B = R; +  } +  return B; +} + +CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E) { +  if (E->isLogicalOp()) { +    // Destructors for temporaries in LHS expression should be called after +    // those for RHS expression. Even if this will unnecessarily create a block, +    // this block will be used at least by the full expression. +    autoCreateBlock(); +    CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getLHS()); +    if (badCFG) +      return NULL; + +    Succ = ConfluenceBlock; +    Block = NULL; +    CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS()); + +    if (RHSBlock) { +      if (badCFG) +        return NULL; + +      // If RHS expression did produce destructors we need to connect created +      // blocks to CFG in same manner as for binary operator itself. +      CFGBlock *LHSBlock = createBlock(false); +      LHSBlock->setTerminator(CFGTerminator(E, true)); + +      // For binary operator LHS block is before RHS in list of predecessors +      // of ConfluenceBlock. +      std::reverse(ConfluenceBlock->pred_begin(), +          ConfluenceBlock->pred_end()); + +      // See if this is a known constant. +      TryResult KnownVal = tryEvaluateBool(E->getLHS()); +      if (KnownVal.isKnown() && (E->getOpcode() == BO_LOr)) +        KnownVal.negate(); + +      // Link LHSBlock with RHSBlock exactly the same way as for binary operator +      // itself. +      if (E->getOpcode() == BO_LOr) { +        addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); +        addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); +      } else { +        assert (E->getOpcode() == BO_LAnd); +        addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); +        addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); +      } + +      Block = LHSBlock; +      return LHSBlock; +    } + +    Block = ConfluenceBlock; +    return ConfluenceBlock; +  } + +  if (E->isAssignmentOp()) { +    // For assignment operator (=) LHS expression is visited +    // before RHS expression. For destructors visit them in reverse order. +    CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS()); +    CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS()); +    return LHSBlock ? LHSBlock : RHSBlock; +  } + +  // For any other binary operator RHS expression is visited before +  // LHS expression (order of children). For destructors visit them in reverse +  // order. +  CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS()); +  CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS()); +  return RHSBlock ? RHSBlock : LHSBlock; +} + +CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( +    CXXBindTemporaryExpr *E, bool BindToTemporary) { +  // First add destructors for temporaries in subexpression. +  CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr()); +  if (!BindToTemporary) { +    // If lifetime of temporary is not prolonged (by assigning to constant +    // reference) add destructor for it. + +    // If the destructor is marked as a no-return destructor, we need to create +    // a new block for the destructor which does not have as a successor +    // anything built thus far. Control won't flow out of this block. +    const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor(); +    if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) +      Block = createNoReturnBlock(); +    else +      autoCreateBlock(); + +    appendTemporaryDtor(Block, E); +    B = Block; +  } +  return B; +} + +CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( +    AbstractConditionalOperator *E, bool BindToTemporary) { +  // First add destructors for condition expression.  Even if this will +  // unnecessarily create a block, this block will be used at least by the full +  // expression. +  autoCreateBlock(); +  CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond()); +  if (badCFG) +    return NULL; +  if (BinaryConditionalOperator *BCO +        = dyn_cast<BinaryConditionalOperator>(E)) { +    ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon()); +    if (badCFG) +      return NULL; +  } + +  // Try to add block with destructors for LHS expression. +  CFGBlock *LHSBlock = NULL; +  Succ = ConfluenceBlock; +  Block = NULL; +  LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary); +  if (badCFG) +    return NULL; + +  // Try to add block with destructors for RHS expression; +  Succ = ConfluenceBlock; +  Block = NULL; +  CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(), +                                              BindToTemporary); +  if (badCFG) +    return NULL; + +  if (!RHSBlock && !LHSBlock) { +    // If neither LHS nor RHS expression had temporaries to destroy don't create +    // more blocks. +    Block = ConfluenceBlock; +    return Block; +  } + +  Block = createBlock(false); +  Block->setTerminator(CFGTerminator(E, true)); + +  // See if this is a known constant. +  const TryResult &KnownVal = tryEvaluateBool(E->getCond()); + +  if (LHSBlock) { +    addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock); +  } else if (KnownVal.isFalse()) { +    addSuccessor(Block, NULL); +  } else { +    addSuccessor(Block, ConfluenceBlock); +    std::reverse(ConfluenceBlock->pred_begin(), ConfluenceBlock->pred_end()); +  } + +  if (!RHSBlock) +    RHSBlock = ConfluenceBlock; +  addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock); + +  return Block; +} + +} // end anonymous namespace + +/// createBlock - Constructs and adds a new CFGBlock to the CFG.  The block has +///  no successors or predecessors.  If this is the first block created in the +///  CFG, it is automatically set to be the Entry and Exit of the CFG. +CFGBlock *CFG::createBlock() { +  bool first_block = begin() == end(); + +  // Create the block. +  CFGBlock *Mem = getAllocator().Allocate<CFGBlock>(); +  new (Mem) CFGBlock(NumBlockIDs++, BlkBVC, this); +  Blocks.push_back(Mem, BlkBVC); + +  // If this is the first block, set it as the Entry and Exit. +  if (first_block) +    Entry = Exit = &back(); + +  // Return the block. +  return &back(); +} + +/// buildCFG - Constructs a CFG from an AST.  Ownership of the returned +///  CFG is returned to the caller. +CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, +    const BuildOptions &BO) { +  CFGBuilder Builder(C, BO); +  return Builder.buildCFG(D, Statement); +} + +const CXXDestructorDecl * +CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { +  switch (getKind()) { +    case CFGElement::Invalid: +    case CFGElement::Statement: +    case CFGElement::Initializer: +      llvm_unreachable("getDestructorDecl should only be used with " +                       "ImplicitDtors"); +    case CFGElement::AutomaticObjectDtor: { +      const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl(); +      QualType ty = var->getType(); +      ty = ty.getNonReferenceType(); +      while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) { +        ty = arrayType->getElementType(); +      } +      const RecordType *recordType = ty->getAs<RecordType>(); +      const CXXRecordDecl *classDecl = +      cast<CXXRecordDecl>(recordType->getDecl()); +      return classDecl->getDestructor();       +    } +    case CFGElement::TemporaryDtor: { +      const CXXBindTemporaryExpr *bindExpr = +        cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr(); +      const CXXTemporary *temp = bindExpr->getTemporary(); +      return temp->getDestructor(); +    } +    case CFGElement::BaseDtor: +    case CFGElement::MemberDtor: + +      // Not yet supported. +      return 0; +  } +  llvm_unreachable("getKind() returned bogus value"); +} + +bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const { +  if (const CXXDestructorDecl *cdecl = getDestructorDecl(astContext)) { +    QualType ty = cdecl->getType(); +    return cast<FunctionType>(ty)->getNoReturnAttr(); +  } +  return false; +} + +//===----------------------------------------------------------------------===// +// CFG: Queries for BlkExprs. +//===----------------------------------------------------------------------===// + +namespace { +  typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy; +} + +static void FindSubExprAssignments(const Stmt *S, +                                   llvm::SmallPtrSet<const Expr*,50>& Set) { +  if (!S) +    return; + +  for (Stmt::const_child_range I = S->children(); I; ++I) { +    const Stmt *child = *I; +    if (!child) +      continue; + +    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(child)) +      if (B->isAssignmentOp()) Set.insert(B); + +    FindSubExprAssignments(child, Set); +  } +} + +static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { +  BlkExprMapTy* M = new BlkExprMapTy(); + +  // Look for assignments that are used as subexpressions.  These are the only +  // assignments that we want to *possibly* register as a block-level +  // expression.  Basically, if an assignment occurs both in a subexpression and +  // at the block-level, it is a block-level expression. +  llvm::SmallPtrSet<const Expr*,50> SubExprAssignments; + +  for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) +    for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) +      if (const CFGStmt *S = BI->getAs<CFGStmt>()) +        FindSubExprAssignments(S->getStmt(), SubExprAssignments); + +  for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) { + +    // Iterate over the statements again on identify the Expr* and Stmt* at the +    // block-level that are block-level expressions. + +    for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) { +      const CFGStmt *CS = BI->getAs<CFGStmt>(); +      if (!CS) +        continue; +      if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) { +        assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps"); + +        if (const BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) { +          // Assignment expressions that are not nested within another +          // expression are really "statements" whose value is never used by +          // another expression. +          if (B->isAssignmentOp() && !SubExprAssignments.count(Exp)) +            continue; +        } else if (const StmtExpr *SE = dyn_cast<StmtExpr>(Exp)) { +          // Special handling for statement expressions.  The last statement in +          // the statement expression is also a block-level expr. +          const CompoundStmt *C = SE->getSubStmt(); +          if (!C->body_empty()) { +            const Stmt *Last = C->body_back(); +            if (const Expr *LastEx = dyn_cast<Expr>(Last)) +              Last = LastEx->IgnoreParens(); +            unsigned x = M->size(); +            (*M)[Last] = x; +          } +        } + +        unsigned x = M->size(); +        (*M)[Exp] = x; +      } +    } + +    // Look at terminators.  The condition is a block-level expression. + +    Stmt *S = (*I)->getTerminatorCondition(); + +    if (S && M->find(S) == M->end()) { +      unsigned x = M->size(); +      (*M)[S] = x; +    } +  } + +  return M; +} + +CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt *S) { +  assert(S != NULL); +  if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); } + +  BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap); +  BlkExprMapTy::iterator I = M->find(S); +  return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second); +} + +unsigned CFG::getNumBlkExprs() { +  if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap)) +    return M->size(); + +  // We assume callers interested in the number of BlkExprs will want +  // the map constructed if it doesn't already exist. +  BlkExprMap = (void*) PopulateBlkExprMap(*this); +  return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size(); +} + +//===----------------------------------------------------------------------===// +// Filtered walking of the CFG. +//===----------------------------------------------------------------------===// + +bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F, +        const CFGBlock *From, const CFGBlock *To) { + +  if (To && F.IgnoreDefaultsWithCoveredEnums) { +    // If the 'To' has no label or is labeled but the label isn't a +    // CaseStmt then filter this edge. +    if (const SwitchStmt *S = +        dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) { +      if (S->isAllEnumCasesCovered()) { +        const Stmt *L = To->getLabel(); +        if (!L || !isa<CaseStmt>(L)) +          return true; +      } +    } +  } + +  return false; +} + +//===----------------------------------------------------------------------===// +// Cleanup: CFG dstor. +//===----------------------------------------------------------------------===// + +CFG::~CFG() { +  delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap); +} + +//===----------------------------------------------------------------------===// +// CFG pretty printing +//===----------------------------------------------------------------------===// + +namespace { + +class StmtPrinterHelper : public PrinterHelper  { +  typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; +  typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy; +  StmtMapTy StmtMap; +  DeclMapTy DeclMap; +  signed currentBlock; +  unsigned currentStmt; +  const LangOptions &LangOpts; +public: + +  StmtPrinterHelper(const CFG* cfg, const LangOptions &LO) +    : currentBlock(0), currentStmt(0), LangOpts(LO) +  { +    for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { +      unsigned j = 1; +      for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ; +           BI != BEnd; ++BI, ++j ) {         +        if (const CFGStmt *SE = BI->getAs<CFGStmt>()) { +          const Stmt *stmt= SE->getStmt(); +          std::pair<unsigned, unsigned> P((*I)->getBlockID(), j); +          StmtMap[stmt] = P; + +          switch (stmt->getStmtClass()) { +            case Stmt::DeclStmtClass: +                DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P; +                break; +            case Stmt::IfStmtClass: { +              const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable(); +              if (var) +                DeclMap[var] = P; +              break; +            } +            case Stmt::ForStmtClass: { +              const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable(); +              if (var) +                DeclMap[var] = P; +              break; +            } +            case Stmt::WhileStmtClass: { +              const VarDecl *var = +                cast<WhileStmt>(stmt)->getConditionVariable(); +              if (var) +                DeclMap[var] = P; +              break; +            } +            case Stmt::SwitchStmtClass: { +              const VarDecl *var = +                cast<SwitchStmt>(stmt)->getConditionVariable(); +              if (var) +                DeclMap[var] = P; +              break; +            } +            case Stmt::CXXCatchStmtClass: { +              const VarDecl *var = +                cast<CXXCatchStmt>(stmt)->getExceptionDecl(); +              if (var) +                DeclMap[var] = P; +              break; +            } +            default: +              break; +          } +        } +      } +    } +  } +   + +  virtual ~StmtPrinterHelper() {} + +  const LangOptions &getLangOpts() const { return LangOpts; } +  void setBlockID(signed i) { currentBlock = i; } +  void setStmtID(unsigned i) { currentStmt = i; } + +  virtual bool handledStmt(Stmt *S, raw_ostream &OS) { +    StmtMapTy::iterator I = StmtMap.find(S); + +    if (I == StmtMap.end()) +      return false; + +    if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock +                          && I->second.second == currentStmt) { +      return false; +    } + +    OS << "[B" << I->second.first << "." << I->second.second << "]"; +    return true; +  } + +  bool handleDecl(const Decl *D, raw_ostream &OS) { +    DeclMapTy::iterator I = DeclMap.find(D); + +    if (I == DeclMap.end()) +      return false; + +    if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock +                          && I->second.second == currentStmt) { +      return false; +    } + +    OS << "[B" << I->second.first << "." << I->second.second << "]"; +    return true; +  } +}; +} // end anonymous namespace + + +namespace { +class CFGBlockTerminatorPrint +  : public StmtVisitor<CFGBlockTerminatorPrint,void> { + +  raw_ostream &OS; +  StmtPrinterHelper* Helper; +  PrintingPolicy Policy; +public: +  CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper, +                          const PrintingPolicy &Policy) +    : OS(os), Helper(helper), Policy(Policy) {} + +  void VisitIfStmt(IfStmt *I) { +    OS << "if "; +    I->getCond()->printPretty(OS,Helper,Policy); +  } + +  // Default case. +  void VisitStmt(Stmt *Terminator) { +    Terminator->printPretty(OS, Helper, Policy); +  } + +  void VisitForStmt(ForStmt *F) { +    OS << "for (" ; +    if (F->getInit()) +      OS << "..."; +    OS << "; "; +    if (Stmt *C = F->getCond()) +      C->printPretty(OS, Helper, Policy); +    OS << "; "; +    if (F->getInc()) +      OS << "..."; +    OS << ")"; +  } + +  void VisitWhileStmt(WhileStmt *W) { +    OS << "while " ; +    if (Stmt *C = W->getCond()) +      C->printPretty(OS, Helper, Policy); +  } + +  void VisitDoStmt(DoStmt *D) { +    OS << "do ... while "; +    if (Stmt *C = D->getCond()) +      C->printPretty(OS, Helper, Policy); +  } + +  void VisitSwitchStmt(SwitchStmt *Terminator) { +    OS << "switch "; +    Terminator->getCond()->printPretty(OS, Helper, Policy); +  } + +  void VisitCXXTryStmt(CXXTryStmt *CS) { +    OS << "try ..."; +  } + +  void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) { +    C->getCond()->printPretty(OS, Helper, Policy); +    OS << " ? ... : ..."; +  } + +  void VisitChooseExpr(ChooseExpr *C) { +    OS << "__builtin_choose_expr( "; +    C->getCond()->printPretty(OS, Helper, Policy); +    OS << " )"; +  } + +  void VisitIndirectGotoStmt(IndirectGotoStmt *I) { +    OS << "goto *"; +    I->getTarget()->printPretty(OS, Helper, Policy); +  } + +  void VisitBinaryOperator(BinaryOperator* B) { +    if (!B->isLogicalOp()) { +      VisitExpr(B); +      return; +    } + +    B->getLHS()->printPretty(OS, Helper, Policy); + +    switch (B->getOpcode()) { +      case BO_LOr: +        OS << " || ..."; +        return; +      case BO_LAnd: +        OS << " && ..."; +        return; +      default: +        llvm_unreachable("Invalid logical operator."); +    } +  } + +  void VisitExpr(Expr *E) { +    E->printPretty(OS, Helper, Policy); +  } +}; +} // end anonymous namespace + +static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper, +                       const CFGElement &E) { +  if (const CFGStmt *CS = E.getAs<CFGStmt>()) { +    const Stmt *S = CS->getStmt(); +     +    if (Helper) { + +      // special printing for statement-expressions. +      if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) { +        const CompoundStmt *Sub = SE->getSubStmt(); + +        if (Sub->children()) { +          OS << "({ ... ; "; +          Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS); +          OS << " })\n"; +          return; +        } +      } +      // special printing for comma expressions. +      if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { +        if (B->getOpcode() == BO_Comma) { +          OS << "... , "; +          Helper->handledStmt(B->getRHS(),OS); +          OS << '\n'; +          return; +        } +      } +    } +    S->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); + +    if (isa<CXXOperatorCallExpr>(S)) { +      OS << " (OperatorCall)"; +    } +    else if (isa<CXXBindTemporaryExpr>(S)) { +      OS << " (BindTemporary)"; +    } +    else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) { +      OS << " (CXXConstructExpr, " << CCE->getType().getAsString() << ")"; +    } +    else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) { +      OS << " (" << CE->getStmtClassName() << ", " +         << CE->getCastKindName() +         << ", " << CE->getType().getAsString() +         << ")"; +    } + +    // Expressions need a newline. +    if (isa<Expr>(S)) +      OS << '\n'; + +  } else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) { +    const CXXCtorInitializer *I = IE->getInitializer(); +    if (I->isBaseInitializer()) +      OS << I->getBaseClass()->getAsCXXRecordDecl()->getName(); +    else OS << I->getAnyMember()->getName(); + +    OS << "("; +    if (Expr *IE = I->getInit()) +      IE->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); +    OS << ")"; + +    if (I->isBaseInitializer()) +      OS << " (Base initializer)\n"; +    else OS << " (Member initializer)\n"; + +  } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){ +    const VarDecl *VD = DE->getVarDecl(); +    Helper->handleDecl(VD, OS); + +    const Type* T = VD->getType().getTypePtr(); +    if (const ReferenceType* RT = T->getAs<ReferenceType>()) +      T = RT->getPointeeType().getTypePtr(); +    else if (const Type *ET = T->getArrayElementTypeNoTypeQual()) +      T = ET; + +    OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; +    OS << " (Implicit destructor)\n"; + +  } else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) { +    const CXXBaseSpecifier *BS = BE->getBaseSpecifier(); +    OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; +    OS << " (Base object destructor)\n"; + +  } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) { +    const FieldDecl *FD = ME->getFieldDecl(); + +    const Type *T = FD->getType().getTypePtr(); +    if (const Type *ET = T->getArrayElementTypeNoTypeQual()) +      T = ET; + +    OS << "this->" << FD->getName(); +    OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; +    OS << " (Member object destructor)\n"; + +  } else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) { +    const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr(); +    OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()"; +    OS << " (Temporary object destructor)\n"; +  } +} + +static void print_block(raw_ostream &OS, const CFG* cfg, +                        const CFGBlock &B, +                        StmtPrinterHelper* Helper, bool print_edges, +                        bool ShowColors) { + +  if (Helper) +    Helper->setBlockID(B.getBlockID()); + +  // Print the header. +  if (ShowColors) +    OS.changeColor(raw_ostream::YELLOW, true); +   +  OS << "\n [B" << B.getBlockID(); + +  if (&B == &cfg->getEntry()) +    OS << " (ENTRY)]\n"; +  else if (&B == &cfg->getExit()) +    OS << " (EXIT)]\n"; +  else if (&B == cfg->getIndirectGotoBlock()) +    OS << " (INDIRECT GOTO DISPATCH)]\n"; +  else +    OS << "]\n"; +   +  if (ShowColors) +    OS.resetColor(); + +  // Print the label of this block. +  if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) { + +    if (print_edges) +      OS << "  "; + +    if (LabelStmt *L = dyn_cast<LabelStmt>(Label)) +      OS << L->getName(); +    else if (CaseStmt *C = dyn_cast<CaseStmt>(Label)) { +      OS << "case "; +      C->getLHS()->printPretty(OS, Helper, +                               PrintingPolicy(Helper->getLangOpts())); +      if (C->getRHS()) { +        OS << " ... "; +        C->getRHS()->printPretty(OS, Helper, +                                 PrintingPolicy(Helper->getLangOpts())); +      } +    } else if (isa<DefaultStmt>(Label)) +      OS << "default"; +    else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) { +      OS << "catch ("; +      if (CS->getExceptionDecl()) +        CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()), +                                      0); +      else +        OS << "..."; +      OS << ")"; + +    } else +      llvm_unreachable("Invalid label statement in CFGBlock."); + +    OS << ":\n"; +  } + +  // Iterate through the statements in the block and print them. +  unsigned j = 1; + +  for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; +       I != E ; ++I, ++j ) { + +    // Print the statement # in the basic block and the statement itself. +    if (print_edges) +      OS << " "; + +    OS << llvm::format("%3d", j) << ": "; + +    if (Helper) +      Helper->setStmtID(j); + +    print_elem(OS, Helper, *I); +  } + +  // Print the terminator of this block. +  if (B.getTerminator()) { +    if (ShowColors) +      OS.changeColor(raw_ostream::GREEN); + +    OS << "   T: "; + +    if (Helper) Helper->setBlockID(-1); + +    CFGBlockTerminatorPrint TPrinter(OS, Helper, +                                     PrintingPolicy(Helper->getLangOpts())); +    TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt())); +    OS << '\n'; +     +    if (ShowColors) +      OS.resetColor(); +  } + +  if (print_edges) { +    // Print the predecessors of this block. +    if (!B.pred_empty()) { +      const raw_ostream::Colors Color = raw_ostream::BLUE; +      if (ShowColors) +        OS.changeColor(Color); +      OS << "   Preds " ; +      if (ShowColors) +        OS.resetColor(); +      OS << '(' << B.pred_size() << "):"; +      unsigned i = 0; + +      if (ShowColors) +        OS.changeColor(Color); +       +      for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end(); +           I != E; ++I, ++i) { + +        if (i == 8 || (i-8) == 0) +          OS << "\n     "; + +        OS << " B" << (*I)->getBlockID(); +      } +       +      if (ShowColors) +        OS.resetColor(); + +      OS << '\n'; +    } + +    // Print the successors of this block. +    if (!B.succ_empty()) { +      const raw_ostream::Colors Color = raw_ostream::MAGENTA; +      if (ShowColors) +        OS.changeColor(Color); +      OS << "   Succs "; +      if (ShowColors) +        OS.resetColor(); +      OS << '(' << B.succ_size() << "):"; +      unsigned i = 0; + +      if (ShowColors) +        OS.changeColor(Color); + +      for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); +           I != E; ++I, ++i) { + +        if (i == 8 || (i-8) % 10 == 0) +          OS << "\n    "; + +        if (*I) +          OS << " B" << (*I)->getBlockID(); +        else +          OS  << " NULL"; +      } +       +      if (ShowColors) +        OS.resetColor(); +      OS << '\n'; +    } +  } +} + + +/// dump - A simple pretty printer of a CFG that outputs to stderr. +void CFG::dump(const LangOptions &LO, bool ShowColors) const { +  print(llvm::errs(), LO, ShowColors); +} + +/// print - A simple pretty printer of a CFG that outputs to an ostream. +void CFG::print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const { +  StmtPrinterHelper Helper(this, LO); + +  // Print the entry block. +  print_block(OS, this, getEntry(), &Helper, true, ShowColors); + +  // Iterate through the CFGBlocks and print them one by one. +  for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { +    // Skip the entry block, because we already printed it. +    if (&(**I) == &getEntry() || &(**I) == &getExit()) +      continue; + +    print_block(OS, this, **I, &Helper, true, ShowColors); +  } + +  // Print the exit block. +  print_block(OS, this, getExit(), &Helper, true, ShowColors); +  OS << '\n'; +  OS.flush(); +} + +/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. +void CFGBlock::dump(const CFG* cfg, const LangOptions &LO, +                    bool ShowColors) const { +  print(llvm::errs(), cfg, LO, ShowColors); +} + +/// print - A simple pretty printer of a CFGBlock that outputs to an ostream. +///   Generally this will only be called from CFG::print. +void CFGBlock::print(raw_ostream &OS, const CFG* cfg, +                     const LangOptions &LO, bool ShowColors) const { +  StmtPrinterHelper Helper(cfg, LO); +  print_block(OS, cfg, *this, &Helper, true, ShowColors); +  OS << '\n'; +} + +/// printTerminator - A simple pretty printer of the terminator of a CFGBlock. +void CFGBlock::printTerminator(raw_ostream &OS, +                               const LangOptions &LO) const { +  CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO)); +  TPrinter.Visit(const_cast<Stmt*>(getTerminator().getStmt())); +} + +Stmt *CFGBlock::getTerminatorCondition() { +  Stmt *Terminator = this->Terminator; +  if (!Terminator) +    return NULL; + +  Expr *E = NULL; + +  switch (Terminator->getStmtClass()) { +    default: +      break; + +    case Stmt::ForStmtClass: +      E = cast<ForStmt>(Terminator)->getCond(); +      break; + +    case Stmt::WhileStmtClass: +      E = cast<WhileStmt>(Terminator)->getCond(); +      break; + +    case Stmt::DoStmtClass: +      E = cast<DoStmt>(Terminator)->getCond(); +      break; + +    case Stmt::IfStmtClass: +      E = cast<IfStmt>(Terminator)->getCond(); +      break; + +    case Stmt::ChooseExprClass: +      E = cast<ChooseExpr>(Terminator)->getCond(); +      break; + +    case Stmt::IndirectGotoStmtClass: +      E = cast<IndirectGotoStmt>(Terminator)->getTarget(); +      break; + +    case Stmt::SwitchStmtClass: +      E = cast<SwitchStmt>(Terminator)->getCond(); +      break; + +    case Stmt::BinaryConditionalOperatorClass: +      E = cast<BinaryConditionalOperator>(Terminator)->getCond(); +      break; + +    case Stmt::ConditionalOperatorClass: +      E = cast<ConditionalOperator>(Terminator)->getCond(); +      break; + +    case Stmt::BinaryOperatorClass: // '&&' and '||' +      E = cast<BinaryOperator>(Terminator)->getLHS(); +      break; + +    case Stmt::ObjCForCollectionStmtClass: +      return Terminator; +  } + +  return E ? E->IgnoreParens() : NULL; +} + +//===----------------------------------------------------------------------===// +// CFG Graphviz Visualization +//===----------------------------------------------------------------------===// + + +#ifndef NDEBUG +static StmtPrinterHelper* GraphHelper; +#endif + +void CFG::viewCFG(const LangOptions &LO) const { +#ifndef NDEBUG +  StmtPrinterHelper H(this, LO); +  GraphHelper = &H; +  llvm::ViewGraph(this,"CFG"); +  GraphHelper = NULL; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { + +  DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + +  static std::string getNodeLabel(const CFGBlock *Node, const CFG* Graph) { + +#ifndef NDEBUG +    std::string OutSStr; +    llvm::raw_string_ostream Out(OutSStr); +    print_block(Out,Graph, *Node, GraphHelper, false, false); +    std::string& OutStr = Out.str(); + +    if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + +    // Process string output to make it nicer... +    for (unsigned i = 0; i != OutStr.length(); ++i) +      if (OutStr[i] == '\n') {                            // Left justify +        OutStr[i] = '\\'; +        OutStr.insert(OutStr.begin()+i+1, 'l'); +      } + +    return OutStr; +#else +    return ""; +#endif +  } +}; +} // end namespace llvm diff --git a/clang/lib/Analysis/CFGReachabilityAnalysis.cpp b/clang/lib/Analysis/CFGReachabilityAnalysis.cpp new file mode 100644 index 0000000..e77e72f --- /dev/null +++ b/clang/lib/Analysis/CFGReachabilityAnalysis.cpp @@ -0,0 +1,76 @@ +//==- CFGReachabilityAnalysis.cpp - Basic reachability analysis --*- C++ -*-==// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a flow-sensitive, (mostly) path-insensitive reachability +// analysis based on Clang's CFGs.  Clients can query if a given basic block +// is reachable within the CFG. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/CFG.h" + +using namespace clang; + +CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(const CFG &cfg) +  : analyzed(cfg.getNumBlockIDs(), false) {} + +bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src, +                                          const CFGBlock *Dst) { + +  const unsigned DstBlockID = Dst->getBlockID(); +   +  // If we haven't analyzed the destination node, run the analysis now +  if (!analyzed[DstBlockID]) { +    mapReachability(Dst); +    analyzed[DstBlockID] = true; +  } +   +  // Return the cached result +  return reachable[DstBlockID][Src->getBlockID()]; +} + +// Maps reachability to a common node by walking the predecessors of the +// destination node. +void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) { +  SmallVector<const CFGBlock *, 11> worklist; +  llvm::BitVector visited(analyzed.size()); +   +  ReachableSet &DstReachability = reachable[Dst->getBlockID()]; +  DstReachability.resize(analyzed.size(), false); +   +  // Start searching from the destination node, since we commonly will perform +  // multiple queries relating to a destination node. +  worklist.push_back(Dst); +  bool firstRun = true; +   +  while (!worklist.empty()) {     +    const CFGBlock *block = worklist.back(); +    worklist.pop_back(); +     +    if (visited[block->getBlockID()]) +      continue; +    visited[block->getBlockID()] = true; +     +    // Update reachability information for this node -> Dst +    if (!firstRun) { +      // Don't insert Dst -> Dst unless it was a predecessor of itself +      DstReachability[block->getBlockID()] = true; +    } +    else +      firstRun = false; +     +    // Add the predecessors to the worklist. +    for (CFGBlock::const_pred_iterator i = block->pred_begin(),  +         e = block->pred_end(); i != e; ++i) { +      worklist.push_back(*i); +    } +  } +} diff --git a/clang/lib/Analysis/CFGStmtMap.cpp b/clang/lib/Analysis/CFGStmtMap.cpp new file mode 100644 index 0000000..16df676 --- /dev/null +++ b/clang/lib/Analysis/CFGStmtMap.cpp @@ -0,0 +1,91 @@ +//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file defines the CFGStmtMap class, which defines a mapping from +//  Stmt* to CFGBlock* +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "clang/AST/ParentMap.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" + +using namespace clang; + +typedef llvm::DenseMap<const Stmt*, CFGBlock*> SMap; +static SMap *AsMap(void *m) { return (SMap*) m; } + +CFGStmtMap::~CFGStmtMap() { delete AsMap(M); } + +CFGBlock *CFGStmtMap::getBlock(Stmt *S) {   +  SMap *SM = AsMap(M); +  Stmt *X = S; + +  // If 'S' isn't in the map, walk the ParentMap to see if one of its ancestors +  // is in the map. +  while (X) { +    SMap::iterator I = SM->find(X); +    if (I != SM->end()) { +      CFGBlock *B = I->second; +      // Memoize this lookup. +      if (X != S) +        (*SM)[X] = B; +      return B; +    } + +    X = PM->getParentIgnoreParens(X); +  } +   +  return 0; +} + +static void Accumulate(SMap &SM, CFGBlock *B) { +  // First walk the block-level expressions. +  for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) { +    const CFGElement &CE = *I; +    const CFGStmt *CS = CE.getAs<CFGStmt>(); +    if (!CS) +      continue; +     +    CFGBlock *&Entry = SM[CS->getStmt()]; +    // If 'Entry' is already initialized (e.g., a terminator was already), +    // skip. +    if (Entry) +      continue; +       +    Entry = B; +     +  } +   +  // Look at the label of the block. +  if (Stmt *Label = B->getLabel()) +    SM[Label] = B; + +  // Finally, look at the terminator.  If the terminator was already added +  // because it is a block-level expression in another block, overwrite +  // that mapping. +  if (Stmt *Term = B->getTerminator()) +    SM[Term] = B; +} + +CFGStmtMap *CFGStmtMap::Build(CFG *C, ParentMap *PM) { +  if (!C || !PM) +    return 0; + +  SMap *SM = new SMap(); + +  // Walk all blocks, accumulating the block-level expressions, labels, +  // and terminators.   +  for (CFG::iterator I = C->begin(), E = C->end(); I != E; ++I) +    Accumulate(*SM, *I); + +  return new CFGStmtMap(PM, SM); +} + diff --git a/clang/lib/Analysis/CMakeLists.txt b/clang/lib/Analysis/CMakeLists.txt new file mode 100644 index 0000000..bede002 --- /dev/null +++ b/clang/lib/Analysis/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_USED_LIBS clangBasic clangAST) + +add_clang_library(clangAnalysis +  AnalysisDeclContext.cpp +  CallGraph.cpp +  CFG.cpp +  CFGReachabilityAnalysis.cpp +  CFGStmtMap.cpp +  CocoaConventions.cpp +  Dominators.cpp +  FormatString.cpp +  Interval.cpp +  LiveVariables.cpp +  PostOrderCFGView.cpp +  PrintfFormatString.cpp +  ProgramPoint.cpp +  PseudoConstantAnalysis.cpp +  ReachableCode.cpp +  ScanfFormatString.cpp +  ThreadSafety.cpp +  UninitializedValues.cpp +  ) + +add_dependencies(clangAnalysis ClangAttrClasses ClangAttrList +                 ClangDiagnosticAnalysis ClangDeclNodes ClangStmtNodes) diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp new file mode 100644 index 0000000..96a16c3 --- /dev/null +++ b/clang/lib/Analysis/CallGraph.cpp @@ -0,0 +1,184 @@ +//== CallGraph.cpp - AST-based Call graph  ----------------------*- C++ -*--==// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file defines the AST-based CallGraph. +// +//===----------------------------------------------------------------------===// +#include "clang/Analysis/CallGraph.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/StmtVisitor.h" + +#include "llvm/Support/GraphWriter.h" + +using namespace clang; + +namespace { +/// A helper class, which walks the AST and locates all the call sites in the +/// given function body. +class CGBuilder : public StmtVisitor<CGBuilder> { +  CallGraph *G; +  const Decl *FD; +  CallGraphNode *CallerNode; + +public: +  CGBuilder(CallGraph *g, const Decl *D, CallGraphNode *N) +    : G(g), FD(D), CallerNode(N) {} + +  void VisitStmt(Stmt *S) { VisitChildren(S); } + +  void VisitCallExpr(CallExpr *CE) { +    // TODO: We need to handle ObjC method calls as well. +    if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) +      if (G->includeInGraph(CalleeDecl)) { +        CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl); +        CallerNode->addCallee(CalleeNode, G); +      } +  } + +  void VisitChildren(Stmt *S) { +    for (Stmt::child_range I = S->children(); I; ++I) +      if (*I) +        static_cast<CGBuilder*>(this)->Visit(*I); +  } +}; + +} // end anonymous namespace + +CallGraph::CallGraph() { +  Root = getOrInsertNode(0); +} + +CallGraph::~CallGraph() { +  if (!FunctionMap.empty()) { +    for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end(); +        I != E; ++I) +      delete I->second; +    FunctionMap.clear(); +  } +} + +bool CallGraph::includeInGraph(const Decl *D) { +  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { +    // We skip function template definitions, as their semantics is +    // only determined when they are instantiated. +    if (!FD->isThisDeclarationADefinition() || +        FD->isDependentContext()) +      return false; + +    IdentifierInfo *II = FD->getIdentifier(); +    if (II && II->getName().startswith("__inline")) +      return false; +  } + +  if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) { +    if (!ID->isThisDeclarationADefinition()) +      return false; +  } + +  return true; +} + +void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) { +  assert(D); + +  // Do nothing if the node already exists. +  if (FunctionMap.find(D) != FunctionMap.end()) +    return; + +  // Allocate a new node, mark it as root, and process it's calls. +  CallGraphNode *Node = getOrInsertNode(D); +  if (IsGlobal) +    Root->addCallee(Node, this); + +  // Process all the calls by this function as well. +  CGBuilder builder(this, D, Node); +  if (Stmt *Body = D->getBody()) +    builder.Visit(Body); +} + +CallGraphNode *CallGraph::getNode(const Decl *F) const { +  FunctionMapTy::const_iterator I = FunctionMap.find(F); +  if (I == FunctionMap.end()) return 0; +  return I->second; +} + +CallGraphNode *CallGraph::getOrInsertNode(Decl *F) { +  CallGraphNode *&Node = FunctionMap[F]; +  if (Node) +    return Node; + +  Node = new CallGraphNode(F); +  // If not root, add to the parentless list. +  if (F != 0) +    ParentlessNodes.insert(Node); +  return Node; +} + +void CallGraph::print(raw_ostream &OS) const { +  OS << " --- Call graph Dump --- \n"; +  for (const_iterator I = begin(), E = end(); I != E; ++I) { +    OS << "  Function: "; +    if (I->second == Root) +      OS << "< root >"; +    else +      I->second->print(OS); +    OS << " calls: "; +    for (CallGraphNode::iterator CI = I->second->begin(), +        CE = I->second->end(); CI != CE; ++CI) { +      assert(*CI != Root && "No one can call the root node."); +      (*CI)->print(OS); +      OS << " "; +    } +    OS << '\n'; +  } +  OS.flush(); +} + +void CallGraph::dump() const { +  print(llvm::errs()); +} + +void CallGraph::viewGraph() const { +  llvm::ViewGraph(this, "CallGraph"); +} + +StringRef CallGraphNode::getName() const { +  if (const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(FD)) +    if (const IdentifierInfo *II = D->getIdentifier()) +      return II->getName(); +    return "< >"; +} + +void CallGraphNode::print(raw_ostream &os) const { +  os << getName(); +} + +void CallGraphNode::dump() const { +  print(llvm::errs()); +} + +namespace llvm { + +template <> +struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits { + +  DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + +  static std::string getNodeLabel(const CallGraphNode *Node, +                                  const CallGraph *CG) { +    if (CG->getRoot() == Node) { +      return "< root >"; +    } +    return Node->getName(); +  } + +}; +} diff --git a/clang/lib/Analysis/CocoaConventions.cpp b/clang/lib/Analysis/CocoaConventions.cpp new file mode 100644 index 0000000..7e9e38f --- /dev/null +++ b/clang/lib/Analysis/CocoaConventions.cpp @@ -0,0 +1,138 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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 cocoa naming convention analysis.  +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; +using namespace ento; + +bool cocoa::isRefType(QualType RetTy, StringRef Prefix, +                      StringRef Name) { +  // Recursively walk the typedef stack, allowing typedefs of reference types. +  while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { +    StringRef TDName = TD->getDecl()->getIdentifier()->getName(); +    if (TDName.startswith(Prefix) && TDName.endswith("Ref")) +      return true; +    // XPC unfortunately uses CF-style function names, but aren't CF types. +    if (TDName.startswith("xpc_")) +      return false; +    RetTy = TD->getDecl()->getUnderlyingType(); +  } +   +  if (Name.empty()) +    return false; +   +  // Is the type void*? +  const PointerType* PT = RetTy->getAs<PointerType>(); +  if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) +    return false; +   +  // Does the name start with the prefix? +  return Name.startswith(Prefix); +} + +bool coreFoundation::isCFObjectRef(QualType T) { +  return cocoa::isRefType(T, "CF") || // Core Foundation. +         cocoa::isRefType(T, "CG") || // Core Graphics. +         cocoa::isRefType(T, "DADisk") || // Disk Arbitration API. +         cocoa::isRefType(T, "DADissenter") || +         cocoa::isRefType(T, "DASessionRef"); +} + + +bool cocoa::isCocoaObjectRef(QualType Ty) { +  if (!Ty->isObjCObjectPointerType()) +    return false; +   +  const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>(); +   +  // Can be true for objects with the 'NSObject' attribute. +  if (!PT) +    return true; +   +  // We assume that id<..>, id, Class, and Class<..> all represent tracked +  // objects. +  if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || +      PT->isObjCClassType() || PT->isObjCQualifiedClassType()) +    return true; +   +  // Does the interface subclass NSObject? +  // FIXME: We can memoize here if this gets too expensive. +  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); +   +  // Assume that anything declared with a forward declaration and no +  // @interface subclasses NSObject. +  if (!ID->hasDefinition()) +    return true; +   +  for ( ; ID ; ID = ID->getSuperClass()) +    if (ID->getIdentifier()->getName() == "NSObject") +      return true; +   +  return false; +} + +bool coreFoundation::followsCreateRule(const FunctionDecl *fn) { +  // For now, *just* base this on the function name, not on anything else. + +  const IdentifierInfo *ident = fn->getIdentifier(); +  if (!ident) return false; +  StringRef functionName = ident->getName(); +   +  StringRef::iterator it = functionName.begin(); +  StringRef::iterator start = it; +  StringRef::iterator endI = functionName.end(); +     +  while (true) { +    // Scan for the start of 'create' or 'copy'. +    for ( ; it != endI ; ++it) { +      // Search for the first character.  It can either be 'C' or 'c'. +      char ch = *it; +      if (ch == 'C' || ch == 'c') { +        // Make sure this isn't something like 'recreate' or 'Scopy'. +        if (ch == 'c' && it != start && isalpha(*(it - 1))) +          continue; + +        ++it; +        break; +      } +    } + +    // Did we hit the end of the string?  If so, we didn't find a match. +    if (it == endI) +      return false; +     +    // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase +    // character. +    StringRef suffix = functionName.substr(it - start); +    if (suffix.startswith("reate")) { +      it += 5; +    } +    else if (suffix.startswith("opy")) { +      it += 3; +    } else { +      // Keep scanning. +      continue; +    } +     +    if (it == endI || !islower(*it)) +      return true; +   +    // If we matched a lowercase character, it isn't the end of the +    // word.  Keep scanning. +  } +} diff --git a/clang/lib/Analysis/Dominators.cpp b/clang/lib/Analysis/Dominators.cpp new file mode 100644 index 0000000..0e02c6d --- /dev/null +++ b/clang/lib/Analysis/Dominators.cpp @@ -0,0 +1,14 @@ +//=- Dominators.cpp - Implementation of dominators tree for Clang CFG C++ -*-=// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/Dominators.h" + +using namespace clang; + +void DominatorTree::anchor() { } diff --git a/clang/lib/Analysis/FormatString.cpp b/clang/lib/Analysis/FormatString.cpp new file mode 100644 index 0000000..ba45865 --- /dev/null +++ b/clang/lib/Analysis/FormatString.cpp @@ -0,0 +1,678 @@ +// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*- +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Shared details for processing format strings of printf and scanf +// (and friends). +// +//===----------------------------------------------------------------------===// + +#include "FormatStringParsing.h" +#include "clang/Basic/LangOptions.h" + +using clang::analyze_format_string::ArgTypeResult; +using clang::analyze_format_string::FormatStringHandler; +using clang::analyze_format_string::FormatSpecifier; +using clang::analyze_format_string::LengthModifier; +using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::PositionContext; +using clang::analyze_format_string::ConversionSpecifier; +using namespace clang; + +// Key function to FormatStringHandler. +FormatStringHandler::~FormatStringHandler() {} + +//===----------------------------------------------------------------------===// +// Functions for parsing format strings components in both printf and +// scanf format strings. +//===----------------------------------------------------------------------===// + +OptionalAmount +clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) { +  const char *I = Beg; +  UpdateOnReturn <const char*> UpdateBeg(Beg, I); + +  unsigned accumulator = 0; +  bool hasDigits = false; + +  for ( ; I != E; ++I) { +    char c = *I; +    if (c >= '0' && c <= '9') { +      hasDigits = true; +      accumulator = (accumulator * 10) + (c - '0'); +      continue; +    } + +    if (hasDigits) +      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg, +          false); + +    break; +  } + +  return OptionalAmount(); +} + +OptionalAmount +clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg, +                                                     const char *E, +                                                     unsigned &argIndex) { +  if (*Beg == '*') { +    ++Beg; +    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false); +  } + +  return ParseAmount(Beg, E); +} + +OptionalAmount +clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H, +                                                  const char *Start, +                                                  const char *&Beg, +                                                  const char *E, +                                                  PositionContext p) { +  if (*Beg == '*') { +    const char *I = Beg + 1; +    const OptionalAmount &Amt = ParseAmount(I, E); + +    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { +      H.HandleInvalidPosition(Beg, I - Beg, p); +      return OptionalAmount(false); +    } + +    if (I == E) { +      // No more characters left? +      H.HandleIncompleteSpecifier(Start, E - Start); +      return OptionalAmount(false); +    } + +    assert(Amt.getHowSpecified() == OptionalAmount::Constant); + +    if (*I == '$') { +      // Handle positional arguments + +      // Special case: '*0$', since this is an easy mistake. +      if (Amt.getConstantAmount() == 0) { +        H.HandleZeroPosition(Beg, I - Beg + 1); +        return OptionalAmount(false); +      } + +      const char *Tmp = Beg; +      Beg = ++I; + +      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1, +                            Tmp, 0, true); +    } + +    H.HandleInvalidPosition(Beg, I - Beg, p); +    return OptionalAmount(false); +  } + +  return ParseAmount(Beg, E); +} + + +bool +clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H, +                                              FormatSpecifier &CS, +                                              const char *Start, +                                              const char *&Beg, const char *E, +                                              unsigned *argIndex) { +  // FIXME: Support negative field widths. +  if (argIndex) { +    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); +  } +  else { +    const OptionalAmount Amt = +      ParsePositionAmount(H, Start, Beg, E, +                          analyze_format_string::FieldWidthPos); + +    if (Amt.isInvalid()) +      return true; +    CS.setFieldWidth(Amt); +  } +  return false; +} + +bool +clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H, +                                               FormatSpecifier &FS, +                                               const char *Start, +                                               const char *&Beg, +                                               const char *E) { +  const char *I = Beg; + +  const OptionalAmount &Amt = ParseAmount(I, E); + +  if (I == E) { +    // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } + +  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { +    // Warn that positional arguments are non-standard. +    H.HandlePosition(Start, I - Start); + +    // Special case: '%0$', since this is an easy mistake. +    if (Amt.getConstantAmount() == 0) { +      H.HandleZeroPosition(Start, I - Start); +      return true; +    } + +    FS.setArgIndex(Amt.getConstantAmount() - 1); +    FS.setUsesPositionalArg(); +    // Update the caller's pointer if we decided to consume +    // these characters. +    Beg = I; +    return false; +  } + +  return false; +} + +bool +clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, +                                                  const char *&I, +                                                  const char *E, +                                                  const LangOptions &LO, +                                                  bool IsScanf) { +  LengthModifier::Kind lmKind = LengthModifier::None; +  const char *lmPosition = I; +  switch (*I) { +    default: +      return false; +    case 'h': +      ++I; +      lmKind = (I != E && *I == 'h') ? (++I, LengthModifier::AsChar) +                                     : LengthModifier::AsShort; +      break; +    case 'l': +      ++I; +      lmKind = (I != E && *I == 'l') ? (++I, LengthModifier::AsLongLong) +                                     : LengthModifier::AsLong; +      break; +    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break; +    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break; +    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break; +    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break; +    case 'q': lmKind = LengthModifier::AsQuad;       ++I; break; +    case 'a': +      if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) { +        // For scanf in C90, look at the next character to see if this should +        // be parsed as the GNU extension 'a' length modifier. If not, this +        // will be parsed as a conversion specifier. +        ++I; +        if (I != E && (*I == 's' || *I == 'S' || *I == '[')) { +          lmKind = LengthModifier::AsAllocate; +          break; +        } +        --I; +      } +      return false; +    case 'm': +      if (IsScanf) { +        lmKind = LengthModifier::AsMAllocate; +        ++I; +        break; +      } +      return false; +  } +  LengthModifier lm(lmPosition, lmKind); +  FS.setLengthModifier(lm); +  return true; +} + +//===----------------------------------------------------------------------===// +// Methods on ArgTypeResult. +//===----------------------------------------------------------------------===// + +bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { +  switch (K) { +    case InvalidTy: +      llvm_unreachable("ArgTypeResult must be valid"); + +    case UnknownTy: +      return true; +       +    case AnyCharTy: { +      if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) +        switch (BT->getKind()) { +          default: +            break; +          case BuiltinType::Char_S: +          case BuiltinType::SChar: +          case BuiltinType::UChar: +          case BuiltinType::Char_U: +            return true;             +        } +      return false; +    } +       +    case SpecificTy: { +      argTy = C.getCanonicalType(argTy).getUnqualifiedType(); +      if (T == argTy) +        return true; +      // Check for "compatible types". +      if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) +        switch (BT->getKind()) { +          default: +            break; +          case BuiltinType::Char_S: +          case BuiltinType::SChar: +            return T == C.UnsignedCharTy; +          case BuiltinType::Char_U: +          case BuiltinType::UChar:                     +            return T == C.SignedCharTy; +          case BuiltinType::Short: +            return T == C.UnsignedShortTy; +          case BuiltinType::UShort: +            return T == C.ShortTy; +          case BuiltinType::Int: +            return T == C.UnsignedIntTy; +          case BuiltinType::UInt: +            return T == C.IntTy; +          case BuiltinType::Long: +            return T == C.UnsignedLongTy; +          case BuiltinType::ULong: +            return T == C.LongTy; +          case BuiltinType::LongLong: +            return T == C.UnsignedLongLongTy; +          case BuiltinType::ULongLong: +            return T == C.LongLongTy; +        } +      return false; +    } + +    case CStrTy: { +      const PointerType *PT = argTy->getAs<PointerType>(); +      if (!PT) +        return false; +      QualType pointeeTy = PT->getPointeeType(); +      if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) +        switch (BT->getKind()) { +          case BuiltinType::Void: +          case BuiltinType::Char_U: +          case BuiltinType::UChar: +          case BuiltinType::Char_S: +          case BuiltinType::SChar: +            return true; +          default: +            break; +        } + +      return false; +    } + +    case WCStrTy: { +      const PointerType *PT = argTy->getAs<PointerType>(); +      if (!PT) +        return false; +      QualType pointeeTy = +        C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); +      return pointeeTy == C.getWCharType(); +    } +     +    case WIntTy: { +      // Instead of doing a lookup for the definition of 'wint_t' (which +      // is defined by the system headers) instead see if wchar_t and +      // the argument type promote to the same type. +      QualType PromoWChar = +        C.getWCharType()->isPromotableIntegerType()  +          ? C.getPromotedIntegerType(C.getWCharType()) : C.getWCharType(); +      QualType PromoArg =  +        argTy->isPromotableIntegerType() +          ? C.getPromotedIntegerType(argTy) : argTy; +       +      PromoWChar = C.getCanonicalType(PromoWChar).getUnqualifiedType(); +      PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); +       +      return PromoWChar == PromoArg; +    } + +    case CPointerTy: +      return argTy->isPointerType() || argTy->isObjCObjectPointerType() || +             argTy->isBlockPointerType() || argTy->isNullPtrType(); + +    case ObjCPointerTy: { +      if (argTy->getAs<ObjCObjectPointerType>() || +          argTy->getAs<BlockPointerType>()) +        return true; +       +      // Handle implicit toll-free bridging. +      if (const PointerType *PT = argTy->getAs<PointerType>()) { +        // Things such as CFTypeRef are really just opaque pointers +        // to C structs representing CF types that can often be bridged +        // to Objective-C objects.  Since the compiler doesn't know which +        // structs can be toll-free bridged, we just accept them all. +        QualType pointee = PT->getPointeeType(); +        if (pointee->getAsStructureType() || pointee->isVoidType()) +          return true; +      } +      return false;       +    } +  } + +  llvm_unreachable("Invalid ArgTypeResult Kind!"); +} + +QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { +  switch (K) { +    case InvalidTy: +      llvm_unreachable("No representative type for Invalid ArgTypeResult"); +    case UnknownTy: +      return QualType(); +    case AnyCharTy: +      return C.CharTy; +    case SpecificTy: +      return T; +    case CStrTy: +      return C.getPointerType(C.CharTy); +    case WCStrTy: +      return C.getPointerType(C.getWCharType()); +    case ObjCPointerTy: +      return C.ObjCBuiltinIdTy; +    case CPointerTy: +      return C.VoidPtrTy; +    case WIntTy: { +      QualType WC = C.getWCharType(); +      return WC->isPromotableIntegerType() ? C.getPromotedIntegerType(WC) : WC; +    } +  } + +  llvm_unreachable("Invalid ArgTypeResult Kind!"); +} + +std::string ArgTypeResult::getRepresentativeTypeName(ASTContext &C) const { +  std::string S = getRepresentativeType(C).getAsString(); +  if (Name && S != Name) +    return std::string("'") + Name + "' (aka '" + S + "')"; +  return std::string("'") + S + "'"; +} + + +//===----------------------------------------------------------------------===// +// Methods on OptionalAmount. +//===----------------------------------------------------------------------===// + +ArgTypeResult +analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const { +  return Ctx.IntTy; +} + +//===----------------------------------------------------------------------===// +// Methods on LengthModifier. +//===----------------------------------------------------------------------===// + +const char * +analyze_format_string::LengthModifier::toString() const { +  switch (kind) { +  case AsChar: +    return "hh"; +  case AsShort: +    return "h"; +  case AsLong: // or AsWideChar +    return "l"; +  case AsLongLong: +    return "ll"; +  case AsQuad: +    return "q"; +  case AsIntMax: +    return "j"; +  case AsSizeT: +    return "z"; +  case AsPtrDiff: +    return "t"; +  case AsLongDouble: +    return "L"; +  case AsAllocate: +    return "a"; +  case AsMAllocate: +    return "m"; +  case None: +    return ""; +  } +  return NULL; +} + +//===----------------------------------------------------------------------===// +// Methods on ConversionSpecifier. +//===----------------------------------------------------------------------===// + +const char *ConversionSpecifier::toString() const { +  switch (kind) { +  case dArg: return "d"; +  case iArg: return "i"; +  case oArg: return "o"; +  case uArg: return "u"; +  case xArg: return "x"; +  case XArg: return "X"; +  case fArg: return "f"; +  case FArg: return "F"; +  case eArg: return "e"; +  case EArg: return "E"; +  case gArg: return "g"; +  case GArg: return "G"; +  case aArg: return "a"; +  case AArg: return "A"; +  case cArg: return "c"; +  case sArg: return "s"; +  case pArg: return "p"; +  case nArg: return "n"; +  case PercentArg:  return "%"; +  case ScanListArg: return "["; +  case InvalidSpecifier: return NULL; + +  // MacOS X unicode extensions. +  case CArg: return "C"; +  case SArg: return "S"; + +  // Objective-C specific specifiers. +  case ObjCObjArg: return "@"; + +  // GlibC specific specifiers. +  case PrintErrno: return "m"; +  } +  return NULL; +} + +//===----------------------------------------------------------------------===// +// Methods on OptionalAmount. +//===----------------------------------------------------------------------===// + +void OptionalAmount::toString(raw_ostream &os) const { +  switch (hs) { +  case Invalid: +  case NotSpecified: +    return; +  case Arg: +    if (UsesDotPrefix) +        os << "."; +    if (usesPositionalArg()) +      os << "*" << getPositionalArgIndex() << "$"; +    else +      os << "*"; +    break; +  case Constant: +    if (UsesDotPrefix) +        os << "."; +    os << amt; +    break; +  } +} + +bool FormatSpecifier::hasValidLengthModifier() const { +  switch (LM.getKind()) { +    case LengthModifier::None: +      return true; +       +    // Handle most integer flags +    case LengthModifier::AsChar: +    case LengthModifier::AsShort: +    case LengthModifier::AsLongLong: +    case LengthModifier::AsQuad: +    case LengthModifier::AsIntMax: +    case LengthModifier::AsSizeT: +    case LengthModifier::AsPtrDiff: +      switch (CS.getKind()) { +        case ConversionSpecifier::dArg: +        case ConversionSpecifier::iArg: +        case ConversionSpecifier::oArg: +        case ConversionSpecifier::uArg: +        case ConversionSpecifier::xArg: +        case ConversionSpecifier::XArg: +        case ConversionSpecifier::nArg: +          return true; +        default: +          return false; +      } +       +    // Handle 'l' flag +    case LengthModifier::AsLong: +      switch (CS.getKind()) { +        case ConversionSpecifier::dArg: +        case ConversionSpecifier::iArg: +        case ConversionSpecifier::oArg: +        case ConversionSpecifier::uArg: +        case ConversionSpecifier::xArg: +        case ConversionSpecifier::XArg: +        case ConversionSpecifier::aArg: +        case ConversionSpecifier::AArg: +        case ConversionSpecifier::fArg: +        case ConversionSpecifier::FArg: +        case ConversionSpecifier::eArg: +        case ConversionSpecifier::EArg: +        case ConversionSpecifier::gArg: +        case ConversionSpecifier::GArg: +        case ConversionSpecifier::nArg: +        case ConversionSpecifier::cArg: +        case ConversionSpecifier::sArg: +        case ConversionSpecifier::ScanListArg: +          return true; +        default: +          return false; +      } +       +    case LengthModifier::AsLongDouble: +      switch (CS.getKind()) { +        case ConversionSpecifier::aArg: +        case ConversionSpecifier::AArg: +        case ConversionSpecifier::fArg: +        case ConversionSpecifier::FArg: +        case ConversionSpecifier::eArg: +        case ConversionSpecifier::EArg: +        case ConversionSpecifier::gArg: +        case ConversionSpecifier::GArg: +          return true; +        // GNU extension. +        case ConversionSpecifier::dArg: +        case ConversionSpecifier::iArg: +        case ConversionSpecifier::oArg: +        case ConversionSpecifier::uArg: +        case ConversionSpecifier::xArg: +        case ConversionSpecifier::XArg: +          return true; +        default: +          return false; +      } + +    case LengthModifier::AsAllocate: +      switch (CS.getKind()) { +        case ConversionSpecifier::sArg: +        case ConversionSpecifier::SArg: +        case ConversionSpecifier::ScanListArg: +          return true; +        default: +          return false; +      } + +    case LengthModifier::AsMAllocate: +      switch (CS.getKind()) { +        case ConversionSpecifier::cArg: +        case ConversionSpecifier::CArg: +        case ConversionSpecifier::sArg: +        case ConversionSpecifier::SArg: +        case ConversionSpecifier::ScanListArg: +          return true; +        default: +          return false; +      } +  } +  llvm_unreachable("Invalid LengthModifier Kind!"); +} + +bool FormatSpecifier::hasStandardLengthModifier() const { +  switch (LM.getKind()) { +    case LengthModifier::None: +    case LengthModifier::AsChar: +    case LengthModifier::AsShort: +    case LengthModifier::AsLong: +    case LengthModifier::AsLongLong: +    case LengthModifier::AsIntMax: +    case LengthModifier::AsSizeT: +    case LengthModifier::AsPtrDiff: +    case LengthModifier::AsLongDouble: +      return true; +    case LengthModifier::AsAllocate: +    case LengthModifier::AsMAllocate: +    case LengthModifier::AsQuad: +      return false; +  } +  llvm_unreachable("Invalid LengthModifier Kind!"); +} + +bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) const { +  switch (CS.getKind()) { +    case ConversionSpecifier::cArg: +    case ConversionSpecifier::dArg: +    case ConversionSpecifier::iArg: +    case ConversionSpecifier::oArg: +    case ConversionSpecifier::uArg: +    case ConversionSpecifier::xArg: +    case ConversionSpecifier::XArg: +    case ConversionSpecifier::fArg: +    case ConversionSpecifier::FArg: +    case ConversionSpecifier::eArg: +    case ConversionSpecifier::EArg: +    case ConversionSpecifier::gArg: +    case ConversionSpecifier::GArg: +    case ConversionSpecifier::aArg: +    case ConversionSpecifier::AArg: +    case ConversionSpecifier::sArg: +    case ConversionSpecifier::pArg: +    case ConversionSpecifier::nArg: +    case ConversionSpecifier::ObjCObjArg: +    case ConversionSpecifier::ScanListArg: +    case ConversionSpecifier::PercentArg: +      return true; +    case ConversionSpecifier::CArg: +    case ConversionSpecifier::SArg: +      return LangOpt.ObjC1 || LangOpt.ObjC2; +    case ConversionSpecifier::InvalidSpecifier: +    case ConversionSpecifier::PrintErrno: +      return false; +  } +  llvm_unreachable("Invalid ConversionSpecifier Kind!"); +} + +bool FormatSpecifier::hasStandardLengthConversionCombination() const { +  if (LM.getKind() == LengthModifier::AsLongDouble) { +    switch(CS.getKind()) { +        case ConversionSpecifier::dArg: +        case ConversionSpecifier::iArg: +        case ConversionSpecifier::oArg: +        case ConversionSpecifier::uArg: +        case ConversionSpecifier::xArg: +        case ConversionSpecifier::XArg: +          return false; +        default: +          return true; +    } +  } +  return true; +} diff --git a/clang/lib/Analysis/FormatStringParsing.h b/clang/lib/Analysis/FormatStringParsing.h new file mode 100644 index 0000000..f483ec6 --- /dev/null +++ b/clang/lib/Analysis/FormatStringParsing.h @@ -0,0 +1,74 @@ +#ifndef LLVM_CLANG_FORMAT_PARSING_H +#define LLVM_CLANG_FORMAT_PARSING_H + +#include "clang/Analysis/Analyses/FormatString.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +class LangOptions; + +template <typename T> +class UpdateOnReturn { +  T &ValueToUpdate; +  const T &ValueToCopy; +public: +  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy) +    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {} + +  ~UpdateOnReturn() { +    ValueToUpdate = ValueToCopy; +  } +}; + +namespace analyze_format_string { +   +OptionalAmount ParseAmount(const char *&Beg, const char *E); +OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, +                                      unsigned &argIndex); + +OptionalAmount ParsePositionAmount(FormatStringHandler &H, +                                   const char *Start, const char *&Beg, +                                   const char *E, PositionContext p); +   +bool ParseFieldWidth(FormatStringHandler &H, +                     FormatSpecifier &CS, +                     const char *Start, const char *&Beg, const char *E, +                     unsigned *argIndex); +     +bool ParseArgPosition(FormatStringHandler &H, +                      FormatSpecifier &CS, const char *Start, +                      const char *&Beg, const char *E); + +/// Returns true if a LengthModifier was parsed and installed in the +/// FormatSpecifier& argument, and false otherwise. +bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E, +                         const LangOptions &LO, bool IsScanf = false); +   +template <typename T> class SpecifierResult { +  T FS; +  const char *Start; +  bool Stop; +public: +  SpecifierResult(bool stop = false) +  : Start(0), Stop(stop) {} +  SpecifierResult(const char *start, +                  const T &fs) +  : FS(fs), Start(start), Stop(false) {} +   +  const char *getStart() const { return Start; } +  bool shouldStop() const { return Stop; } +  bool hasValue() const { return Start != 0; } +  const T &getValue() const { +    assert(hasValue()); +    return FS; +  } +  const T &getValue() { return FS; } +}; +   +} // end analyze_format_string namespace +} // end clang namespace + +#endif diff --git a/clang/lib/Analysis/Interval.cpp b/clang/lib/Analysis/Interval.cpp new file mode 100644 index 0000000..bfa1ccf --- /dev/null +++ b/clang/lib/Analysis/Interval.cpp @@ -0,0 +1,230 @@ +#include "clang/Analysis/Analyses/Interval.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/StmtVisitor.h" + +#include "clang/Analysis/Analyses/IntervalSolver/Log.hpp" +#include "clang/Analysis/Analyses/IntervalSolver/Complete.hpp" +#include "clang/Analysis/Analyses/IntervalSolver/VariableAssignment.hpp" +#include "clang/Analysis/Analyses/IntervalSolver/EquationSystem.hpp" +   +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Process.h" +   +#include <deque> +#include <algorithm> +#include <vector> +#include <map> + +using namespace clang; + +typedef EquationSystem<Complete<int> > EqnSys; +typedef Expression<Complete<int> > EqnExpr; + +#include <sstream> +template<typename T> +std::string toString(const T& obj) { +  std::stringstream stream; +  stream << obj; +  return stream.str(); +} + +IntervalAnalysis :: IntervalAnalysis(AnalysisDeclContext &context) +  : context(&context) { +} + +IntervalAnalysis :: ~IntervalAnalysis() { +} + +// Two pieces of state: +//  -> condition protecting a node +//  -> node's expression itself +// We can then combine these in a straightforward way to +// get out equation system, whereupon we can solve for what +// we want to know. Then we can have program invariants! +// +// Hooray! + +EqnExpr* fromStmt(const Stmt*, EqnSys&); + +EqnExpr* fromInteger(const IntegerLiteral* expr, EqnSys& system) { +  return &system.constant(*expr->getValue().getRawData()); +} + +EqnExpr* fromDeclExpr(const DeclRefExpr* expr, EqnSys& system) { +  return &system.variable(expr->getNameInfo().getAsString()); +} + +EqnExpr* fromUnary(const UnaryOperator* op, EqnSys& system) { +  switch (op->getOpcode()) { +  case UO_PreInc: +    break; +  case UO_PostInc: +    break; +  } +  return NULL; +} + + +Addition<Complete<int> >* add = new Addition<Complete<int> >(); +Subtraction<Complete<int> >* sub = new Subtraction<Complete<int> >(); +Multiplication<Complete<int> >* mul = new Multiplication<Complete<int> >(); + +EqnExpr* fromBinary(const BinaryOperator* op, EqnSys& system) { +  EqnExpr* left = fromStmt(op->getLHS()->IgnoreParenCasts(), system); +  EqnExpr* right = fromStmt(op->getRHS()->IgnoreParenCasts(), system); +   +  std::vector<EqnExpr*> args; +  args.push_back(left); +  args.push_back(right); +   +  switch (op->getOpcode()) { +  case BO_Add: +    return &system.expression(add, args); +  case BO_Sub: +    return &system.expression(sub, args); +  case BO_Mul: +    return &system.expression(mul, args); +  case BO_LT: +  case BO_LE: +  case BO_GT: +  case BO_GE: +    break; +  }  +  return NULL; +} + +EqnExpr* fromDeclStmt(const DeclStmt* stmt, EqnSys& system) { +  for (DeclStmt::const_decl_iterator it = stmt->decl_begin(), +                                     ei = stmt->decl_end(); +       it != ei; +       ++it) { +    if ((*it)->getKind() == Decl::Var) { +      const VarDecl* decl = static_cast<const VarDecl*>(*it); +      Variable<Complete<int> > var = system.variable(decl->getNameAsString()); +      std::vector<EqnExpr*> args; +      args.push_back(&system.constant(-infinity<Complete<int> >())); +      args.push_back(fromStmt(decl->getInit(), system)); +      system[var] = &system.maxExpression(args); +    } +  } +  return NULL; +} + +EqnExpr* fromAssignment(const BinaryOperator* op, EqnSys& system) { +  EqnExpr* left = fromStmt(op->getLHS()->IgnoreParenCasts(), system); +  EqnExpr* right = fromStmt(op->getRHS()->IgnoreParenCasts(), system); +  Variable<Complete<int> >* var = static_cast<Variable<Complete<int> >*>(left); + +  std::vector<EqnExpr*> args; +  args.push_back(&system.constant(-infinity<Complete<int> >())); +  args.push_back(right); +  if (system[*var] != NULL) +    args.push_back(system[*var]); +  system[*var] = &system.maxExpression(args); + +  return NULL; +} + +EqnExpr* fromStmt(const Stmt* stmt, EqnSys& system) { +  if (!stmt) +    return NULL; +  switch (stmt->getStmtClass()) { +  case Stmt::IntegerLiteralClass: +    return fromInteger(static_cast<const IntegerLiteral*>(stmt), system); +  case Stmt::DeclRefExprClass: +    return fromDeclExpr(static_cast<const DeclRefExpr*>(stmt), system); +  case Stmt::UnaryOperatorClass: +    return fromUnary(static_cast<const UnaryOperator*>(stmt), system); +  case Stmt::DeclStmtClass: +    return fromDeclStmt(static_cast<const DeclStmt*>(stmt), system); +  case Stmt::BinaryOperatorClass: +    { +      const BinaryOperator* binop = static_cast<const BinaryOperator*>(stmt); +      if (binop->isAssignmentOp()) +        return fromAssignment(binop, system); +      else +        return fromBinary(binop, system); +    } +  } +  return NULL; +} + +void runOnBlock(std::string id, const CFGBlock* block, EqnSys& system) { +  for (CFGBlock::const_iterator it = block->begin(), +                                ei = block->end(); +       it != ei; +       ++it) { +    const CFGStmt* cfg_stmt = it->getAs<CFGStmt>(); +    const Stmt* stmt = static_cast<const Stmt*>(cfg_stmt->getStmt()); +    EqnExpr* expr = fromStmt(stmt, system); +  } +  fromStmt(block->getTerminatorCondition(), system); + +  /*if (terminator.getStmt() != NULL) { +    if (terminator.getStmt()->getStmtClass() == Stmt::IfStmtClass) { +      const IfStmt* if_stmt = static_cast<const IfStmt*>(terminator.getStmt()); +      llvm::errs() << "If: \n"; +      if_stmt->dump(); +    } else { +      llvm::errs() << "\n"; +      terminator.getStmt()->dump(); +    } +    }*/ +  return; // TODO: return a generated expression +} + +void IntervalAnalysis::runOnAllBlocks() { +  llvm::errs() << "Enter run on all blocks\n"; + +  const CFG *cfg = this->context->getCFG(); + +  EqnSys system; + +  std::set<const CFGBlock*> seen; +  std::deque<const CFGBlock*> todo; +  todo.push_back(&cfg->getEntry()); + +  while (!todo.empty()) { +    const CFGBlock* block = todo.front(); +    if (seen.find(todo.front()) != seen.end()) { +      todo.pop_front(); +      continue; +    } +    llvm::errs() << (void*)block << "\n"; +    seen.insert(block); +    todo.pop_front(); +    runOnBlock(toString(block), block, system); +    llvm::errs() << "-> "; +    for (CFGBlock::const_succ_iterator it = block->succ_begin(), +                                       ei = block->succ_end(); +         it != ei; +         it++ ) { +      llvm::errs() << (void*) *it << ", "; +      todo.push_back(*it); +    } +    llvm::errs() << "\n\n"; +  } + +  llvm::errs() << "Exit run on all blocks\n"; + +  llvm::errs() << toString(system) << "\n"; + +  system.indexMaxExpressions(); +  DynamicMaxStrategy<Complete<int> > strategy(system); +  DynamicVariableAssignment<Complete<int> > rho(system, strategy); +  strategy.setRho(rho); + +  for (unsigned int i = 0, size = system.variableCount(); i < size; ++i) { +    Variable<Complete<int> >& var = system.variable(i); +    llvm::errs() << toString(var.name()) << " = " << toString(rho[var]) << "\n"; +  } + +  //  cfg->dump(context->getASTContext().getLangOpts(), +  //            llvm::sys::Process::StandardErrHasColors()); +} + + +const void *IntervalAnalysis::getTag() { static int x; return &x; } diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp new file mode 100644 index 0000000..ff6607d --- /dev/null +++ b/clang/lib/Analysis/LiveVariables.cpp @@ -0,0 +1,607 @@ +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Analyses/PostOrderCFGView.h" + +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/StmtVisitor.h" + +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DenseMap.h" + +#include <deque> +#include <algorithm> +#include <vector> + +using namespace clang; + +namespace { + +class DataflowWorklist { +  SmallVector<const CFGBlock *, 20> worklist; +  llvm::BitVector enqueuedBlocks; +  PostOrderCFGView *POV; +public: +  DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx) +    : enqueuedBlocks(cfg.getNumBlockIDs()), +      POV(Ctx.getAnalysis<PostOrderCFGView>()) {} +   +  void enqueueBlock(const CFGBlock *block); +  void enqueueSuccessors(const CFGBlock *block); +  void enqueuePredecessors(const CFGBlock *block); + +  const CFGBlock *dequeue(); + +  void sortWorklist(); +}; + +} + +void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) { +  if (block && !enqueuedBlocks[block->getBlockID()]) { +    enqueuedBlocks[block->getBlockID()] = true; +    worklist.push_back(block); +  } +} +   +void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { +  const unsigned OldWorklistSize = worklist.size(); +  for (CFGBlock::const_succ_iterator I = block->succ_begin(), +       E = block->succ_end(); I != E; ++I) { +    enqueueBlock(*I); +  } + +  if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) +    return; + +  sortWorklist(); +} + +void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) { +  const unsigned OldWorklistSize = worklist.size(); +  for (CFGBlock::const_pred_iterator I = block->pred_begin(), +       E = block->pred_end(); I != E; ++I) { +    enqueueBlock(*I); +  } +   +  if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) +    return; + +  sortWorklist(); +} + +void DataflowWorklist::sortWorklist() { +  std::sort(worklist.begin(), worklist.end(), POV->getComparator()); +} + +const CFGBlock *DataflowWorklist::dequeue() { +  if (worklist.empty()) +    return 0; +  const CFGBlock *b = worklist.back(); +  worklist.pop_back(); +  enqueuedBlocks[b->getBlockID()] = false; +  return b; +} + +namespace { +class LiveVariablesImpl { +public:   +  AnalysisDeclContext &analysisContext; +  std::vector<LiveVariables::LivenessValues> cfgBlockValues; +  llvm::ImmutableSet<const Stmt *>::Factory SSetFact; +  llvm::ImmutableSet<const VarDecl *>::Factory DSetFact; +  llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness; +  llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness; +  llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness; +  llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment; +  const bool killAtAssign; +   +  LiveVariables::LivenessValues +  merge(LiveVariables::LivenessValues valsA, +        LiveVariables::LivenessValues valsB); +       +  LiveVariables::LivenessValues runOnBlock(const CFGBlock *block, +                                           LiveVariables::LivenessValues val, +                                           LiveVariables::Observer *obs = 0); + +  void dumpBlockLiveness(const SourceManager& M); + +  LiveVariablesImpl(AnalysisDeclContext &ac, bool KillAtAssign) +    : analysisContext(ac), +      SSetFact(false), // Do not canonicalize ImmutableSets by default. +      DSetFact(false), // This is a *major* performance win. +      killAtAssign(KillAtAssign) {} +}; +} + +static LiveVariablesImpl &getImpl(void *x) { +  return *((LiveVariablesImpl *) x); +} + +//===----------------------------------------------------------------------===// +// Operations and queries on LivenessValues. +//===----------------------------------------------------------------------===// + +bool LiveVariables::LivenessValues::isLive(const Stmt *S) const { +  return liveStmts.contains(S); +} + +bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const { +  return liveDecls.contains(D); +} + +namespace { +  template <typename SET> +  SET mergeSets(SET A, SET B) { +    if (A.isEmpty()) +      return B; +     +    for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) { +      A = A.add(*it); +    } +    return A; +  } +} + +void LiveVariables::Observer::anchor() { } + +LiveVariables::LivenessValues +LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA, +                         LiveVariables::LivenessValues valsB) {   +   +  llvm::ImmutableSetRef<const Stmt *> +    SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()), +    SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()); +                                                 +   +  llvm::ImmutableSetRef<const VarDecl *> +    DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()), +    DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()); +   + +  SSetRefA = mergeSets(SSetRefA, SSetRefB); +  DSetRefA = mergeSets(DSetRefA, DSetRefB); +   +  // asImmutableSet() canonicalizes the tree, allowing us to do an easy +  // comparison afterwards. +  return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(), +                                       DSetRefA.asImmutableSet());   +} + +bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const { +  return liveStmts == V.liveStmts && liveDecls == V.liveDecls; +} + +//===----------------------------------------------------------------------===// +// Query methods. +//===----------------------------------------------------------------------===// + +static bool isAlwaysAlive(const VarDecl *D) { +  return D->hasGlobalStorage(); +} + +bool LiveVariables::isLive(const CFGBlock *B, const VarDecl *D) { +  return isAlwaysAlive(D) || getImpl(impl).blocksEndToLiveness[B].isLive(D); +} + +bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) { +  return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D); +} + +bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) { +  return getImpl(impl).stmtsToLiveness[Loc].isLive(S); +} + +//===----------------------------------------------------------------------===// +// Dataflow computation. +//===----------------------------------------------------------------------===// + +namespace { +class TransferFunctions : public StmtVisitor<TransferFunctions> { +  LiveVariablesImpl &LV; +  LiveVariables::LivenessValues &val; +  LiveVariables::Observer *observer; +  const CFGBlock *currentBlock; +public: +  TransferFunctions(LiveVariablesImpl &im, +                    LiveVariables::LivenessValues &Val, +                    LiveVariables::Observer *Observer, +                    const CFGBlock *CurrentBlock) +  : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {} + +  void VisitBinaryOperator(BinaryOperator *BO); +  void VisitBlockExpr(BlockExpr *BE); +  void VisitDeclRefExpr(DeclRefExpr *DR);   +  void VisitDeclStmt(DeclStmt *DS); +  void VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS); +  void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE); +  void VisitUnaryOperator(UnaryOperator *UO); +  void Visit(Stmt *S); +}; +} + +static const VariableArrayType *FindVA(QualType Ty) { +  const Type *ty = Ty.getTypePtr(); +  while (const ArrayType *VT = dyn_cast<ArrayType>(ty)) { +    if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(VT)) +      if (VAT->getSizeExpr()) +        return VAT; +     +    ty = VT->getElementType().getTypePtr(); +  } +   +  return 0; +} + +static const Stmt *LookThroughStmt(const Stmt *S) { +  while (S) { +    if (const Expr *Ex = dyn_cast<Expr>(S)) +      S = Ex->IgnoreParens();     +    if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) { +      S = EWC->getSubExpr(); +      continue; +    } +    if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) { +      S = OVE->getSourceExpr(); +      continue; +    } +    break; +  } +  return S; +} + +static void AddLiveStmt(llvm::ImmutableSet<const Stmt *> &Set, +                        llvm::ImmutableSet<const Stmt *>::Factory &F, +                        const Stmt *S) { +  Set = F.add(Set, LookThroughStmt(S)); +} + +void TransferFunctions::Visit(Stmt *S) { +  if (observer) +    observer->observeStmt(S, currentBlock, val); +   +  StmtVisitor<TransferFunctions>::Visit(S); +   +  if (isa<Expr>(S)) { +    val.liveStmts = LV.SSetFact.remove(val.liveStmts, S); +  } + +  // Mark all children expressions live. +   +  switch (S->getStmtClass()) { +    default: +      break; +    case Stmt::StmtExprClass: { +      // For statement expressions, look through the compound statement. +      S = cast<StmtExpr>(S)->getSubStmt(); +      break; +    } +    case Stmt::CXXMemberCallExprClass: { +      // Include the implicit "this" pointer as being live. +      CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S); +      if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) { +        AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj); +      } +      break; +    } +    case Stmt::DeclStmtClass: { +      const DeclStmt *DS = cast<DeclStmt>(S); +      if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) { +        for (const VariableArrayType* VA = FindVA(VD->getType()); +             VA != 0; VA = FindVA(VA->getElementType())) { +          AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr()); +        } +      } +      break; +    } +    case Stmt::PseudoObjectExprClass: { +      // A pseudo-object operation only directly consumes its result +      // expression. +      Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr(); +      if (!child) return; +      if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child)) +        child = OV->getSourceExpr(); +      child = child->IgnoreParens(); +      val.liveStmts = LV.SSetFact.add(val.liveStmts, child); +      return; +    } + +    // FIXME: These cases eventually shouldn't be needed. +    case Stmt::ExprWithCleanupsClass: { +      S = cast<ExprWithCleanups>(S)->getSubExpr(); +      break; +    } +    case Stmt::CXXBindTemporaryExprClass: { +      S = cast<CXXBindTemporaryExpr>(S)->getSubExpr(); +      break; +    } +    case Stmt::UnaryExprOrTypeTraitExprClass: { +      // No need to unconditionally visit subexpressions. +      return; +    } +  } +   +  for (Stmt::child_iterator it = S->child_begin(), ei = S->child_end(); +       it != ei; ++it) { +    if (Stmt *child = *it) +      AddLiveStmt(val.liveStmts, LV.SSetFact, child); +  } +} + +void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { +  if (B->isAssignmentOp()) { +    if (!LV.killAtAssign) +      return; +     +    // Assigning to a variable? +    Expr *LHS = B->getLHS()->IgnoreParens(); +     +    if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) +      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { +        // Assignments to references don't kill the ref's address +        if (VD->getType()->isReferenceType()) +          return; + +        if (!isAlwaysAlive(VD)) { +          // The variable is now dead. +          val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); +        } + +        if (observer) +          observer->observerKill(DR); +      } +  } +} + +void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { +  AnalysisDeclContext::referenced_decls_iterator I, E; +  llvm::tie(I, E) = +    LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl()); +  for ( ; I != E ; ++I) { +    const VarDecl *VD = *I; +    if (isAlwaysAlive(VD)) +      continue; +    val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); +  } +} + +void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) { +  if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) +    if (!isAlwaysAlive(D) && LV.inAssignment.find(DR) == LV.inAssignment.end()) +      val.liveDecls = LV.DSetFact.add(val.liveDecls, D); +} + +void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { +  for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end(); +       DI != DE; ++DI) +    if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) { +      if (!isAlwaysAlive(VD)) +        val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); +    } +} + +void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) { +  // Kill the iteration variable. +  DeclRefExpr *DR = 0; +  const VarDecl *VD = 0; + +  Stmt *element = OS->getElement(); +  if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) { +    VD = cast<VarDecl>(DS->getSingleDecl()); +  } +  else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) { +    VD = cast<VarDecl>(DR->getDecl()); +  } +   +  if (VD) { +    val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); +    if (observer && DR) +      observer->observerKill(DR); +  } +} + +void TransferFunctions:: +VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE) +{ +  // While sizeof(var) doesn't technically extend the liveness of 'var', it +  // does extent the liveness of metadata if 'var' is a VariableArrayType. +  // We handle that special case here. +  if (UE->getKind() != UETT_SizeOf || UE->isArgumentType()) +    return; + +  const Expr *subEx = UE->getArgumentExpr(); +  if (subEx->getType()->isVariableArrayType()) { +    assert(subEx->isLValue()); +    val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens()); +  } +} + +void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) { +  // Treat ++/-- as a kill. +  // Note we don't actually have to do anything if we don't have an observer, +  // since a ++/-- acts as both a kill and a "use". +  if (!observer) +    return; +   +  switch (UO->getOpcode()) { +  default: +    return; +  case UO_PostInc: +  case UO_PostDec:     +  case UO_PreInc: +  case UO_PreDec: +    break; +  } +   +  if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) +    if (isa<VarDecl>(DR->getDecl())) { +      // Treat ++/-- as a kill. +      observer->observerKill(DR); +    } +} + +LiveVariables::LivenessValues +LiveVariablesImpl::runOnBlock(const CFGBlock *block, +                              LiveVariables::LivenessValues val, +                              LiveVariables::Observer *obs) { + +  TransferFunctions TF(*this, val, obs, block); +   +  // Visit the terminator (if any). +  if (const Stmt *term = block->getTerminator()) +    TF.Visit(const_cast<Stmt*>(term)); +   +  // Apply the transfer function for all Stmts in the block. +  for (CFGBlock::const_reverse_iterator it = block->rbegin(), +       ei = block->rend(); it != ei; ++it) { +    const CFGElement &elem = *it; +    if (!isa<CFGStmt>(elem)) +      continue; +     +    const Stmt *S = cast<CFGStmt>(elem).getStmt(); +    TF.Visit(const_cast<Stmt*>(S)); +    stmtsToLiveness[S] = val; +  } +  return val; +} + +void LiveVariables::runOnAllBlocks(LiveVariables::Observer &obs) { +  const CFG *cfg = getImpl(impl).analysisContext.getCFG(); +  for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) +    getImpl(impl).runOnBlock(*it, getImpl(impl).blocksEndToLiveness[*it], &obs);     +} + +LiveVariables::LiveVariables(void *im) : impl(im) {}  + +LiveVariables::~LiveVariables() { +  delete (LiveVariablesImpl*) impl; +} + +LiveVariables * +LiveVariables::computeLiveness(AnalysisDeclContext &AC, +                                 bool killAtAssign) { + +  // No CFG?  Bail out. +  CFG *cfg = AC.getCFG(); +  if (!cfg) +    return 0; + +  LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign); + +  // Construct the dataflow worklist.  Enqueue the exit block as the +  // start of the analysis. +  DataflowWorklist worklist(*cfg, AC); +  llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs()); + +  // FIXME: we should enqueue using post order. +  for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { +    const CFGBlock *block = *it; +    worklist.enqueueBlock(block); +     +    // FIXME: Scan for DeclRefExprs using in the LHS of an assignment. +    // We need to do this because we lack context in the reverse analysis +    // to determine if a DeclRefExpr appears in such a context, and thus +    // doesn't constitute a "use". +    if (killAtAssign) +      for (CFGBlock::const_iterator bi = block->begin(), be = block->end(); +           bi != be; ++bi) { +        if (const CFGStmt *cs = bi->getAs<CFGStmt>()) { +          if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(cs->getStmt())) { +            if (BO->getOpcode() == BO_Assign) { +              if (const DeclRefExpr *DR = +                    dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) { +                LV->inAssignment[DR] = 1; +              } +            } +          } +        } +      } +  } +   +  worklist.sortWorklist(); +   +  while (const CFGBlock *block = worklist.dequeue()) { +    // Determine if the block's end value has changed.  If not, we +    // have nothing left to do for this block. +    LivenessValues &prevVal = LV->blocksEndToLiveness[block]; +     +    // Merge the values of all successor blocks. +    LivenessValues val; +    for (CFGBlock::const_succ_iterator it = block->succ_begin(), +                                       ei = block->succ_end(); it != ei; ++it) { +      if (const CFGBlock *succ = *it) {      +        val = LV->merge(val, LV->blocksBeginToLiveness[succ]); +      } +    } +     +    if (!everAnalyzedBlock[block->getBlockID()]) +      everAnalyzedBlock[block->getBlockID()] = true; +    else if (prevVal.equals(val)) +      continue; + +    prevVal = val; +     +    // Update the dataflow value for the start of this block. +    LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val); +     +    // Enqueue the value to the predecessors. +    worklist.enqueuePredecessors(block); +  } +   +  return new LiveVariables(LV); +} + +static bool compare_entries(const CFGBlock *A, const CFGBlock *B) { +  return A->getBlockID() < B->getBlockID(); +} + +static bool compare_vd_entries(const Decl *A, const Decl *B) { +  SourceLocation ALoc = A->getLocStart(); +  SourceLocation BLoc = B->getLocStart(); +  return ALoc.getRawEncoding() < BLoc.getRawEncoding(); +} + +void LiveVariables::dumpBlockLiveness(const SourceManager &M) { +  getImpl(impl).dumpBlockLiveness(M); +} + +void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) { +  std::vector<const CFGBlock *> vec; +  for (llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues>::iterator +       it = blocksEndToLiveness.begin(), ei = blocksEndToLiveness.end(); +       it != ei; ++it) { +    vec.push_back(it->first);     +  } +  std::sort(vec.begin(), vec.end(), compare_entries); + +  std::vector<const VarDecl*> declVec; + +  for (std::vector<const CFGBlock *>::iterator +        it = vec.begin(), ei = vec.end(); it != ei; ++it) { +    llvm::errs() << "\n[ B" << (*it)->getBlockID() +                 << " (live variables at block exit) ]\n"; +     +    LiveVariables::LivenessValues vals = blocksEndToLiveness[*it]; +    declVec.clear(); +     +    for (llvm::ImmutableSet<const VarDecl *>::iterator si = +          vals.liveDecls.begin(), +          se = vals.liveDecls.end(); si != se; ++si) { +      declVec.push_back(*si);       +    } +     +    std::sort(declVec.begin(), declVec.end(), compare_vd_entries); +     +    for (std::vector<const VarDecl*>::iterator di = declVec.begin(), +         de = declVec.end(); di != de; ++di) { +      llvm::errs() << " " << (*di)->getDeclName().getAsString() +                   << " <"; +      (*di)->getLocation().dump(M); +      llvm::errs() << ">\n"; +    } +  } +  llvm::errs() << "\n";   +} + +const void *LiveVariables::getTag() { static int x; return &x; } +const void *RelaxedLiveVariables::getTag() { static int x; return &x; } diff --git a/clang/lib/Analysis/Makefile b/clang/lib/Analysis/Makefile new file mode 100644 index 0000000..fbbb83d --- /dev/null +++ b/clang/lib/Analysis/Makefile @@ -0,0 +1,18 @@ +##===- clang/lib/Analysis/Makefile -------------------------*- Makefile -*-===## +#  +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +#  +##===----------------------------------------------------------------------===## +# +# This implements analyses built on top of source-level CFGs.  +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME := clangAnalysis + +include $(CLANG_LEVEL)/Makefile + diff --git a/clang/lib/Analysis/PostOrderCFGView.cpp b/clang/lib/Analysis/PostOrderCFGView.cpp new file mode 100644 index 0000000..cfd66f7 --- /dev/null +++ b/clang/lib/Analysis/PostOrderCFGView.cpp @@ -0,0 +1,49 @@ +//===- PostOrderCFGView.cpp - Post order view of CFG blocks -------*- 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 post order view of the blocks in a CFG. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/PostOrderCFGView.h" + +using namespace clang; + +void PostOrderCFGView::anchor() { } + +PostOrderCFGView::PostOrderCFGView(const CFG *cfg) { +  Blocks.reserve(cfg->getNumBlockIDs()); +  CFGBlockSet BSet(cfg); +     +  for (po_iterator I = po_iterator::begin(cfg, BSet), +                   E = po_iterator::end(cfg, BSet); I != E; ++I) { +    BlockOrder[*I] = Blocks.size() + 1; +    Blocks.push_back(*I);       +  } +} + +PostOrderCFGView *PostOrderCFGView::create(AnalysisDeclContext &ctx) { +  const CFG *cfg = ctx.getCFG(); +  if (!cfg) +    return 0; +  return new PostOrderCFGView(cfg); +} + +const void *PostOrderCFGView::getTag() { static int x; return &x; } + +bool PostOrderCFGView::BlockOrderCompare::operator()(const CFGBlock *b1, +                                                     const CFGBlock *b2) const { +  PostOrderCFGView::BlockOrderTy::const_iterator b1It = POV.BlockOrder.find(b1); +  PostOrderCFGView::BlockOrderTy::const_iterator b2It = POV.BlockOrder.find(b2); +     +  unsigned b1V = (b1It == POV.BlockOrder.end()) ? 0 : b1It->second; +  unsigned b2V = (b2It == POV.BlockOrder.end()) ? 0 : b2It->second; +  return b1V > b2V; +} + diff --git a/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp new file mode 100644 index 0000000..e1049b3 --- /dev/null +++ b/clang/lib/Analysis/PrintfFormatString.cpp @@ -0,0 +1,669 @@ +//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Handling of format string in printf and friends.  The structure of format +// strings for fprintf() are described in C99 7.19.6.1. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/FormatString.h" +#include "FormatStringParsing.h" + +using clang::analyze_format_string::ArgTypeResult; +using clang::analyze_format_string::FormatStringHandler; +using clang::analyze_format_string::LengthModifier; +using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::ConversionSpecifier; +using clang::analyze_printf::PrintfSpecifier; + +using namespace clang; + +typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> +        PrintfSpecifierResult; + +//===----------------------------------------------------------------------===// +// Methods for parsing format strings. +//===----------------------------------------------------------------------===// + +using analyze_format_string::ParseNonPositionAmount; + +static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, +                           const char *Start, const char *&Beg, const char *E, +                           unsigned *argIndex) { +  if (argIndex) { +    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); +  } else { +    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, +                                           analyze_format_string::PrecisionPos); +    if (Amt.isInvalid()) +      return true; +    FS.setPrecision(Amt); +  } +  return false; +} + +static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, +                                                  const char *&Beg, +                                                  const char *E, +                                                  unsigned &argIndex, +                                                  const LangOptions &LO) { + +  using namespace clang::analyze_format_string; +  using namespace clang::analyze_printf; + +  const char *I = Beg; +  const char *Start = 0; +  UpdateOnReturn <const char*> UpdateBeg(Beg, I); + +  // Look for a '%' character that indicates the start of a format specifier. +  for ( ; I != E ; ++I) { +    char c = *I; +    if (c == '\0') { +      // Detect spurious null characters, which are likely errors. +      H.HandleNullChar(I); +      return true; +    } +    if (c == '%') { +      Start = I++;  // Record the start of the format specifier. +      break; +    } +  } + +  // No format specifier found? +  if (!Start) +    return false; + +  if (I == E) { +    // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } + +  PrintfSpecifier FS; +  if (ParseArgPosition(H, FS, Start, I, E)) +    return true; + +  if (I == E) { +    // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } + +  // Look for flags (if any). +  bool hasMore = true; +  for ( ; I != E; ++I) { +    switch (*I) { +      default: hasMore = false; break; +      case '\'': +        // FIXME: POSIX specific.  Always accept? +        FS.setHasThousandsGrouping(I); +        break; +      case '-': FS.setIsLeftJustified(I); break; +      case '+': FS.setHasPlusPrefix(I); break; +      case ' ': FS.setHasSpacePrefix(I); break; +      case '#': FS.setHasAlternativeForm(I); break; +      case '0': FS.setHasLeadingZeros(I); break; +    } +    if (!hasMore) +      break; +  } + +  if (I == E) { +    // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } + +  // Look for the field width (if any). +  if (ParseFieldWidth(H, FS, Start, I, E, +                      FS.usesPositionalArg() ? 0 : &argIndex)) +    return true; + +  if (I == E) { +    // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } + +  // Look for the precision (if any). +  if (*I == '.') { +    ++I; +    if (I == E) { +      H.HandleIncompleteSpecifier(Start, E - Start); +      return true; +    } + +    if (ParsePrecision(H, FS, Start, I, E, +                       FS.usesPositionalArg() ? 0 : &argIndex)) +      return true; + +    if (I == E) { +      // No more characters left? +      H.HandleIncompleteSpecifier(Start, E - Start); +      return true; +    } +  } + +  // Look for the length modifier. +  if (ParseLengthModifier(FS, I, E, LO) && I == E) { +    // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } + +  if (*I == '\0') { +    // Detect spurious null characters, which are likely errors. +    H.HandleNullChar(I); +    return true; +  } + +  // Finally, look for the conversion specifier. +  const char *conversionPosition = I++; +  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; +  switch (*conversionPosition) { +    default: +      break; +    // C99: 7.19.6.1 (section 8). +    case '%': k = ConversionSpecifier::PercentArg;   break; +    case 'A': k = ConversionSpecifier::AArg; break; +    case 'E': k = ConversionSpecifier::EArg; break; +    case 'F': k = ConversionSpecifier::FArg; break; +    case 'G': k = ConversionSpecifier::GArg; break; +    case 'X': k = ConversionSpecifier::XArg; break; +    case 'a': k = ConversionSpecifier::aArg; break; +    case 'c': k = ConversionSpecifier::cArg; break; +    case 'd': k = ConversionSpecifier::dArg; break; +    case 'e': k = ConversionSpecifier::eArg; break; +    case 'f': k = ConversionSpecifier::fArg; break; +    case 'g': k = ConversionSpecifier::gArg; break; +    case 'i': k = ConversionSpecifier::iArg; break; +    case 'n': k = ConversionSpecifier::nArg; break; +    case 'o': k = ConversionSpecifier::oArg; break; +    case 'p': k = ConversionSpecifier::pArg;   break; +    case 's': k = ConversionSpecifier::sArg;      break; +    case 'u': k = ConversionSpecifier::uArg; break; +    case 'x': k = ConversionSpecifier::xArg; break; +    // POSIX specific. +    case 'C': k = ConversionSpecifier::CArg; break; +    case 'S': k = ConversionSpecifier::SArg; break; +    // Objective-C. +    case '@': k = ConversionSpecifier::ObjCObjArg; break; +    // Glibc specific. +    case 'm': k = ConversionSpecifier::PrintErrno; break; +  } +  PrintfConversionSpecifier CS(conversionPosition, k); +  FS.setConversionSpecifier(CS); +  if (CS.consumesDataArgument() && !FS.usesPositionalArg()) +    FS.setArgIndex(argIndex++); + +  if (k == ConversionSpecifier::InvalidSpecifier) { +    // Assume the conversion takes one argument. +    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start); +  } +  return PrintfSpecifierResult(Start, FS); +} + +bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, +                                                     const char *I, +                                                     const char *E, +                                                     const LangOptions &LO) { + +  unsigned argIndex = 0; + +  // Keep looking for a format specifier until we have exhausted the string. +  while (I != E) { +    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, +                                                            LO); +    // Did a fail-stop error of any kind occur when parsing the specifier? +    // If so, don't do any more processing. +    if (FSR.shouldStop()) +      return true;; +    // Did we exhaust the string or encounter an error that +    // we can recover from? +    if (!FSR.hasValue()) +      continue; +    // We have a format specifier.  Pass it to the callback. +    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), +                                 I - FSR.getStart())) +      return true; +  } +  assert(I == E && "Format string not exhausted"); +  return false; +} + +//===----------------------------------------------------------------------===// +// Methods on PrintfSpecifier. +//===----------------------------------------------------------------------===// + +ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx, +                                          bool IsObjCLiteral) const { +  const PrintfConversionSpecifier &CS = getConversionSpecifier(); + +  if (!CS.consumesDataArgument()) +    return ArgTypeResult::Invalid(); + +  if (CS.getKind() == ConversionSpecifier::cArg) +    switch (LM.getKind()) { +      case LengthModifier::None: return Ctx.IntTy; +      case LengthModifier::AsLong: +        return ArgTypeResult(ArgTypeResult::WIntTy, "wint_t"); +      default: +        return ArgTypeResult::Invalid(); +    } + +  if (CS.isIntArg()) +    switch (LM.getKind()) { +      case LengthModifier::AsLongDouble: +        // GNU extension. +        return Ctx.LongLongTy; +      case LengthModifier::None: return Ctx.IntTy; +      case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy; +      case LengthModifier::AsShort: return Ctx.ShortTy; +      case LengthModifier::AsLong: return Ctx.LongTy; +      case LengthModifier::AsLongLong: +      case LengthModifier::AsQuad: +        return Ctx.LongLongTy; +      case LengthModifier::AsIntMax: +        return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t"); +      case LengthModifier::AsSizeT: +        // FIXME: How to get the corresponding signed version of size_t? +        return ArgTypeResult(); +      case LengthModifier::AsPtrDiff: +        return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t"); +      case LengthModifier::AsAllocate: +      case LengthModifier::AsMAllocate: +        return ArgTypeResult::Invalid(); +    } + +  if (CS.isUIntArg()) +    switch (LM.getKind()) { +      case LengthModifier::AsLongDouble: +        // GNU extension. +        return Ctx.UnsignedLongLongTy; +      case LengthModifier::None: return Ctx.UnsignedIntTy; +      case LengthModifier::AsChar: return Ctx.UnsignedCharTy; +      case LengthModifier::AsShort: return Ctx.UnsignedShortTy; +      case LengthModifier::AsLong: return Ctx.UnsignedLongTy; +      case LengthModifier::AsLongLong: +      case LengthModifier::AsQuad: +        return Ctx.UnsignedLongLongTy; +      case LengthModifier::AsIntMax: +        return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t"); +      case LengthModifier::AsSizeT: +        return ArgTypeResult(Ctx.getSizeType(), "size_t"); +      case LengthModifier::AsPtrDiff: +        // FIXME: How to get the corresponding unsigned +        // version of ptrdiff_t? +        return ArgTypeResult(); +      case LengthModifier::AsAllocate: +      case LengthModifier::AsMAllocate: +        return ArgTypeResult::Invalid(); +    } + +  if (CS.isDoubleArg()) { +    if (LM.getKind() == LengthModifier::AsLongDouble) +      return Ctx.LongDoubleTy; +    return Ctx.DoubleTy; +  } + +  switch (CS.getKind()) { +    case ConversionSpecifier::sArg: +      if (LM.getKind() == LengthModifier::AsWideChar) { +        if (IsObjCLiteral) +          return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); +        return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *"); +      } +      return ArgTypeResult::CStrTy; +    case ConversionSpecifier::SArg: +      if (IsObjCLiteral) +        return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()); +      return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *"); +    case ConversionSpecifier::CArg: +      if (IsObjCLiteral) +        return Ctx.UnsignedShortTy; +      return ArgTypeResult(Ctx.WCharTy, "wchar_t"); +    case ConversionSpecifier::pArg: +      return ArgTypeResult::CPointerTy; +    case ConversionSpecifier::ObjCObjArg: +      return ArgTypeResult::ObjCPointerTy; +    default: +      break; +  } + +  // FIXME: Handle other cases. +  return ArgTypeResult(); +} + +bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, +                              ASTContext &Ctx, bool IsObjCLiteral) { +  // Handle strings first (char *, wchar_t *) +  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { +    CS.setKind(ConversionSpecifier::sArg); + +    // Disable irrelevant flags +    HasAlternativeForm = 0; +    HasLeadingZeroes = 0; + +    // Set the long length modifier for wide characters +    if (QT->getPointeeType()->isWideCharType()) +      LM.setKind(LengthModifier::AsWideChar); +    else +      LM.setKind(LengthModifier::None); + +    return true; +  } + +  // We can only work with builtin types. +  const BuiltinType *BT = QT->getAs<BuiltinType>(); +  if (!BT) +    return false; + +  // Set length modifier +  switch (BT->getKind()) { +  case BuiltinType::Bool: +  case BuiltinType::WChar_U: +  case BuiltinType::WChar_S: +  case BuiltinType::Char16: +  case BuiltinType::Char32: +  case BuiltinType::UInt128: +  case BuiltinType::Int128: +  case BuiltinType::Half: +    // Various types which are non-trivial to correct. +    return false; + +#define SIGNED_TYPE(Id, SingletonId) +#define UNSIGNED_TYPE(Id, SingletonId) +#define FLOATING_TYPE(Id, SingletonId) +#define BUILTIN_TYPE(Id, SingletonId) \ +  case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" +    // Misc other stuff which doesn't make sense here. +    return false; + +  case BuiltinType::UInt: +  case BuiltinType::Int: +  case BuiltinType::Float: +  case BuiltinType::Double: +    LM.setKind(LengthModifier::None); +    break; + +  case BuiltinType::Char_U: +  case BuiltinType::UChar: +  case BuiltinType::Char_S: +  case BuiltinType::SChar: +    LM.setKind(LengthModifier::AsChar); +    break; + +  case BuiltinType::Short: +  case BuiltinType::UShort: +    LM.setKind(LengthModifier::AsShort); +    break; + +  case BuiltinType::Long: +  case BuiltinType::ULong: +    LM.setKind(LengthModifier::AsLong); +    break; + +  case BuiltinType::LongLong: +  case BuiltinType::ULongLong: +    LM.setKind(LengthModifier::AsLongLong); +    break; + +  case BuiltinType::LongDouble: +    LM.setKind(LengthModifier::AsLongDouble); +    break; +  } + +  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. +  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) { +    const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier(); +    if (Identifier->getName() == "size_t") { +      LM.setKind(LengthModifier::AsSizeT); +    } else if (Identifier->getName() == "ssize_t") { +      // Not C99, but common in Unix. +      LM.setKind(LengthModifier::AsSizeT); +    } else if (Identifier->getName() == "intmax_t") { +      LM.setKind(LengthModifier::AsIntMax); +    } else if (Identifier->getName() == "uintmax_t") { +      LM.setKind(LengthModifier::AsIntMax); +    } else if (Identifier->getName() == "ptrdiff_t") { +      LM.setKind(LengthModifier::AsPtrDiff); +    } +  } + +  // If fixing the length modifier was enough, we are done. +  const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral); +  if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT)) +    return true; + +  // Set conversion specifier and disable any flags which do not apply to it. +  // Let typedefs to char fall through to int, as %c is silly for uint8_t. +  if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { +    CS.setKind(ConversionSpecifier::cArg); +    LM.setKind(LengthModifier::None); +    Precision.setHowSpecified(OptionalAmount::NotSpecified); +    HasAlternativeForm = 0; +    HasLeadingZeroes = 0; +    HasPlusPrefix = 0; +  } +  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType +  else if (QT->isRealFloatingType()) { +    CS.setKind(ConversionSpecifier::fArg); +  } +  else if (QT->isSignedIntegerType()) { +    CS.setKind(ConversionSpecifier::dArg); +    HasAlternativeForm = 0; +  } +  else if (QT->isUnsignedIntegerType()) { +    CS.setKind(ConversionSpecifier::uArg); +    HasAlternativeForm = 0; +    HasPlusPrefix = 0; +  } else { +    llvm_unreachable("Unexpected type"); +  } + +  return true; +} + +void PrintfSpecifier::toString(raw_ostream &os) const { +  // Whilst some features have no defined order, we are using the order +  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) +  os << "%"; + +  // Positional args +  if (usesPositionalArg()) { +    os << getPositionalArgIndex() << "$"; +  } + +  // Conversion flags +  if (IsLeftJustified)    os << "-"; +  if (HasPlusPrefix)      os << "+"; +  if (HasSpacePrefix)     os << " "; +  if (HasAlternativeForm) os << "#"; +  if (HasLeadingZeroes)   os << "0"; + +  // Minimum field width +  FieldWidth.toString(os); +  // Precision +  Precision.toString(os); +  // Length modifier +  os << LM.toString(); +  // Conversion specifier +  os << CS.toString(); +} + +bool PrintfSpecifier::hasValidPlusPrefix() const { +  if (!HasPlusPrefix) +    return true; + +  // The plus prefix only makes sense for signed conversions +  switch (CS.getKind()) { +  case ConversionSpecifier::dArg: +  case ConversionSpecifier::iArg: +  case ConversionSpecifier::fArg: +  case ConversionSpecifier::FArg: +  case ConversionSpecifier::eArg: +  case ConversionSpecifier::EArg: +  case ConversionSpecifier::gArg: +  case ConversionSpecifier::GArg: +  case ConversionSpecifier::aArg: +  case ConversionSpecifier::AArg: +    return true; + +  default: +    return false; +  } +} + +bool PrintfSpecifier::hasValidAlternativeForm() const { +  if (!HasAlternativeForm) +    return true; + +  // Alternate form flag only valid with the oxXaAeEfFgG conversions +  switch (CS.getKind()) { +  case ConversionSpecifier::oArg: +  case ConversionSpecifier::xArg: +  case ConversionSpecifier::XArg: +  case ConversionSpecifier::aArg: +  case ConversionSpecifier::AArg: +  case ConversionSpecifier::eArg: +  case ConversionSpecifier::EArg: +  case ConversionSpecifier::fArg: +  case ConversionSpecifier::FArg: +  case ConversionSpecifier::gArg: +  case ConversionSpecifier::GArg: +    return true; + +  default: +    return false; +  } +} + +bool PrintfSpecifier::hasValidLeadingZeros() const { +  if (!HasLeadingZeroes) +    return true; + +  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions +  switch (CS.getKind()) { +  case ConversionSpecifier::dArg: +  case ConversionSpecifier::iArg: +  case ConversionSpecifier::oArg: +  case ConversionSpecifier::uArg: +  case ConversionSpecifier::xArg: +  case ConversionSpecifier::XArg: +  case ConversionSpecifier::aArg: +  case ConversionSpecifier::AArg: +  case ConversionSpecifier::eArg: +  case ConversionSpecifier::EArg: +  case ConversionSpecifier::fArg: +  case ConversionSpecifier::FArg: +  case ConversionSpecifier::gArg: +  case ConversionSpecifier::GArg: +    return true; + +  default: +    return false; +  } +} + +bool PrintfSpecifier::hasValidSpacePrefix() const { +  if (!HasSpacePrefix) +    return true; + +  // The space prefix only makes sense for signed conversions +  switch (CS.getKind()) { +  case ConversionSpecifier::dArg: +  case ConversionSpecifier::iArg: +  case ConversionSpecifier::fArg: +  case ConversionSpecifier::FArg: +  case ConversionSpecifier::eArg: +  case ConversionSpecifier::EArg: +  case ConversionSpecifier::gArg: +  case ConversionSpecifier::GArg: +  case ConversionSpecifier::aArg: +  case ConversionSpecifier::AArg: +    return true; + +  default: +    return false; +  } +} + +bool PrintfSpecifier::hasValidLeftJustified() const { +  if (!IsLeftJustified) +    return true; + +  // The left justified flag is valid for all conversions except n +  switch (CS.getKind()) { +  case ConversionSpecifier::nArg: +    return false; + +  default: +    return true; +  } +} + +bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { +  if (!HasThousandsGrouping) +    return true; + +  switch (CS.getKind()) { +    case ConversionSpecifier::dArg: +    case ConversionSpecifier::iArg: +    case ConversionSpecifier::uArg: +    case ConversionSpecifier::fArg: +    case ConversionSpecifier::FArg: +    case ConversionSpecifier::gArg: +    case ConversionSpecifier::GArg: +      return true; +    default: +      return false; +  } +} + +bool PrintfSpecifier::hasValidPrecision() const { +  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) +    return true; + +  // Precision is only valid with the diouxXaAeEfFgGs conversions +  switch (CS.getKind()) { +  case ConversionSpecifier::dArg: +  case ConversionSpecifier::iArg: +  case ConversionSpecifier::oArg: +  case ConversionSpecifier::uArg: +  case ConversionSpecifier::xArg: +  case ConversionSpecifier::XArg: +  case ConversionSpecifier::aArg: +  case ConversionSpecifier::AArg: +  case ConversionSpecifier::eArg: +  case ConversionSpecifier::EArg: +  case ConversionSpecifier::fArg: +  case ConversionSpecifier::FArg: +  case ConversionSpecifier::gArg: +  case ConversionSpecifier::GArg: +  case ConversionSpecifier::sArg: +    return true; + +  default: +    return false; +  } +} +bool PrintfSpecifier::hasValidFieldWidth() const { +  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) +      return true; + +  // The field width is valid for all conversions except n +  switch (CS.getKind()) { +  case ConversionSpecifier::nArg: +    return false; + +  default: +    return true; +  } +} diff --git a/clang/lib/Analysis/ProgramPoint.cpp b/clang/lib/Analysis/ProgramPoint.cpp new file mode 100644 index 0000000..3f711b4 --- /dev/null +++ b/clang/lib/Analysis/ProgramPoint.cpp @@ -0,0 +1,49 @@ +//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/ +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file defines the interface ProgramPoint, which identifies a +//  distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/ProgramPoint.h" + +using namespace clang; + +ProgramPointTag::~ProgramPointTag() {} + +ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K, +                                           const LocationContext *LC, +                                           const ProgramPointTag *tag){ +  switch (K) { +    default: +      llvm_unreachable("Unhandled ProgramPoint kind"); +    case ProgramPoint::PreStmtKind: +      return PreStmt(S, LC, tag); +    case ProgramPoint::PostStmtKind: +      return PostStmt(S, LC, tag); +    case ProgramPoint::PreLoadKind: +      return PreLoad(S, LC, tag); +    case ProgramPoint::PostLoadKind: +      return PostLoad(S, LC, tag); +    case ProgramPoint::PreStoreKind: +      return PreStore(S, LC, tag); +    case ProgramPoint::PostLValueKind: +      return PostLValue(S, LC, tag); +    case ProgramPoint::PostPurgeDeadSymbolsKind: +      return PostPurgeDeadSymbols(S, LC, tag); +  } +} + +SimpleProgramPointTag::SimpleProgramPointTag(StringRef description) +  : desc(description) {} + +StringRef SimpleProgramPointTag::getTagDescription() const { +  return desc; +} diff --git a/clang/lib/Analysis/PseudoConstantAnalysis.cpp b/clang/lib/Analysis/PseudoConstantAnalysis.cpp new file mode 100644 index 0000000..c8b491a --- /dev/null +++ b/clang/lib/Analysis/PseudoConstantAnalysis.cpp @@ -0,0 +1,227 @@ +//== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tracks the usage of variables in a Decl body to see if they are +// never written to, implying that they constant. This is useful in static +// analysis to see if a developer might have intended a variable to be const. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" +#include <deque> + +using namespace clang; + +// The number of ValueDecls we want to keep track of by default (per-function) +#define VARDECL_SET_SIZE 256 +typedef llvm::SmallPtrSet<const VarDecl*, VARDECL_SET_SIZE> VarDeclSet; + +PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) : +      DeclBody(DeclBody), Analyzed(false) { +  NonConstantsImpl = new VarDeclSet; +  UsedVarsImpl = new VarDeclSet; +} + +PseudoConstantAnalysis::~PseudoConstantAnalysis() { +  delete (VarDeclSet*)NonConstantsImpl; +  delete (VarDeclSet*)UsedVarsImpl; +} + +// Returns true if the given ValueDecl is never written to in the given DeclBody +bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) { +  // Only local and static variables can be pseudoconstants +  if (!VD->hasLocalStorage() && !VD->isStaticLocal()) +    return false; + +  if (!Analyzed) { +    RunAnalysis(); +    Analyzed = true; +  } + +  VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; + +  return !NonConstants->count(VD); +} + +// Returns true if the variable was used (self assignments don't count) +bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) { +  if (!Analyzed) { +    RunAnalysis(); +    Analyzed = true; +  } + +  VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; + +  return UsedVars->count(VD); +} + +// Returns a Decl from a (Block)DeclRefExpr (if any) +const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) { +  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) +    return DR->getDecl(); +  else +    return 0; +} + +void PseudoConstantAnalysis::RunAnalysis() { +  std::deque<const Stmt *> WorkList; +  VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; +  VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; + +  // Start with the top level statement of the function +  WorkList.push_back(DeclBody); + +  while (!WorkList.empty()) { +    const Stmt *Head = WorkList.front(); +    WorkList.pop_front(); + +    if (const Expr *Ex = dyn_cast<Expr>(Head)) +      Head = Ex->IgnoreParenCasts(); + +    switch (Head->getStmtClass()) { +    // Case 1: Assignment operators modifying VarDecls +    case Stmt::BinaryOperatorClass: { +      const BinaryOperator *BO = cast<BinaryOperator>(Head); +      // Look for a Decl on the LHS +      const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts()); +      if (!LHSDecl) +        break; + +      // We found a binary operator with a DeclRefExpr on the LHS. We now check +      // for any of the assignment operators, implying that this Decl is being +      // written to. +      switch (BO->getOpcode()) { +      // Self-assignments don't count as use of a variable +      case BO_Assign: { +        // Look for a DeclRef on the RHS +        const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts()); + +        // If the Decls match, we have self-assignment +        if (LHSDecl == RHSDecl) +          // Do not visit the children +          continue; + +      } +      case BO_AddAssign: +      case BO_SubAssign: +      case BO_MulAssign: +      case BO_DivAssign: +      case BO_AndAssign: +      case BO_OrAssign: +      case BO_XorAssign: +      case BO_ShlAssign: +      case BO_ShrAssign: { +        const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl); +        // The DeclRefExpr is being assigned to - mark it as non-constant +        if (VD) +          NonConstants->insert(VD); +        break; +      } + +      default: +        break; +      } +      break; +    } + +    // Case 2: Pre/post increment/decrement and address of +    case Stmt::UnaryOperatorClass: { +      const UnaryOperator *UO = cast<UnaryOperator>(Head); + +      // Look for a DeclRef in the subexpression +      const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts()); +      if (!D) +        break; + +      // We found a unary operator with a DeclRef as a subexpression. We now +      // check for any of the increment/decrement operators, as well as +      // addressOf. +      switch (UO->getOpcode()) { +      case UO_PostDec: +      case UO_PostInc: +      case UO_PreDec: +      case UO_PreInc: +        // The DeclRef is being changed - mark it as non-constant +      case UO_AddrOf: { +        // If we are taking the address of the DeclRefExpr, assume it is +        // non-constant. +        const VarDecl *VD = dyn_cast<VarDecl>(D); +        if (VD) +          NonConstants->insert(VD); +        break; +      } + +      default: +        break; +      } +      break; +    } + +    // Case 3: Reference Declarations +    case Stmt::DeclStmtClass: { +      const DeclStmt *DS = cast<DeclStmt>(Head); +      // Iterate over each decl and see if any of them contain reference decls +      for (DeclStmt::const_decl_iterator I = DS->decl_begin(), +          E = DS->decl_end(); I != E; ++I) { +        // We only care about VarDecls +        const VarDecl *VD = dyn_cast<VarDecl>(*I); +        if (!VD) +          continue; + +        // We found a VarDecl; make sure it is a reference type +        if (!VD->getType().getTypePtr()->isReferenceType()) +          continue; + +        // Try to find a Decl in the initializer +        const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts()); +        if (!D) +          break; + +        // If the reference is to another var, add the var to the non-constant +        // list +        if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) { +          NonConstants->insert(RefVD); +          continue; +        } +      } +      break; +    } + +    // Case 4: Variable references +    case Stmt::DeclRefExprClass: { +      const DeclRefExpr *DR = cast<DeclRefExpr>(Head); +      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { +        // Add the Decl to the used list +        UsedVars->insert(VD); +        continue; +      } +      break; +    } + +    // Case 5: Block expressions +    case Stmt::BlockExprClass: { +      const BlockExpr *B = cast<BlockExpr>(Head); +      // Add the body of the block to the list +      WorkList.push_back(B->getBody()); +      continue; +    } + +    default: +      break; +    } // switch (head->getStmtClass()) + +    // Add all substatements to the worklist +    for (Stmt::const_child_range I = Head->children(); I; ++I) +      if (*I) +        WorkList.push_back(*I); +  } // while (!WorkList.empty()) +} diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp new file mode 100644 index 0000000..bb63e2c --- /dev/null +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -0,0 +1,331 @@ +//=- 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; + +namespace { +class DeadCodeScan { +  llvm::BitVector Visited; +  llvm::BitVector &Reachable; +  llvm::SmallVector<const CFGBlock *, 10> WorkList; +   +  typedef llvm::SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12> +      DeferredLocsTy; +   +  DeferredLocsTy DeferredLocs; +   +public: +  DeadCodeScan(llvm::BitVector &reachable) +    : Visited(reachable.size()), +      Reachable(reachable) {} +   +  void enqueue(const CFGBlock *block);   +  unsigned scanBackwards(const CFGBlock *Start, +                         clang::reachable_code::Callback &CB); +   +  bool isDeadCodeRoot(const CFGBlock *Block); +   +  const Stmt *findDeadCode(const CFGBlock *Block); +   +  void reportDeadCode(const Stmt *S, +                      clang::reachable_code::Callback &CB); +}; +} + +void DeadCodeScan::enqueue(const CFGBlock *block) {   +  unsigned blockID = block->getBlockID(); +  if (Reachable[blockID] || Visited[blockID]) +    return; +  Visited[blockID] = true; +  WorkList.push_back(block); +} + +bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) { +  bool isDeadRoot = true; +   +  for (CFGBlock::const_pred_iterator I = Block->pred_begin(), +        E = Block->pred_end(); I != E; ++I) { +    if (const CFGBlock *PredBlock = *I) { +      unsigned blockID = PredBlock->getBlockID(); +      if (Visited[blockID]) { +        isDeadRoot = false; +        continue; +      } +      if (!Reachable[blockID]) { +        isDeadRoot = false; +        Visited[blockID] = true; +        WorkList.push_back(PredBlock); +        continue; +      } +    } +  } +   +  return isDeadRoot; +} + +static bool isValidDeadStmt(const Stmt *S) { +  if (S->getLocStart().isInvalid()) +    return false; +  if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) +    return BO->getOpcode() != BO_Comma; +  return true; +} + +const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) { +  for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I) +    if (const CFGStmt *CS = I->getAs<CFGStmt>()) { +      const Stmt *S = CS->getStmt(); +      if (isValidDeadStmt(S)) +        return S; +    } +   +  if (CFGTerminator T = Block->getTerminator()) { +    const Stmt *S = T.getStmt(); +    if (isValidDeadStmt(S)) +      return S;     +  } + +  return 0; +} + +static int SrcCmp(const void *p1, const void *p2) { +  return +    ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() < +    ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart(); +} + +unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, +                                     clang::reachable_code::Callback &CB) { + +  unsigned count = 0; +  enqueue(Start); +   +  while (!WorkList.empty()) { +    const CFGBlock *Block = WorkList.pop_back_val(); + +    // It is possible that this block has been marked reachable after +    // it was enqueued. +    if (Reachable[Block->getBlockID()]) +      continue; + +    // Look for any dead code within the block. +    const Stmt *S = findDeadCode(Block); +     +    if (!S) { +      // No dead code.  Possibly an empty block.  Look at dead predecessors. +      for (CFGBlock::const_pred_iterator I = Block->pred_begin(), +           E = Block->pred_end(); I != E; ++I) { +        if (const CFGBlock *predBlock = *I) +          enqueue(predBlock); +      } +      continue; +    } +     +    // Specially handle macro-expanded code. +    if (S->getLocStart().isMacroID()) { +      count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable); +      continue; +    } + +    if (isDeadCodeRoot(Block)) { +      reportDeadCode(S, CB); +      count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable); +    } +    else { +      // Record this statement as the possibly best location in a +      // strongly-connected component of dead code for emitting a +      // warning. +      DeferredLocs.push_back(std::make_pair(Block, S)); +    } +  } + +  // If we didn't find a dead root, then report the dead code with the +  // earliest location. +  if (!DeferredLocs.empty()) { +    llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp); +    for (DeferredLocsTy::iterator I = DeferredLocs.begin(), +          E = DeferredLocs.end(); I != E; ++I) { +      const CFGBlock *block = I->first; +      if (Reachable[block->getBlockID()]) +        continue; +      reportDeadCode(I->second, CB); +      count += clang::reachable_code::ScanReachableFromBlock(block, Reachable); +    } +  } +     +  return count; +} + +static SourceLocation GetUnreachableLoc(const Stmt *S, +                                        SourceRange &R1, +                                        SourceRange &R2) { +  R1 = R2 = SourceRange(); + +  if (const Expr *Ex = dyn_cast<Expr>(S)) +    S = Ex->IgnoreParenImpCasts(); + +  switch (S->getStmtClass()) { +    case Expr::BinaryOperatorClass: { +      const BinaryOperator *BO = cast<BinaryOperator>(S); +      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(); +} + +void DeadCodeScan::reportDeadCode(const Stmt *S, +                                  clang::reachable_code::Callback &CB) { +  SourceRange R1, R2; +  SourceLocation Loc = GetUnreachableLoc(S, R1, R2); +  CB.HandleUnreachable(Loc, R1, R2); +} + +namespace clang { namespace reachable_code { + +void Callback::anchor() { }   + +unsigned ScanReachableFromBlock(const CFGBlock *Start, +                                llvm::BitVector &Reachable) { +  unsigned count = 0; +   +  // Prep work queue +  SmallVector<const CFGBlock*, 32> WL; +   +  // The entry block may have already been marked reachable +  // by the caller. +  if (!Reachable[Start->getBlockID()]) { +    ++count; +    Reachable[Start->getBlockID()] = true; +  } +   +  WL.push_back(Start); +   +  // Find the reachable blocks from 'Start'. +  while (!WL.empty()) { +    const CFGBlock *item = WL.pop_back_val(); +     +    // 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) { +        unsigned blockID = B->getBlockID(); +        if (!Reachable[blockID]) { +          Reachable.set(blockID); +          WL.push_back(B); +          ++count; +        } +      } +  } +  return count; +} +   +void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB) { +  CFG *cfg = AC.getCFG(); +  if (!cfg) +    return; + +  // Scan for reachable blocks from the entrance of the CFG.   +  // If there are no unreachable blocks, we're done. +  llvm::BitVector reachable(cfg->getNumBlockIDs()); +  unsigned numReachable = ScanReachableFromBlock(&cfg->getEntry(), reachable); +  if (numReachable == cfg->getNumBlockIDs()) +    return; +   +  // If there aren't explicit EH edges, we should include the 'try' dispatch +  // blocks as roots. +  if (!AC.getCFGBuildOptions().AddEHEdges) { +    for (CFG::try_block_iterator I = cfg->try_blocks_begin(), +         E = cfg->try_blocks_end() ; I != E; ++I) { +      numReachable += ScanReachableFromBlock(*I, reachable); +    } +    if (numReachable == cfg->getNumBlockIDs()) +      return; +  } + +  // There are some unreachable blocks.  We need to find the root blocks that +  // contain code that should be considered unreachable.   +  for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { +    const CFGBlock *block = *I; +    // A block may have been marked reachable during this loop. +    if (reachable[block->getBlockID()]) +      continue; +     +    DeadCodeScan DS(reachable); +    numReachable += DS.scanBackwards(block, CB); +     +    if (numReachable == cfg->getNumBlockIDs()) +      return; +  } +} + +}} // end namespace clang::reachable_code diff --git a/clang/lib/Analysis/ScanfFormatString.cpp b/clang/lib/Analysis/ScanfFormatString.cpp new file mode 100644 index 0000000..6bc4adb --- /dev/null +++ b/clang/lib/Analysis/ScanfFormatString.cpp @@ -0,0 +1,499 @@ +//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Handling of format string in scanf and friends.  The structure of format +// strings for fscanf() are described in C99 7.19.6.2. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/FormatString.h" +#include "FormatStringParsing.h" + +using clang::analyze_format_string::ArgTypeResult; +using clang::analyze_format_string::FormatStringHandler; +using clang::analyze_format_string::LengthModifier; +using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::ConversionSpecifier; +using clang::analyze_scanf::ScanfArgTypeResult; +using clang::analyze_scanf::ScanfConversionSpecifier; +using clang::analyze_scanf::ScanfSpecifier; +using clang::UpdateOnReturn; +using namespace clang; + +typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier> +        ScanfSpecifierResult; + +static bool ParseScanList(FormatStringHandler &H, +                          ScanfConversionSpecifier &CS, +                          const char *&Beg, const char *E) { +  const char *I = Beg; +  const char *start = I - 1; +  UpdateOnReturn <const char*> UpdateBeg(Beg, I); + +  // No more characters? +  if (I == E) { +    H.HandleIncompleteScanList(start, I); +    return true; +  } +   +  // Special case: ']' is the first character. +  if (*I == ']') { +    if (++I == E) { +      H.HandleIncompleteScanList(start, I - 1); +      return true; +    } +  } + +  // Look for a ']' character which denotes the end of the scan list. +  while (*I != ']') { +    if (++I == E) { +      H.HandleIncompleteScanList(start, I - 1); +      return true; +    } +  }     + +  CS.setEndScanList(I); +  return false; +} + +// FIXME: Much of this is copy-paste from ParsePrintfSpecifier. +// We can possibly refactor. +static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, +                                                const char *&Beg, +                                                const char *E, +                                                unsigned &argIndex, +                                                const LangOptions &LO) { +   +  using namespace clang::analyze_scanf; +  const char *I = Beg; +  const char *Start = 0; +  UpdateOnReturn <const char*> UpdateBeg(Beg, I); + +    // Look for a '%' character that indicates the start of a format specifier. +  for ( ; I != E ; ++I) { +    char c = *I; +    if (c == '\0') { +        // Detect spurious null characters, which are likely errors. +      H.HandleNullChar(I); +      return true; +    } +    if (c == '%') { +      Start = I++;  // Record the start of the format specifier. +      break; +    } +  } +   +    // No format specifier found? +  if (!Start) +    return false; +   +  if (I == E) { +      // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } +   +  ScanfSpecifier FS; +  if (ParseArgPosition(H, FS, Start, I, E)) +    return true; + +  if (I == E) { +      // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } +   +  // Look for '*' flag if it is present. +  if (*I == '*') { +    FS.setSuppressAssignment(I); +    if (++I == E) { +      H.HandleIncompleteSpecifier(Start, E - Start); +      return true; +    } +  } +   +  // Look for the field width (if any).  Unlike printf, this is either +  // a fixed integer or isn't present. +  const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E); +  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) { +    assert(Amt.getHowSpecified() == OptionalAmount::Constant); +    FS.setFieldWidth(Amt); + +    if (I == E) { +      // No more characters left? +      H.HandleIncompleteSpecifier(Start, E - Start); +      return true; +    } +  } +   +  // Look for the length modifier. +  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) { +      // No more characters left? +    H.HandleIncompleteSpecifier(Start, E - Start); +    return true; +  } +   +  // Detect spurious null characters, which are likely errors. +  if (*I == '\0') { +    H.HandleNullChar(I); +    return true; +  } +   +  // Finally, look for the conversion specifier. +  const char *conversionPosition = I++; +  ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier; +  switch (*conversionPosition) { +    default: +      break; +    case '%': k = ConversionSpecifier::PercentArg;   break; +    case 'A': k = ConversionSpecifier::AArg; break; +    case 'E': k = ConversionSpecifier::EArg; break; +    case 'F': k = ConversionSpecifier::FArg; break; +    case 'G': k = ConversionSpecifier::GArg; break; +    case 'X': k = ConversionSpecifier::XArg; break; +    case 'a': k = ConversionSpecifier::aArg; break; +    case 'd': k = ConversionSpecifier::dArg; break; +    case 'e': k = ConversionSpecifier::eArg; break; +    case 'f': k = ConversionSpecifier::fArg; break; +    case 'g': k = ConversionSpecifier::gArg; break; +    case 'i': k = ConversionSpecifier::iArg; break; +    case 'n': k = ConversionSpecifier::nArg; break; +    case 'c': k = ConversionSpecifier::cArg; break; +    case 'C': k = ConversionSpecifier::CArg; break; +    case 'S': k = ConversionSpecifier::SArg; break; +    case '[': k = ConversionSpecifier::ScanListArg; break; +    case 'u': k = ConversionSpecifier::uArg; break; +    case 'x': k = ConversionSpecifier::xArg; break; +    case 'o': k = ConversionSpecifier::oArg; break; +    case 's': k = ConversionSpecifier::sArg; break; +    case 'p': k = ConversionSpecifier::pArg; break; +  } +  ScanfConversionSpecifier CS(conversionPosition, k); +  if (k == ScanfConversionSpecifier::ScanListArg) { +    if (ParseScanList(H, CS, I, E)) +      return true; +  } +  FS.setConversionSpecifier(CS); +  if (CS.consumesDataArgument() && !FS.getSuppressAssignment() +      && !FS.usesPositionalArg()) +    FS.setArgIndex(argIndex++); +   +  // FIXME: '%' and '*' doesn't make sense.  Issue a warning. +  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense. +   +  if (k == ScanfConversionSpecifier::InvalidSpecifier) { +    // Assume the conversion takes one argument. +    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, I - Beg); +  } +  return ScanfSpecifierResult(Start, FS); +} + +ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const { +  const ScanfConversionSpecifier &CS = getConversionSpecifier(); + +  if (!CS.consumesDataArgument()) +    return ScanfArgTypeResult::Invalid(); + +  switch(CS.getKind()) { +    // Signed int. +    case ConversionSpecifier::dArg: +    case ConversionSpecifier::iArg: +      switch (LM.getKind()) { +        case LengthModifier::None: return ArgTypeResult(Ctx.IntTy); +        case LengthModifier::AsChar: +          return ArgTypeResult(ArgTypeResult::AnyCharTy); +        case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy); +        case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy); +        case LengthModifier::AsLongLong: +        case LengthModifier::AsQuad: +          return ArgTypeResult(Ctx.LongLongTy); +        case LengthModifier::AsIntMax: +          return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *"); +        case LengthModifier::AsSizeT: +          // FIXME: ssize_t. +          return ScanfArgTypeResult(); +        case LengthModifier::AsPtrDiff: +          return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *"); +        case LengthModifier::AsLongDouble: +          // GNU extension. +          return ArgTypeResult(Ctx.LongLongTy); +        case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid(); +        case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid(); +      } + +    // Unsigned int. +    case ConversionSpecifier::oArg: +    case ConversionSpecifier::uArg: +    case ConversionSpecifier::xArg: +    case ConversionSpecifier::XArg: +      switch (LM.getKind()) { +        case LengthModifier::None: return ArgTypeResult(Ctx.UnsignedIntTy); +        case LengthModifier::AsChar: return ArgTypeResult(Ctx.UnsignedCharTy); +        case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy); +        case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy); +        case LengthModifier::AsLongLong: +        case LengthModifier::AsQuad: +          return ArgTypeResult(Ctx.UnsignedLongLongTy); +        case LengthModifier::AsIntMax: +          return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *"); +        case LengthModifier::AsSizeT: +          return ScanfArgTypeResult(Ctx.getSizeType(), "size_t *"); +        case LengthModifier::AsPtrDiff: +          // FIXME: Unsigned version of ptrdiff_t? +          return ScanfArgTypeResult(); +        case LengthModifier::AsLongDouble: +          // GNU extension. +          return ArgTypeResult(Ctx.UnsignedLongLongTy); +        case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid(); +        case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid(); +      } + +    // Float. +    case ConversionSpecifier::aArg: +    case ConversionSpecifier::AArg: +    case ConversionSpecifier::eArg: +    case ConversionSpecifier::EArg: +    case ConversionSpecifier::fArg: +    case ConversionSpecifier::FArg: +    case ConversionSpecifier::gArg: +    case ConversionSpecifier::GArg: +      switch (LM.getKind()) { +        case LengthModifier::None: return ArgTypeResult(Ctx.FloatTy); +        case LengthModifier::AsLong: return ArgTypeResult(Ctx.DoubleTy); +        case LengthModifier::AsLongDouble: +          return ArgTypeResult(Ctx.LongDoubleTy); +        default: +          return ScanfArgTypeResult::Invalid(); +      } + +    // Char, string and scanlist. +    case ConversionSpecifier::cArg: +    case ConversionSpecifier::sArg: +    case ConversionSpecifier::ScanListArg: +      switch (LM.getKind()) { +        case LengthModifier::None: return ScanfArgTypeResult::CStrTy; +        case LengthModifier::AsLong: +          return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *"); +        case LengthModifier::AsAllocate: +        case LengthModifier::AsMAllocate: +          return ScanfArgTypeResult(ArgTypeResult::CStrTy); +        default: +          return ScanfArgTypeResult::Invalid(); +      } +    case ConversionSpecifier::CArg: +    case ConversionSpecifier::SArg: +      // FIXME: Mac OS X specific? +      switch (LM.getKind()) { +        case LengthModifier::None: +          return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *"); +        case LengthModifier::AsAllocate: +        case LengthModifier::AsMAllocate: +          return ScanfArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t **"); +        default: +          return ScanfArgTypeResult::Invalid(); +      } + +    // Pointer. +    case ConversionSpecifier::pArg: +      return ScanfArgTypeResult(ArgTypeResult(ArgTypeResult::CPointerTy)); + +    default: +      break; +  } + +  return ScanfArgTypeResult(); +} + +bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, +                             ASTContext &Ctx) { +  if (!QT->isPointerType()) +    return false; + +  QualType PT = QT->getPointeeType(); +  const BuiltinType *BT = PT->getAs<BuiltinType>(); +  if (!BT) +    return false; + +  // Pointer to a character. +  if (PT->isAnyCharacterType()) { +    CS.setKind(ConversionSpecifier::sArg); +    if (PT->isWideCharType()) +      LM.setKind(LengthModifier::AsWideChar); +    else +      LM.setKind(LengthModifier::None); +    return true; +  } + +  // Figure out the length modifier. +  switch (BT->getKind()) { +    // no modifier +    case BuiltinType::UInt: +    case BuiltinType::Int: +    case BuiltinType::Float: +      LM.setKind(LengthModifier::None); +      break; + +    // hh +    case BuiltinType::Char_U: +    case BuiltinType::UChar: +    case BuiltinType::Char_S: +    case BuiltinType::SChar: +      LM.setKind(LengthModifier::AsChar); +      break; + +    // h +    case BuiltinType::Short: +    case BuiltinType::UShort: +      LM.setKind(LengthModifier::AsShort); +      break; + +    // l +    case BuiltinType::Long: +    case BuiltinType::ULong: +    case BuiltinType::Double: +      LM.setKind(LengthModifier::AsLong); +      break; + +    // ll +    case BuiltinType::LongLong: +    case BuiltinType::ULongLong: +      LM.setKind(LengthModifier::AsLongLong); +      break; + +    // L +    case BuiltinType::LongDouble: +      LM.setKind(LengthModifier::AsLongDouble); +      break; + +    // Don't know. +    default: +      return false; +  } + +  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. +  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) { +    const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier(); +    if (Identifier->getName() == "size_t") { +      LM.setKind(LengthModifier::AsSizeT); +    } else if (Identifier->getName() == "ssize_t") { +      // Not C99, but common in Unix. +      LM.setKind(LengthModifier::AsSizeT); +    } else if (Identifier->getName() == "intmax_t") { +      LM.setKind(LengthModifier::AsIntMax); +    } else if (Identifier->getName() == "uintmax_t") { +      LM.setKind(LengthModifier::AsIntMax); +    } else if (Identifier->getName() == "ptrdiff_t") { +      LM.setKind(LengthModifier::AsPtrDiff); +    } +  } + +  // If fixing the length modifier was enough, we are done. +  const analyze_scanf::ScanfArgTypeResult &ATR = getArgType(Ctx); +  if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT)) +    return true; + +  // Figure out the conversion specifier. +  if (PT->isRealFloatingType()) +    CS.setKind(ConversionSpecifier::fArg); +  else if (PT->isSignedIntegerType()) +    CS.setKind(ConversionSpecifier::dArg); +  else if (PT->isUnsignedIntegerType()) +    CS.setKind(ConversionSpecifier::uArg); +  else +    llvm_unreachable("Unexpected type"); + +  return true; +} + +void ScanfSpecifier::toString(raw_ostream &os) const { +  os << "%"; + +  if (usesPositionalArg()) +    os << getPositionalArgIndex() << "$"; +  if (SuppressAssignment) +    os << "*"; + +  FieldWidth.toString(os); +  os << LM.toString(); +  os << CS.toString(); +} + +bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H, +                                                    const char *I, +                                                    const char *E, +                                                    const LangOptions &LO) { +   +  unsigned argIndex = 0; +   +  // Keep looking for a format specifier until we have exhausted the string. +  while (I != E) { +    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex, +                                                          LO); +    // Did a fail-stop error of any kind occur when parsing the specifier? +    // If so, don't do any more processing. +    if (FSR.shouldStop()) +      return true;; +      // Did we exhaust the string or encounter an error that +      // we can recover from? +    if (!FSR.hasValue()) +      continue; +      // We have a format specifier.  Pass it to the callback. +    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(), +                                I - FSR.getStart())) { +      return true; +    } +  } +  assert(I == E && "Format string not exhausted"); +  return false; +} + +bool ScanfArgTypeResult::matchesType(ASTContext& C, QualType argTy) const { +  switch (K) { +    case InvalidTy: +      llvm_unreachable("ArgTypeResult must be valid"); +    case UnknownTy: +      return true; +    case CStrTy: +      return ArgTypeResult(ArgTypeResult::CStrTy).matchesType(C, argTy); +    case WCStrTy: +      return ArgTypeResult(ArgTypeResult::WCStrTy).matchesType(C, argTy); +    case PtrToArgTypeResultTy: { +      const PointerType *PT = argTy->getAs<PointerType>(); +      if (!PT) +        return false; +      return A.matchesType(C, PT->getPointeeType()); +    } +  } + +  llvm_unreachable("Invalid ScanfArgTypeResult Kind!"); +} + +QualType ScanfArgTypeResult::getRepresentativeType(ASTContext &C) const { +  switch (K) { +    case InvalidTy: +      llvm_unreachable("No representative type for Invalid ArgTypeResult"); +    case UnknownTy: +      return QualType(); +    case CStrTy: +      return C.getPointerType(C.CharTy); +    case WCStrTy: +      return C.getPointerType(C.getWCharType()); +    case PtrToArgTypeResultTy: +      return C.getPointerType(A.getRepresentativeType(C)); +  } + +  llvm_unreachable("Invalid ScanfArgTypeResult Kind!"); +} + +std::string ScanfArgTypeResult::getRepresentativeTypeName(ASTContext& C) const { +  std::string S = getRepresentativeType(C).getAsString(); +  if (!Name) +    return std::string("'") + S + "'"; +  return std::string("'") + Name + "' (aka '" + S + "')"; +} diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp new file mode 100644 index 0000000..2f7e794 --- /dev/null +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -0,0 +1,1726 @@ +//===- ThreadSafety.cpp ----------------------------------------*- C++ --*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A intra-procedural analysis for thread safety (e.g. deadlocks and race +// conditions), based off of an annotation system. +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more +// information. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/ThreadSafety.h" +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <utility> +#include <vector> + +using namespace clang; +using namespace thread_safety; + +// Key method definition +ThreadSafetyHandler::~ThreadSafetyHandler() {} + +namespace { + +/// \brief A MutexID object uniquely identifies a particular mutex, and +/// is built from an Expr* (i.e. calling a lock function). +/// +/// Thread-safety analysis works by comparing lock expressions.  Within the +/// body of a function, an expression such as "x->foo->bar.mu" will resolve to +/// a particular mutex object at run-time.  Subsequent occurrences of the same +/// expression (where "same" means syntactic equality) will refer to the same +/// run-time object if three conditions hold: +/// (1) Local variables in the expression, such as "x" have not changed. +/// (2) Values on the heap that affect the expression have not changed. +/// (3) The expression involves only pure function calls. +/// +/// The current implementation assumes, but does not verify, that multiple uses +/// of the same lock expression satisfies these criteria. +/// +/// Clang introduces an additional wrinkle, which is that it is difficult to +/// derive canonical expressions, or compare expressions directly for equality. +/// Thus, we identify a mutex not by an Expr, but by the list of named +/// declarations that are referenced by the Expr.  In other words, +/// x->foo->bar.mu will be a four element vector with the Decls for +/// mu, bar, and foo, and x.  The vector will uniquely identify the expression +/// for all practical purposes.  Null is used to denote 'this'. +/// +/// Note we will need to perform substitution on "this" and function parameter +/// names when constructing a lock expression. +/// +/// For example: +/// class C { Mutex Mu;  void lock() EXCLUSIVE_LOCK_FUNCTION(this->Mu); }; +/// void myFunc(C *X) { ... X->lock() ... } +/// The original expression for the mutex acquired by myFunc is "this->Mu", but +/// "X" is substituted for "this" so we get X->Mu(); +/// +/// For another example: +/// foo(MyList *L) EXCLUSIVE_LOCKS_REQUIRED(L->Mu) { ... } +/// MyList *MyL; +/// foo(MyL);  // requires lock MyL->Mu to be held +class MutexID { +  SmallVector<NamedDecl*, 2> DeclSeq; + +  /// Build a Decl sequence representing the lock from the given expression. +  /// Recursive function that terminates on DeclRefExpr. +  /// Note: this function merely creates a MutexID; it does not check to +  /// ensure that the original expression is a valid mutex expression. +  void buildMutexID(Expr *Exp, const NamedDecl *D, Expr *Parent, +                    unsigned NumArgs, Expr **FunArgs) { +    if (!Exp) { +      DeclSeq.clear(); +      return; +    } + +    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) { +      NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); +      ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND); +      if (PV) { +        FunctionDecl *FD = +          cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl(); +        unsigned i = PV->getFunctionScopeIndex(); + +        if (FunArgs && FD == D->getCanonicalDecl()) { +          // Substitute call arguments for references to function parameters +          assert(i < NumArgs); +          buildMutexID(FunArgs[i], D, 0, 0, 0); +          return; +        } +        // Map the param back to the param of the original function declaration. +        DeclSeq.push_back(FD->getParamDecl(i)); +        return; +      } +      // Not a function parameter -- just store the reference. +      DeclSeq.push_back(ND); +    } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { +      NamedDecl *ND = ME->getMemberDecl(); +      DeclSeq.push_back(ND); +      buildMutexID(ME->getBase(), D, Parent, NumArgs, FunArgs); +    } else if (isa<CXXThisExpr>(Exp)) { +      if (Parent) +        buildMutexID(Parent, D, 0, 0, 0); +      else { +        DeclSeq.push_back(0);  // Use 0 to represent 'this'. +        return;  // mutexID is still valid in this case +      } +    } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) { +      DeclSeq.push_back(CMCE->getMethodDecl()->getCanonicalDecl()); +      buildMutexID(CMCE->getImplicitObjectArgument(), +                   D, Parent, NumArgs, FunArgs); +      unsigned NumCallArgs = CMCE->getNumArgs(); +      Expr** CallArgs = CMCE->getArgs(); +      for (unsigned i = 0; i < NumCallArgs; ++i) { +        buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs); +      } +    } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) { +      buildMutexID(CE->getCallee(), D, Parent, NumArgs, FunArgs); +      unsigned NumCallArgs = CE->getNumArgs(); +      Expr** CallArgs = CE->getArgs(); +      for (unsigned i = 0; i < NumCallArgs; ++i) { +        buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs); +      } +    } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) { +      buildMutexID(BOE->getLHS(), D, Parent, NumArgs, FunArgs); +      buildMutexID(BOE->getRHS(), D, Parent, NumArgs, FunArgs); +    } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) { +      buildMutexID(UOE->getSubExpr(), D, Parent, NumArgs, FunArgs); +    } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) { +      buildMutexID(ASE->getBase(), D, Parent, NumArgs, FunArgs); +      buildMutexID(ASE->getIdx(), D, Parent, NumArgs, FunArgs); +    } else if (AbstractConditionalOperator *CE = +                 dyn_cast<AbstractConditionalOperator>(Exp)) { +      buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs); +      buildMutexID(CE->getTrueExpr(), D, Parent, NumArgs, FunArgs); +      buildMutexID(CE->getFalseExpr(), D, Parent, NumArgs, FunArgs); +    } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) { +      buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs); +      buildMutexID(CE->getLHS(), D, Parent, NumArgs, FunArgs); +      buildMutexID(CE->getRHS(), D, Parent, NumArgs, FunArgs); +    } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) { +      buildMutexID(CE->getSubExpr(), D, Parent, NumArgs, FunArgs); +    } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) { +      buildMutexID(PE->getSubExpr(), D, Parent, NumArgs, FunArgs); +    } else if (isa<CharacterLiteral>(Exp) || +             isa<CXXNullPtrLiteralExpr>(Exp) || +             isa<GNUNullExpr>(Exp) || +             isa<CXXBoolLiteralExpr>(Exp) || +             isa<FloatingLiteral>(Exp) || +             isa<ImaginaryLiteral>(Exp) || +             isa<IntegerLiteral>(Exp) || +             isa<StringLiteral>(Exp) || +             isa<ObjCStringLiteral>(Exp)) { +      return;  // FIXME: Ignore literals for now +    } else { +      // Ignore.  FIXME: mark as invalid expression? +    } +  } + +  /// \brief Construct a MutexID from an expression. +  /// \param MutexExp The original mutex expression within an attribute +  /// \param DeclExp An expression involving the Decl on which the attribute +  ///        occurs. +  /// \param D  The declaration to which the lock/unlock attribute is attached. +  void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) { +    Expr *Parent = 0; +    unsigned NumArgs = 0; +    Expr **FunArgs = 0; + +    // If we are processing a raw attribute expression, with no substitutions. +    if (DeclExp == 0) { +      buildMutexID(MutexExp, D, 0, 0, 0); +      return; +    } + +    // Examine DeclExp to find Parent and FunArgs, which are used to substitute +    // for formal parameters when we call buildMutexID later. +    if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) { +      Parent = ME->getBase(); +    } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) { +      Parent = CE->getImplicitObjectArgument(); +      NumArgs = CE->getNumArgs(); +      FunArgs = CE->getArgs(); +    } else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) { +      NumArgs = CE->getNumArgs(); +      FunArgs = CE->getArgs(); +    } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) { +      Parent = 0;  // FIXME -- get the parent from DeclStmt +      NumArgs = CE->getNumArgs(); +      FunArgs = CE->getArgs(); +    } else if (D && isa<CXXDestructorDecl>(D)) { +      // There's no such thing as a "destructor call" in the AST. +      Parent = DeclExp; +    } + +    // If the attribute has no arguments, then assume the argument is "this". +    if (MutexExp == 0) { +      buildMutexID(Parent, D, 0, 0, 0); +      return; +    } + +    buildMutexID(MutexExp, D, Parent, NumArgs, FunArgs); +  } + +public: +  explicit MutexID(clang::Decl::EmptyShell e) { +    DeclSeq.clear(); +  } + +  /// \param MutexExp The original mutex expression within an attribute +  /// \param DeclExp An expression involving the Decl on which the attribute +  ///        occurs. +  /// \param D  The declaration to which the lock/unlock attribute is attached. +  /// Caller must check isValid() after construction. +  MutexID(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) { +    buildMutexIDFromExp(MutexExp, DeclExp, D); +  } + +  /// Return true if this is a valid decl sequence. +  /// Caller must call this by hand after construction to handle errors. +  bool isValid() const { +    return !DeclSeq.empty(); +  } + +  /// Issue a warning about an invalid lock expression +  static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp, +                              Expr *DeclExp, const NamedDecl* D) { +    SourceLocation Loc; +    if (DeclExp) +      Loc = DeclExp->getExprLoc(); + +    // FIXME: add a note about the attribute location in MutexExp or D +    if (Loc.isValid()) +      Handler.handleInvalidLockExp(Loc); +  } + +  bool operator==(const MutexID &other) const { +    return DeclSeq == other.DeclSeq; +  } + +  bool operator!=(const MutexID &other) const { +    return !(*this == other); +  } + +  // SmallVector overloads Operator< to do lexicographic ordering. Note that +  // we use pointer equality (and <) to compare NamedDecls. This means the order +  // of MutexIDs in a lockset is nondeterministic. In order to output +  // diagnostics in a deterministic ordering, we must order all diagnostics to +  // output by SourceLocation when iterating through this lockset. +  bool operator<(const MutexID &other) const { +    return DeclSeq < other.DeclSeq; +  } + +  /// \brief Returns the name of the first Decl in the list for a given MutexID; +  /// e.g. the lock expression foo.bar() has name "bar". +  /// The caret will point unambiguously to the lock expression, so using this +  /// name in diagnostics is a way to get simple, and consistent, mutex names. +  /// We do not want to output the entire expression text for security reasons. +  std::string getName() const { +    assert(isValid()); +    if (!DeclSeq.front()) +      return "this";  // Use 0 to represent 'this'. +    return DeclSeq.front()->getNameAsString(); +  } + +  void Profile(llvm::FoldingSetNodeID &ID) const { +    for (SmallVectorImpl<NamedDecl*>::const_iterator I = DeclSeq.begin(), +         E = DeclSeq.end(); I != E; ++I) { +      ID.AddPointer(*I); +    } +  } +}; + + +/// \brief This is a helper class that stores info about the most recent +/// accquire of a Lock. +/// +/// The main body of the analysis maps MutexIDs to LockDatas. +struct LockData { +  SourceLocation AcquireLoc; + +  /// \brief LKind stores whether a lock is held shared or exclusively. +  /// Note that this analysis does not currently support either re-entrant +  /// locking or lock "upgrading" and "downgrading" between exclusive and +  /// shared. +  /// +  /// FIXME: add support for re-entrant locking and lock up/downgrading +  LockKind LKind; +  MutexID UnderlyingMutex;  // for ScopedLockable objects + +  LockData(SourceLocation AcquireLoc, LockKind LKind) +    : AcquireLoc(AcquireLoc), LKind(LKind), UnderlyingMutex(Decl::EmptyShell()) +  {} + +  LockData(SourceLocation AcquireLoc, LockKind LKind, const MutexID &Mu) +    : AcquireLoc(AcquireLoc), LKind(LKind), UnderlyingMutex(Mu) {} + +  bool operator==(const LockData &other) const { +    return AcquireLoc == other.AcquireLoc && LKind == other.LKind; +  } + +  bool operator!=(const LockData &other) const { +    return !(*this == other); +  } + +  void Profile(llvm::FoldingSetNodeID &ID) const { +    ID.AddInteger(AcquireLoc.getRawEncoding()); +    ID.AddInteger(LKind); +  } +}; + + +/// A Lockset maps each MutexID (defined above) to information about how it has +/// been locked. +typedef llvm::ImmutableMap<MutexID, LockData> Lockset; +typedef llvm::ImmutableMap<NamedDecl*, unsigned> LocalVarContext; + +class LocalVariableMap; + +/// A side (entry or exit) of a CFG node. +enum CFGBlockSide { CBS_Entry, CBS_Exit }; + +/// CFGBlockInfo is a struct which contains all the information that is +/// maintained for each block in the CFG.  See LocalVariableMap for more +/// information about the contexts. +struct CFGBlockInfo { +  Lockset EntrySet;             // Lockset held at entry to block +  Lockset ExitSet;              // Lockset held at exit from block +  LocalVarContext EntryContext; // Context held at entry to block +  LocalVarContext ExitContext;  // Context held at exit from block +  SourceLocation EntryLoc;      // Location of first statement in block +  SourceLocation ExitLoc;       // Location of last statement in block. +  unsigned EntryIndex;          // Used to replay contexts later + +  const Lockset &getSet(CFGBlockSide Side) const { +    return Side == CBS_Entry ? EntrySet : ExitSet; +  } +  SourceLocation getLocation(CFGBlockSide Side) const { +    return Side == CBS_Entry ? EntryLoc : ExitLoc; +  } + +private: +  CFGBlockInfo(Lockset EmptySet, LocalVarContext EmptyCtx) +    : EntrySet(EmptySet), ExitSet(EmptySet), +      EntryContext(EmptyCtx), ExitContext(EmptyCtx) +  { } + +public: +  static CFGBlockInfo getEmptyBlockInfo(Lockset::Factory &F, +                                        LocalVariableMap &M); +}; + + + +// A LocalVariableMap maintains a map from local variables to their currently +// valid definitions.  It provides SSA-like functionality when traversing the +// CFG.  Like SSA, each definition or assignment to a variable is assigned a +// unique name (an integer), which acts as the SSA name for that definition. +// The total set of names is shared among all CFG basic blocks. +// Unlike SSA, we do not rewrite expressions to replace local variables declrefs +// with their SSA-names.  Instead, we compute a Context for each point in the +// code, which maps local variables to the appropriate SSA-name.  This map +// changes with each assignment. +// +// The map is computed in a single pass over the CFG.  Subsequent analyses can +// then query the map to find the appropriate Context for a statement, and use +// that Context to look up the definitions of variables. +class LocalVariableMap { +public: +  typedef LocalVarContext Context; + +  /// A VarDefinition consists of an expression, representing the value of the +  /// variable, along with the context in which that expression should be +  /// interpreted.  A reference VarDefinition does not itself contain this +  /// information, but instead contains a pointer to a previous VarDefinition. +  struct VarDefinition { +  public: +    friend class LocalVariableMap; + +    NamedDecl *Dec;       // The original declaration for this variable. +    Expr *Exp;            // The expression for this variable, OR +    unsigned Ref;         // Reference to another VarDefinition +    Context Ctx;          // The map with which Exp should be interpreted. + +    bool isReference() { return !Exp; } + +  private: +    // Create ordinary variable definition +    VarDefinition(NamedDecl *D, Expr *E, Context C) +      : Dec(D), Exp(E), Ref(0), Ctx(C) +    { } + +    // Create reference to previous definition +    VarDefinition(NamedDecl *D, unsigned R, Context C) +      : Dec(D), Exp(0), Ref(R), Ctx(C) +    { } +  }; + +private: +  Context::Factory ContextFactory; +  std::vector<VarDefinition> VarDefinitions; +  std::vector<unsigned> CtxIndices; +  std::vector<std::pair<Stmt*, Context> > SavedContexts; + +public: +  LocalVariableMap() { +    // index 0 is a placeholder for undefined variables (aka phi-nodes). +    VarDefinitions.push_back(VarDefinition(0, 0u, getEmptyContext())); +  } + +  /// Look up a definition, within the given context. +  const VarDefinition* lookup(NamedDecl *D, Context Ctx) { +    const unsigned *i = Ctx.lookup(D); +    if (!i) +      return 0; +    assert(*i < VarDefinitions.size()); +    return &VarDefinitions[*i]; +  } + +  /// Look up the definition for D within the given context.  Returns +  /// NULL if the expression is not statically known.  If successful, also +  /// modifies Ctx to hold the context of the return Expr. +  Expr* lookupExpr(NamedDecl *D, Context &Ctx) { +    const unsigned *P = Ctx.lookup(D); +    if (!P) +      return 0; + +    unsigned i = *P; +    while (i > 0) { +      if (VarDefinitions[i].Exp) { +        Ctx = VarDefinitions[i].Ctx; +        return VarDefinitions[i].Exp; +      } +      i = VarDefinitions[i].Ref; +    } +    return 0; +  } + +  Context getEmptyContext() { return ContextFactory.getEmptyMap(); } + +  /// Return the next context after processing S.  This function is used by +  /// clients of the class to get the appropriate context when traversing the +  /// CFG.  It must be called for every assignment or DeclStmt. +  Context getNextContext(unsigned &CtxIndex, Stmt *S, Context C) { +    if (SavedContexts[CtxIndex+1].first == S) { +      CtxIndex++; +      Context Result = SavedContexts[CtxIndex].second; +      return Result; +    } +    return C; +  } + +  void dumpVarDefinitionName(unsigned i) { +    if (i == 0) { +      llvm::errs() << "Undefined"; +      return; +    } +    NamedDecl *Dec = VarDefinitions[i].Dec; +    if (!Dec) { +      llvm::errs() << "<<NULL>>"; +      return; +    } +    Dec->printName(llvm::errs()); +    llvm::errs() << "." << i << " " << ((void*) Dec); +  } + +  /// Dumps an ASCII representation of the variable map to llvm::errs() +  void dump() { +    for (unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) { +      Expr *Exp = VarDefinitions[i].Exp; +      unsigned Ref = VarDefinitions[i].Ref; + +      dumpVarDefinitionName(i); +      llvm::errs() << " = "; +      if (Exp) Exp->dump(); +      else { +        dumpVarDefinitionName(Ref); +        llvm::errs() << "\n"; +      } +    } +  } + +  /// Dumps an ASCII representation of a Context to llvm::errs() +  void dumpContext(Context C) { +    for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) { +      NamedDecl *D = I.getKey(); +      D->printName(llvm::errs()); +      const unsigned *i = C.lookup(D); +      llvm::errs() << " -> "; +      dumpVarDefinitionName(*i); +      llvm::errs() << "\n"; +    } +  } + +  /// Builds the variable map. +  void traverseCFG(CFG *CFGraph, PostOrderCFGView *SortedGraph, +                     std::vector<CFGBlockInfo> &BlockInfo); + +protected: +  // Get the current context index +  unsigned getContextIndex() { return SavedContexts.size()-1; } + +  // Save the current context for later replay +  void saveContext(Stmt *S, Context C) { +    SavedContexts.push_back(std::make_pair(S,C)); +  } + +  // Adds a new definition to the given context, and returns a new context. +  // This method should be called when declaring a new variable. +  Context addDefinition(NamedDecl *D, Expr *Exp, Context Ctx) { +    assert(!Ctx.contains(D)); +    unsigned newID = VarDefinitions.size(); +    Context NewCtx = ContextFactory.add(Ctx, D, newID); +    VarDefinitions.push_back(VarDefinition(D, Exp, Ctx)); +    return NewCtx; +  } + +  // Add a new reference to an existing definition. +  Context addReference(NamedDecl *D, unsigned i, Context Ctx) { +    unsigned newID = VarDefinitions.size(); +    Context NewCtx = ContextFactory.add(Ctx, D, newID); +    VarDefinitions.push_back(VarDefinition(D, i, Ctx)); +    return NewCtx; +  } + +  // Updates a definition only if that definition is already in the map. +  // This method should be called when assigning to an existing variable. +  Context updateDefinition(NamedDecl *D, Expr *Exp, Context Ctx) { +    if (Ctx.contains(D)) { +      unsigned newID = VarDefinitions.size(); +      Context NewCtx = ContextFactory.remove(Ctx, D); +      NewCtx = ContextFactory.add(NewCtx, D, newID); +      VarDefinitions.push_back(VarDefinition(D, Exp, Ctx)); +      return NewCtx; +    } +    return Ctx; +  } + +  // Removes a definition from the context, but keeps the variable name +  // as a valid variable.  The index 0 is a placeholder for cleared definitions. +  Context clearDefinition(NamedDecl *D, Context Ctx) { +    Context NewCtx = Ctx; +    if (NewCtx.contains(D)) { +      NewCtx = ContextFactory.remove(NewCtx, D); +      NewCtx = ContextFactory.add(NewCtx, D, 0); +    } +    return NewCtx; +  } + +  // Remove a definition entirely frmo the context. +  Context removeDefinition(NamedDecl *D, Context Ctx) { +    Context NewCtx = Ctx; +    if (NewCtx.contains(D)) { +      NewCtx = ContextFactory.remove(NewCtx, D); +    } +    return NewCtx; +  } + +  Context intersectContexts(Context C1, Context C2); +  Context createReferenceContext(Context C); +  void intersectBackEdge(Context C1, Context C2); + +  friend class VarMapBuilder; +}; + + +// This has to be defined after LocalVariableMap. +CFGBlockInfo CFGBlockInfo::getEmptyBlockInfo(Lockset::Factory &F, +                                             LocalVariableMap &M) { +  return CFGBlockInfo(F.getEmptyMap(), M.getEmptyContext()); +} + + +/// Visitor which builds a LocalVariableMap +class VarMapBuilder : public StmtVisitor<VarMapBuilder> { +public: +  LocalVariableMap* VMap; +  LocalVariableMap::Context Ctx; + +  VarMapBuilder(LocalVariableMap *VM, LocalVariableMap::Context C) +    : VMap(VM), Ctx(C) {} + +  void VisitDeclStmt(DeclStmt *S); +  void VisitBinaryOperator(BinaryOperator *BO); +}; + + +// Add new local variables to the variable map +void VarMapBuilder::VisitDeclStmt(DeclStmt *S) { +  bool modifiedCtx = false; +  DeclGroupRef DGrp = S->getDeclGroup(); +  for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) { +    if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) { +      Expr *E = VD->getInit(); + +      // Add local variables with trivial type to the variable map +      QualType T = VD->getType(); +      if (T.isTrivialType(VD->getASTContext())) { +        Ctx = VMap->addDefinition(VD, E, Ctx); +        modifiedCtx = true; +      } +    } +  } +  if (modifiedCtx) +    VMap->saveContext(S, Ctx); +} + +// Update local variable definitions in variable map +void VarMapBuilder::VisitBinaryOperator(BinaryOperator *BO) { +  if (!BO->isAssignmentOp()) +    return; + +  Expr *LHSExp = BO->getLHS()->IgnoreParenCasts(); + +  // Update the variable map and current context. +  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHSExp)) { +    ValueDecl *VDec = DRE->getDecl(); +    if (Ctx.lookup(VDec)) { +      if (BO->getOpcode() == BO_Assign) +        Ctx = VMap->updateDefinition(VDec, BO->getRHS(), Ctx); +      else +        // FIXME -- handle compound assignment operators +        Ctx = VMap->clearDefinition(VDec, Ctx); +      VMap->saveContext(BO, Ctx); +    } +  } +} + + +// Computes the intersection of two contexts.  The intersection is the +// set of variables which have the same definition in both contexts; +// variables with different definitions are discarded. +LocalVariableMap::Context +LocalVariableMap::intersectContexts(Context C1, Context C2) { +  Context Result = C1; +  for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) { +    NamedDecl *Dec = I.getKey(); +    unsigned i1 = I.getData(); +    const unsigned *i2 = C2.lookup(Dec); +    if (!i2)             // variable doesn't exist on second path +      Result = removeDefinition(Dec, Result); +    else if (*i2 != i1)  // variable exists, but has different definition +      Result = clearDefinition(Dec, Result); +  } +  return Result; +} + +// For every variable in C, create a new variable that refers to the +// definition in C.  Return a new context that contains these new variables. +// (We use this for a naive implementation of SSA on loop back-edges.) +LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) { +  Context Result = getEmptyContext(); +  for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) { +    NamedDecl *Dec = I.getKey(); +    unsigned i = I.getData(); +    Result = addReference(Dec, i, Result); +  } +  return Result; +} + +// This routine also takes the intersection of C1 and C2, but it does so by +// altering the VarDefinitions.  C1 must be the result of an earlier call to +// createReferenceContext. +void LocalVariableMap::intersectBackEdge(Context C1, Context C2) { +  for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) { +    NamedDecl *Dec = I.getKey(); +    unsigned i1 = I.getData(); +    VarDefinition *VDef = &VarDefinitions[i1]; +    assert(VDef->isReference()); + +    const unsigned *i2 = C2.lookup(Dec); +    if (!i2 || (*i2 != i1)) +      VDef->Ref = 0;    // Mark this variable as undefined +  } +} + + +// Traverse the CFG in topological order, so all predecessors of a block +// (excluding back-edges) are visited before the block itself.  At +// each point in the code, we calculate a Context, which holds the set of +// variable definitions which are visible at that point in execution. +// Visible variables are mapped to their definitions using an array that +// contains all definitions. +// +// At join points in the CFG, the set is computed as the intersection of +// the incoming sets along each edge, E.g. +// +//                       { Context                 | VarDefinitions } +//   int x = 0;          { x -> x1                 | x1 = 0 } +//   int y = 0;          { x -> x1, y -> y1        | y1 = 0, x1 = 0 } +//   if (b) x = 1;       { x -> x2, y -> y1        | x2 = 1, y1 = 0, ... } +//   else   x = 2;       { x -> x3, y -> y1        | x3 = 2, x2 = 1, ... } +//   ...                 { y -> y1  (x is unknown) | x3 = 2, x2 = 1, ... } +// +// This is essentially a simpler and more naive version of the standard SSA +// algorithm.  Those definitions that remain in the intersection are from blocks +// that strictly dominate the current block.  We do not bother to insert proper +// phi nodes, because they are not used in our analysis; instead, wherever +// a phi node would be required, we simply remove that definition from the +// context (E.g. x above). +// +// The initial traversal does not capture back-edges, so those need to be +// handled on a separate pass.  Whenever the first pass encounters an +// incoming back edge, it duplicates the context, creating new definitions +// that refer back to the originals.  (These correspond to places where SSA +// might have to insert a phi node.)  On the second pass, these definitions are +// set to NULL if the the variable has changed on the back-edge (i.e. a phi +// node was actually required.)  E.g. +// +//                       { Context           | VarDefinitions } +//   int x = 0, y = 0;   { x -> x1, y -> y1  | y1 = 0, x1 = 0 } +//   while (b)           { x -> x2, y -> y1  | [1st:] x2=x1; [2nd:] x2=NULL; } +//     x = x+1;          { x -> x3, y -> y1  | x3 = x2 + 1, ... } +//   ...                 { y -> y1           | x3 = 2, x2 = 1, ... } +// +void LocalVariableMap::traverseCFG(CFG *CFGraph, +                                   PostOrderCFGView *SortedGraph, +                                   std::vector<CFGBlockInfo> &BlockInfo) { +  PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph); + +  CtxIndices.resize(CFGraph->getNumBlockIDs()); + +  for (PostOrderCFGView::iterator I = SortedGraph->begin(), +       E = SortedGraph->end(); I!= E; ++I) { +    const CFGBlock *CurrBlock = *I; +    int CurrBlockID = CurrBlock->getBlockID(); +    CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID]; + +    VisitedBlocks.insert(CurrBlock); + +    // Calculate the entry context for the current block +    bool HasBackEdges = false; +    bool CtxInit = true; +    for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(), +         PE  = CurrBlock->pred_end(); PI != PE; ++PI) { +      // if *PI -> CurrBlock is a back edge, so skip it +      if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) { +        HasBackEdges = true; +        continue; +      } + +      int PrevBlockID = (*PI)->getBlockID(); +      CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; + +      if (CtxInit) { +        CurrBlockInfo->EntryContext = PrevBlockInfo->ExitContext; +        CtxInit = false; +      } +      else { +        CurrBlockInfo->EntryContext = +          intersectContexts(CurrBlockInfo->EntryContext, +                            PrevBlockInfo->ExitContext); +      } +    } + +    // Duplicate the context if we have back-edges, so we can call +    // intersectBackEdges later. +    if (HasBackEdges) +      CurrBlockInfo->EntryContext = +        createReferenceContext(CurrBlockInfo->EntryContext); + +    // Create a starting context index for the current block +    saveContext(0, CurrBlockInfo->EntryContext); +    CurrBlockInfo->EntryIndex = getContextIndex(); + +    // Visit all the statements in the basic block. +    VarMapBuilder VMapBuilder(this, CurrBlockInfo->EntryContext); +    for (CFGBlock::const_iterator BI = CurrBlock->begin(), +         BE = CurrBlock->end(); BI != BE; ++BI) { +      switch (BI->getKind()) { +        case CFGElement::Statement: { +          const CFGStmt *CS = cast<CFGStmt>(&*BI); +          VMapBuilder.Visit(const_cast<Stmt*>(CS->getStmt())); +          break; +        } +        default: +          break; +      } +    } +    CurrBlockInfo->ExitContext = VMapBuilder.Ctx; + +    // Mark variables on back edges as "unknown" if they've been changed. +    for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), +         SE  = CurrBlock->succ_end(); SI != SE; ++SI) { +      // if CurrBlock -> *SI is *not* a back edge +      if (*SI == 0 || !VisitedBlocks.alreadySet(*SI)) +        continue; + +      CFGBlock *FirstLoopBlock = *SI; +      Context LoopBegin = BlockInfo[FirstLoopBlock->getBlockID()].EntryContext; +      Context LoopEnd   = CurrBlockInfo->ExitContext; +      intersectBackEdge(LoopBegin, LoopEnd); +    } +  } + +  // Put an extra entry at the end of the indexed context array +  unsigned exitID = CFGraph->getExit().getBlockID(); +  saveContext(0, BlockInfo[exitID].ExitContext); +} + +/// Find the appropriate source locations to use when producing diagnostics for +/// each block in the CFG. +static void findBlockLocations(CFG *CFGraph, +                               PostOrderCFGView *SortedGraph, +                               std::vector<CFGBlockInfo> &BlockInfo) { +  for (PostOrderCFGView::iterator I = SortedGraph->begin(), +       E = SortedGraph->end(); I!= E; ++I) { +    const CFGBlock *CurrBlock = *I; +    CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()]; + +    // Find the source location of the last statement in the block, if the +    // block is not empty. +    if (const Stmt *S = CurrBlock->getTerminator()) { +      CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->getLocStart(); +    } else { +      for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(), +           BE = CurrBlock->rend(); BI != BE; ++BI) { +        // FIXME: Handle other CFGElement kinds. +        if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) { +          CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart(); +          break; +        } +      } +    } + +    if (!CurrBlockInfo->ExitLoc.isInvalid()) { +      // This block contains at least one statement. Find the source location +      // of the first statement in the block. +      for (CFGBlock::const_iterator BI = CurrBlock->begin(), +           BE = CurrBlock->end(); BI != BE; ++BI) { +        // FIXME: Handle other CFGElement kinds. +        if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) { +          CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart(); +          break; +        } +      } +    } else if (CurrBlock->pred_size() == 1 && *CurrBlock->pred_begin() && +               CurrBlock != &CFGraph->getExit()) { +      // The block is empty, and has a single predecessor. Use its exit +      // location. +      CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = +          BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc; +    } +  } +} + +/// \brief Class which implements the core thread safety analysis routines. +class ThreadSafetyAnalyzer { +  friend class BuildLockset; + +  ThreadSafetyHandler &Handler; +  Lockset::Factory    LocksetFactory; +  LocalVariableMap    LocalVarMap; + +public: +  ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {} + +  Lockset intersectAndWarn(const CFGBlockInfo &Block1, CFGBlockSide Side1, +                           const CFGBlockInfo &Block2, CFGBlockSide Side2, +                           LockErrorKind LEK); + +  Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D, +                  LockKind LK, SourceLocation Loc); + +  void runAnalysis(AnalysisDeclContext &AC); +}; + + +/// \brief We use this class to visit different types of expressions in +/// CFGBlocks, and build up the lockset. +/// An expression may cause us to add or remove locks from the lockset, or else +/// output error messages related to missing locks. +/// FIXME: In future, we may be able to not inherit from a visitor. +class BuildLockset : public StmtVisitor<BuildLockset> { +  friend class ThreadSafetyAnalyzer; + +  ThreadSafetyHandler &Handler; +  Lockset::Factory &LocksetFactory; +  LocalVariableMap &LocalVarMap; + +  Lockset LSet; +  LocalVariableMap::Context LVarCtx; +  unsigned CtxIndex; + +  // Helper functions +  void addLock(const MutexID &Mutex, const LockData &LDat); +  void removeLock(const MutexID &Mutex, SourceLocation UnlockLoc); + +  template <class AttrType> +  void addLocksToSet(LockKind LK, AttrType *Attr, +                     Expr *Exp, NamedDecl *D, VarDecl *VD = 0); +  void removeLocksFromSet(UnlockFunctionAttr *Attr, +                          Expr *Exp, NamedDecl* FunDecl); + +  const ValueDecl *getValueDecl(Expr *Exp); +  void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK, +                           Expr *MutexExp, ProtectedOperationKind POK); +  void checkAccess(Expr *Exp, AccessKind AK); +  void checkDereference(Expr *Exp, AccessKind AK); +  void handleCall(Expr *Exp, NamedDecl *D, VarDecl *VD = 0); + +  template <class AttrType> +  void addTrylock(LockKind LK, AttrType *Attr, Expr *Exp, NamedDecl *FunDecl, +                  const CFGBlock* PredBlock, const CFGBlock *CurrBlock, +                  Expr *BrE, bool Neg); +  CallExpr* getTrylockCallExpr(Stmt *Cond, LocalVariableMap::Context C, +                               bool &Negate); +  void handleTrylock(Stmt *Cond, const CFGBlock* PredBlock, +                     const CFGBlock *CurrBlock); + +  /// \brief Returns true if the lockset contains a lock, regardless of whether +  /// the lock is held exclusively or shared. +  bool locksetContains(const MutexID &Lock) const { +    return LSet.lookup(Lock); +  } + +  /// \brief Returns true if the lockset contains a lock with the passed in +  /// locktype. +  bool locksetContains(const MutexID &Lock, LockKind KindRequested) const { +    const LockData *LockHeld = LSet.lookup(Lock); +    return (LockHeld && KindRequested == LockHeld->LKind); +  } + +  /// \brief Returns true if the lockset contains a lock with at least the +  /// passed in locktype. So for example, if we pass in LK_Shared, this function +  /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in +  /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive. +  bool locksetContainsAtLeast(const MutexID &Lock, +                              LockKind KindRequested) const { +    switch (KindRequested) { +      case LK_Shared: +        return locksetContains(Lock); +      case LK_Exclusive: +        return locksetContains(Lock, KindRequested); +    } +    llvm_unreachable("Unknown LockKind"); +  } + +public: +  BuildLockset(ThreadSafetyAnalyzer *analyzer, CFGBlockInfo &Info) +    : StmtVisitor<BuildLockset>(), +      Handler(analyzer->Handler), +      LocksetFactory(analyzer->LocksetFactory), +      LocalVarMap(analyzer->LocalVarMap), +      LSet(Info.EntrySet), +      LVarCtx(Info.EntryContext), +      CtxIndex(Info.EntryIndex) +  {} + +  void VisitUnaryOperator(UnaryOperator *UO); +  void VisitBinaryOperator(BinaryOperator *BO); +  void VisitCastExpr(CastExpr *CE); +  void VisitCallExpr(CallExpr *Exp); +  void VisitCXXConstructExpr(CXXConstructExpr *Exp); +  void VisitDeclStmt(DeclStmt *S); +}; + +/// \brief Add a new lock to the lockset, warning if the lock is already there. +/// \param Mutex -- the Mutex expression for the lock +/// \param LDat  -- the LockData for the lock +void BuildLockset::addLock(const MutexID &Mutex, const LockData& LDat) { +  // FIXME: deal with acquired before/after annotations. +  // FIXME: Don't always warn when we have support for reentrant locks. +  if (locksetContains(Mutex)) +    Handler.handleDoubleLock(Mutex.getName(), LDat.AcquireLoc); +  else +    LSet = LocksetFactory.add(LSet, Mutex, LDat); +} + +/// \brief Remove a lock from the lockset, warning if the lock is not there. +/// \param LockExp The lock expression corresponding to the lock to be removed +/// \param UnlockLoc The source location of the unlock (only used in error msg) +void BuildLockset::removeLock(const MutexID &Mutex, SourceLocation UnlockLoc) { +  const LockData *LDat = LSet.lookup(Mutex); +  if (!LDat) +    Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc); +  else { +    // For scoped-lockable vars, remove the mutex associated with this var. +    if (LDat->UnderlyingMutex.isValid()) +      removeLock(LDat->UnderlyingMutex, UnlockLoc); +    LSet = LocksetFactory.remove(LSet, Mutex); +  } +} + +/// \brief This function, parameterized by an attribute type, is used to add a +/// set of locks specified as attribute arguments to the lockset. +template <typename AttrType> +void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr, +                                 Expr *Exp, NamedDecl* FunDecl, VarDecl *VD) { +  typedef typename AttrType::args_iterator iterator_type; + +  SourceLocation ExpLocation = Exp->getExprLoc(); + +  // Figure out if we're calling the constructor of scoped lockable class +  bool isScopedVar = false; +  if (VD) { +    if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FunDecl)) { +      CXXRecordDecl* PD = CD->getParent(); +      if (PD && PD->getAttr<ScopedLockableAttr>()) +        isScopedVar = true; +    } +  } + +  if (Attr->args_size() == 0) { +    // The mutex held is the "this" object. +    MutexID Mutex(0, Exp, FunDecl); +    if (!Mutex.isValid()) +      MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl); +    else +      addLock(Mutex, LockData(ExpLocation, LK)); +    return; +  } + +  for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) { +    MutexID Mutex(*I, Exp, FunDecl); +    if (!Mutex.isValid()) +      MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl); +    else { +      addLock(Mutex, LockData(ExpLocation, LK)); +      if (isScopedVar) { +        // For scoped lockable vars, map this var to its underlying mutex. +        DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation()); +        MutexID SMutex(&DRE, 0, 0); +        addLock(SMutex, LockData(VD->getLocation(), LK, Mutex)); +      } +    } +  } +} + +/// \brief This function removes a set of locks specified as attribute +/// arguments from the lockset. +void BuildLockset::removeLocksFromSet(UnlockFunctionAttr *Attr, +                                      Expr *Exp, NamedDecl* FunDecl) { +  SourceLocation ExpLocation; +  if (Exp) ExpLocation = Exp->getExprLoc(); + +  if (Attr->args_size() == 0) { +    // The mutex held is the "this" object. +    MutexID Mu(0, Exp, FunDecl); +    if (!Mu.isValid()) +      MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl); +    else +      removeLock(Mu, ExpLocation); +    return; +  } + +  for (UnlockFunctionAttr::args_iterator I = Attr->args_begin(), +       E = Attr->args_end(); I != E; ++I) { +    MutexID Mutex(*I, Exp, FunDecl); +    if (!Mutex.isValid()) +      MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl); +    else +      removeLock(Mutex, ExpLocation); +  } +} + +/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs +const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) { +  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp)) +    return DR->getDecl(); + +  if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) +    return ME->getMemberDecl(); + +  return 0; +} + +/// \brief Warn if the LSet does not contain a lock sufficient to protect access +/// of at least the passed in AccessKind. +void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, +                                      AccessKind AK, Expr *MutexExp, +                                      ProtectedOperationKind POK) { +  LockKind LK = getLockKindFromAccessKind(AK); + +  MutexID Mutex(MutexExp, Exp, D); +  if (!Mutex.isValid()) +    MutexID::warnInvalidLock(Handler, MutexExp, Exp, D); +  else if (!locksetContainsAtLeast(Mutex, LK)) +    Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc()); +} + +/// \brief This method identifies variable dereferences and checks pt_guarded_by +/// and pt_guarded_var annotations. Note that we only check these annotations +/// at the time a pointer is dereferenced. +/// FIXME: We need to check for other types of pointer dereferences +/// (e.g. [], ->) and deal with them here. +/// \param Exp An expression that has been read or written. +void BuildLockset::checkDereference(Expr *Exp, AccessKind AK) { +  UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp); +  if (!UO || UO->getOpcode() != clang::UO_Deref) +    return; +  Exp = UO->getSubExpr()->IgnoreParenCasts(); + +  const ValueDecl *D = getValueDecl(Exp); +  if(!D || !D->hasAttrs()) +    return; + +  if (D->getAttr<PtGuardedVarAttr>() && LSet.isEmpty()) +    Handler.handleNoMutexHeld(D, POK_VarDereference, AK, Exp->getExprLoc()); + +  const AttrVec &ArgAttrs = D->getAttrs(); +  for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) +    if (PtGuardedByAttr *PGBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i])) +      warnIfMutexNotHeld(D, Exp, AK, PGBAttr->getArg(), POK_VarDereference); +} + +/// \brief Checks guarded_by and guarded_var attributes. +/// Whenever we identify an access (read or write) of a DeclRefExpr or +/// MemberExpr, we need to check whether there are any guarded_by or +/// guarded_var attributes, and make sure we hold the appropriate mutexes. +void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) { +  const ValueDecl *D = getValueDecl(Exp); +  if(!D || !D->hasAttrs()) +    return; + +  if (D->getAttr<GuardedVarAttr>() && LSet.isEmpty()) +    Handler.handleNoMutexHeld(D, POK_VarAccess, AK, Exp->getExprLoc()); + +  const AttrVec &ArgAttrs = D->getAttrs(); +  for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) +    if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i])) +      warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess); +} + +/// \brief Process a function call, method call, constructor call, +/// or destructor call.  This involves looking at the attributes on the +/// corresponding function/method/constructor/destructor, issuing warnings, +/// and updating the locksets accordingly. +/// +/// FIXME: For classes annotated with one of the guarded annotations, we need +/// to treat const method calls as reads and non-const method calls as writes, +/// and check that the appropriate locks are held. Non-const method calls with +/// the same signature as const method calls can be also treated as reads. +/// +/// FIXME: We need to also visit CallExprs to catch/check global functions. +/// +/// FIXME: Do not flag an error for member variables accessed in constructors/ +/// destructors +void BuildLockset::handleCall(Expr *Exp, NamedDecl *D, VarDecl *VD) { +  AttrVec &ArgAttrs = D->getAttrs(); +  for(unsigned i = 0; i < ArgAttrs.size(); ++i) { +    Attr *Attr = ArgAttrs[i]; +    switch (Attr->getKind()) { +      // When we encounter an exclusive lock function, we need to add the lock +      // to our lockset with kind exclusive. +      case attr::ExclusiveLockFunction: { +        ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(Attr); +        addLocksToSet(LK_Exclusive, A, Exp, D, VD); +        break; +      } + +      // When we encounter a shared lock function, we need to add the lock +      // to our lockset with kind shared. +      case attr::SharedLockFunction: { +        SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(Attr); +        addLocksToSet(LK_Shared, A, Exp, D, VD); +        break; +      } + +      // When we encounter an unlock function, we need to remove unlocked +      // mutexes from the lockset, and flag a warning if they are not there. +      case attr::UnlockFunction: { +        UnlockFunctionAttr *UFAttr = cast<UnlockFunctionAttr>(Attr); +        removeLocksFromSet(UFAttr, Exp, D); +        break; +      } + +      case attr::ExclusiveLocksRequired: { +        ExclusiveLocksRequiredAttr *ELRAttr = +            cast<ExclusiveLocksRequiredAttr>(Attr); + +        for (ExclusiveLocksRequiredAttr::args_iterator +             I = ELRAttr->args_begin(), E = ELRAttr->args_end(); I != E; ++I) +          warnIfMutexNotHeld(D, Exp, AK_Written, *I, POK_FunctionCall); +        break; +      } + +      case attr::SharedLocksRequired: { +        SharedLocksRequiredAttr *SLRAttr = cast<SharedLocksRequiredAttr>(Attr); + +        for (SharedLocksRequiredAttr::args_iterator I = SLRAttr->args_begin(), +             E = SLRAttr->args_end(); I != E; ++I) +          warnIfMutexNotHeld(D, Exp, AK_Read, *I, POK_FunctionCall); +        break; +      } + +      case attr::LocksExcluded: { +        LocksExcludedAttr *LEAttr = cast<LocksExcludedAttr>(Attr); +        for (LocksExcludedAttr::args_iterator I = LEAttr->args_begin(), +            E = LEAttr->args_end(); I != E; ++I) { +          MutexID Mutex(*I, Exp, D); +          if (!Mutex.isValid()) +            MutexID::warnInvalidLock(Handler, *I, Exp, D); +          else if (locksetContains(Mutex)) +            Handler.handleFunExcludesLock(D->getName(), Mutex.getName(), +                                          Exp->getExprLoc()); +        } +        break; +      } + +      // Ignore other (non thread-safety) attributes +      default: +        break; +    } +  } +} + + +/// \brief Add lock to set, if the current block is in the taken branch of a +/// trylock. +template <class AttrType> +void BuildLockset::addTrylock(LockKind LK, AttrType *Attr, Expr *Exp, +                              NamedDecl *FunDecl, const CFGBlock *PredBlock, +                              const CFGBlock *CurrBlock, Expr *BrE, bool Neg) { +  // Find out which branch has the lock +  bool branch = 0; +  if (CXXBoolLiteralExpr *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE)) { +    branch = BLE->getValue(); +  } +  else if (IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE)) { +    branch = ILE->getValue().getBoolValue(); +  } +  int branchnum = branch ? 0 : 1; +  if (Neg) branchnum = !branchnum; + +  // If we've taken the trylock branch, then add the lock +  int i = 0; +  for (CFGBlock::const_succ_iterator SI = PredBlock->succ_begin(), +       SE = PredBlock->succ_end(); SI != SE && i < 2; ++SI, ++i) { +    if (*SI == CurrBlock && i == branchnum) { +      addLocksToSet(LK, Attr, Exp, FunDecl, 0); +    } +  } +} + + +// If Cond can be traced back to a function call, return the call expression. +// The negate variable should be called with false, and will be set to true +// if the function call is negated, e.g. if (!mu.tryLock(...)) +CallExpr* BuildLockset::getTrylockCallExpr(Stmt *Cond, +                               LocalVariableMap::Context C, +                               bool &Negate) { +  if (!Cond) +    return 0; + +  if (CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) { +    return CallExp; +  } +  else if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) { +    return getTrylockCallExpr(CE->getSubExpr(), C, Negate); +  } +  else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) { +    Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C); +    return getTrylockCallExpr(E, C, Negate); +  } +  else if (UnaryOperator *UOP = dyn_cast<UnaryOperator>(Cond)) { +    if (UOP->getOpcode() == UO_LNot) { +      Negate = !Negate; +      return getTrylockCallExpr(UOP->getSubExpr(), C, Negate); +    } +  } +  // FIXME -- handle && and || as well. +  return NULL; +} + + +/// \brief Process a conditional branch from a previous block to the current +/// block, looking for trylock calls. +void BuildLockset::handleTrylock(Stmt *Cond, const CFGBlock *PredBlock, +                                 const CFGBlock *CurrBlock) { +  bool Negate = false; +  CallExpr *Exp = getTrylockCallExpr(Cond, LVarCtx, Negate); +  if (!Exp) +    return; + +  NamedDecl *FunDecl = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl()); +  if(!FunDecl || !FunDecl->hasAttrs()) +    return; + +  // If the condition is a call to a Trylock function, then grab the attributes +  AttrVec &ArgAttrs = FunDecl->getAttrs(); +  for (unsigned i = 0; i < ArgAttrs.size(); ++i) { +    Attr *Attr = ArgAttrs[i]; +    switch (Attr->getKind()) { +      case attr::ExclusiveTrylockFunction: { +        ExclusiveTrylockFunctionAttr *A = +          cast<ExclusiveTrylockFunctionAttr>(Attr); +        addTrylock(LK_Exclusive, A, Exp, FunDecl, PredBlock, CurrBlock, +                   A->getSuccessValue(), Negate); +        break; +      } +      case attr::SharedTrylockFunction: { +        SharedTrylockFunctionAttr *A = +          cast<SharedTrylockFunctionAttr>(Attr); +        addTrylock(LK_Shared, A, Exp, FunDecl, PredBlock, CurrBlock, +                   A->getSuccessValue(), Negate); +        break; +      } +      default: +        break; +    } +  } +} + + +/// \brief For unary operations which read and write a variable, we need to +/// check whether we hold any required mutexes. Reads are checked in +/// VisitCastExpr. +void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) { +  switch (UO->getOpcode()) { +    case clang::UO_PostDec: +    case clang::UO_PostInc: +    case clang::UO_PreDec: +    case clang::UO_PreInc: { +      Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts(); +      checkAccess(SubExp, AK_Written); +      checkDereference(SubExp, AK_Written); +      break; +    } +    default: +      break; +  } +} + +/// For binary operations which assign to a variable (writes), we need to check +/// whether we hold any required mutexes. +/// FIXME: Deal with non-primitive types. +void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) { +  if (!BO->isAssignmentOp()) +    return; + +  // adjust the context +  LVarCtx = LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx); + +  Expr *LHSExp = BO->getLHS()->IgnoreParenCasts(); +  checkAccess(LHSExp, AK_Written); +  checkDereference(LHSExp, AK_Written); +} + +/// Whenever we do an LValue to Rvalue cast, we are reading a variable and +/// need to ensure we hold any required mutexes. +/// FIXME: Deal with non-primitive types. +void BuildLockset::VisitCastExpr(CastExpr *CE) { +  if (CE->getCastKind() != CK_LValueToRValue) +    return; +  Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts(); +  checkAccess(SubExp, AK_Read); +  checkDereference(SubExp, AK_Read); +} + + +void BuildLockset::VisitCallExpr(CallExpr *Exp) { +  NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl()); +  if(!D || !D->hasAttrs()) +    return; +  handleCall(Exp, D); +} + +void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) { +  // FIXME -- only handles constructors in DeclStmt below. +} + +void BuildLockset::VisitDeclStmt(DeclStmt *S) { +  // adjust the context +  LVarCtx = LocalVarMap.getNextContext(CtxIndex, S, LVarCtx); + +  DeclGroupRef DGrp = S->getDeclGroup(); +  for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) { +    Decl *D = *I; +    if (VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) { +      Expr *E = VD->getInit(); +      if (CXXConstructExpr *CE = dyn_cast_or_null<CXXConstructExpr>(E)) { +        NamedDecl *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor()); +        if (!CtorD || !CtorD->hasAttrs()) +          return; +        handleCall(CE, CtorD, VD); +      } +    } +  } +} + + +/// \brief Compute the intersection of two locksets and issue warnings for any +/// locks in the symmetric difference. +/// +/// This function is used at a merge point in the CFG when comparing the lockset +/// of each branch being merged. For example, given the following sequence: +/// A; if () then B; else C; D; we need to check that the lockset after B and C +/// are the same. In the event of a difference, we use the intersection of these +/// two locksets at the start of D. +Lockset ThreadSafetyAnalyzer::intersectAndWarn(const CFGBlockInfo &Block1, +                                               CFGBlockSide Side1, +                                               const CFGBlockInfo &Block2, +                                               CFGBlockSide Side2, +                                               LockErrorKind LEK) { +  Lockset LSet1 = Block1.getSet(Side1); +  Lockset LSet2 = Block2.getSet(Side2); + +  Lockset Intersection = LSet1; +  for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) { +    const MutexID &LSet2Mutex = I.getKey(); +    const LockData &LSet2LockData = I.getData(); +    if (const LockData *LD = LSet1.lookup(LSet2Mutex)) { +      if (LD->LKind != LSet2LockData.LKind) { +        Handler.handleExclusiveAndShared(LSet2Mutex.getName(), +                                         LSet2LockData.AcquireLoc, +                                         LD->AcquireLoc); +        if (LD->LKind != LK_Exclusive) +          Intersection = LocksetFactory.add(Intersection, LSet2Mutex, +                                            LSet2LockData); +      } +    } else { +      Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(), +                                        LSet2LockData.AcquireLoc, +                                        Block1.getLocation(Side1), LEK); +    } +  } + +  for (Lockset::iterator I = LSet1.begin(), E = LSet1.end(); I != E; ++I) { +    if (!LSet2.contains(I.getKey())) { +      const MutexID &Mutex = I.getKey(); +      const LockData &MissingLock = I.getData(); +      Handler.handleMutexHeldEndOfScope(Mutex.getName(), +                                        MissingLock.AcquireLoc, +                                        Block2.getLocation(Side2), LEK); +      Intersection = LocksetFactory.remove(Intersection, Mutex); +    } +  } +  return Intersection; +} + +Lockset ThreadSafetyAnalyzer::addLock(Lockset &LSet, Expr *MutexExp, +                                      const NamedDecl *D, +                                      LockKind LK, SourceLocation Loc) { +  MutexID Mutex(MutexExp, 0, D); +  if (!Mutex.isValid()) { +    MutexID::warnInvalidLock(Handler, MutexExp, 0, D); +    return LSet; +  } +  LockData NewLock(Loc, LK); +  return LocksetFactory.add(LSet, Mutex, NewLock); +} + +/// \brief Check a function's CFG for thread-safety violations. +/// +/// We traverse the blocks in the CFG, compute the set of mutexes that are held +/// at the end of each block, and issue warnings for thread safety violations. +/// Each block in the CFG is traversed exactly once. +void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { +  CFG *CFGraph = AC.getCFG(); +  if (!CFGraph) return; +  const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl()); + +  if (!D) +    return;  // Ignore anonymous functions for now. +  if (D->getAttr<NoThreadSafetyAnalysisAttr>()) +    return; +  // FIXME: Do something a bit more intelligent inside constructor and +  // destructor code.  Constructors and destructors must assume unique access +  // to 'this', so checks on member variable access is disabled, but we should +  // still enable checks on other objects. +  if (isa<CXXConstructorDecl>(D)) +    return;  // Don't check inside constructors. +  if (isa<CXXDestructorDecl>(D)) +    return;  // Don't check inside destructors. + +  std::vector<CFGBlockInfo> BlockInfo(CFGraph->getNumBlockIDs(), +    CFGBlockInfo::getEmptyBlockInfo(LocksetFactory, LocalVarMap)); + +  // We need to explore the CFG via a "topological" ordering. +  // That way, we will be guaranteed to have information about required +  // predecessor locksets when exploring a new block. +  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); +  PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph); + +  // Compute SSA names for local variables +  LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo); + +  // Fill in source locations for all CFGBlocks. +  findBlockLocations(CFGraph, SortedGraph, BlockInfo); + +  // Add locks from exclusive_locks_required and shared_locks_required +  // to initial lockset. Also turn off checking for lock and unlock functions. +  // FIXME: is there a more intelligent way to check lock/unlock functions? +  if (!SortedGraph->empty() && D->hasAttrs()) { +    const CFGBlock *FirstBlock = *SortedGraph->begin(); +    Lockset &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet; +    const AttrVec &ArgAttrs = D->getAttrs(); +    for (unsigned i = 0; i < ArgAttrs.size(); ++i) { +      Attr *Attr = ArgAttrs[i]; +      SourceLocation AttrLoc = Attr->getLocation(); +      if (SharedLocksRequiredAttr *SLRAttr +            = dyn_cast<SharedLocksRequiredAttr>(Attr)) { +        for (SharedLocksRequiredAttr::args_iterator +             SLRIter = SLRAttr->args_begin(), +             SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter) +          InitialLockset = addLock(InitialLockset, +                                   *SLRIter, D, LK_Shared, +                                   AttrLoc); +      } else if (ExclusiveLocksRequiredAttr *ELRAttr +                   = dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) { +        for (ExclusiveLocksRequiredAttr::args_iterator +             ELRIter = ELRAttr->args_begin(), +             ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter) +          InitialLockset = addLock(InitialLockset, +                                   *ELRIter, D, LK_Exclusive, +                                   AttrLoc); +      } else if (isa<UnlockFunctionAttr>(Attr)) { +        // Don't try to check unlock functions for now +        return; +      } else if (isa<ExclusiveLockFunctionAttr>(Attr)) { +        // Don't try to check lock functions for now +        return; +      } else if (isa<SharedLockFunctionAttr>(Attr)) { +        // Don't try to check lock functions for now +        return; +      } +    } +  } + +  for (PostOrderCFGView::iterator I = SortedGraph->begin(), +       E = SortedGraph->end(); I!= E; ++I) { +    const CFGBlock *CurrBlock = *I; +    int CurrBlockID = CurrBlock->getBlockID(); +    CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID]; + +    // Use the default initial lockset in case there are no predecessors. +    VisitedBlocks.insert(CurrBlock); + +    // Iterate through the predecessor blocks and warn if the lockset for all +    // predecessors is not the same. We take the entry lockset of the current +    // block to be the intersection of all previous locksets. +    // FIXME: By keeping the intersection, we may output more errors in future +    // for a lock which is not in the intersection, but was in the union. We +    // may want to also keep the union in future. As an example, let's say +    // the intersection contains Mutex L, and the union contains L and M. +    // Later we unlock M. At this point, we would output an error because we +    // never locked M; although the real error is probably that we forgot to +    // lock M on all code paths. Conversely, let's say that later we lock M. +    // In this case, we should compare against the intersection instead of the +    // union because the real error is probably that we forgot to unlock M on +    // all code paths. +    bool LocksetInitialized = false; +    llvm::SmallVector<CFGBlock*, 8> SpecialBlocks; +    for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(), +         PE  = CurrBlock->pred_end(); PI != PE; ++PI) { + +      // if *PI -> CurrBlock is a back edge +      if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) +        continue; + +      // Ignore edges from blocks that can't return. +      if ((*PI)->hasNoReturnElement()) +        continue; + +      // If the previous block ended in a 'continue' or 'break' statement, then +      // a difference in locksets is probably due to a bug in that block, rather +      // than in some other predecessor. In that case, keep the other +      // predecessor's lockset. +      if (const Stmt *Terminator = (*PI)->getTerminator()) { +        if (isa<ContinueStmt>(Terminator) || isa<BreakStmt>(Terminator)) { +          SpecialBlocks.push_back(*PI); +          continue; +        } +      } + +      int PrevBlockID = (*PI)->getBlockID(); +      CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; + +      if (!LocksetInitialized) { +        CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet; +        LocksetInitialized = true; +      } else { +        CurrBlockInfo->EntrySet = +          intersectAndWarn(*CurrBlockInfo, CBS_Entry, +                           *PrevBlockInfo, CBS_Exit, +                           LEK_LockedSomePredecessors); +      } +    } + +    // Process continue and break blocks. Assume that the lockset for the +    // resulting block is unaffected by any discrepancies in them. +    for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size(); +         SpecialI < SpecialN; ++SpecialI) { +      CFGBlock *PrevBlock = SpecialBlocks[SpecialI]; +      int PrevBlockID = PrevBlock->getBlockID(); +      CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; + +      if (!LocksetInitialized) { +        CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet; +        LocksetInitialized = true; +      } else { +        // Determine whether this edge is a loop terminator for diagnostic +        // purposes. FIXME: A 'break' statement might be a loop terminator, but +        // it might also be part of a switch. Also, a subsequent destructor +        // might add to the lockset, in which case the real issue might be a +        // double lock on the other path. +        const Stmt *Terminator = PrevBlock->getTerminator(); +        bool IsLoop = Terminator && isa<ContinueStmt>(Terminator); + +        // Do not update EntrySet. +        intersectAndWarn(*CurrBlockInfo, CBS_Entry, *PrevBlockInfo, CBS_Exit, +                         IsLoop ? LEK_LockedSomeLoopIterations +                                : LEK_LockedSomePredecessors); +      } +    } + +    BuildLockset LocksetBuilder(this, *CurrBlockInfo); +    CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(), +                                  PE = CurrBlock->pred_end(); +    if (PI != PE) { +      // If the predecessor ended in a branch, then process any trylocks. +      // FIXME -- check to make sure there's only one predecessor. +      if (Stmt *TCE = (*PI)->getTerminatorCondition()) { +        LocksetBuilder.handleTrylock(TCE, *PI, CurrBlock); +      } +    } + +    // Visit all the statements in the basic block. +    for (CFGBlock::const_iterator BI = CurrBlock->begin(), +         BE = CurrBlock->end(); BI != BE; ++BI) { +      switch (BI->getKind()) { +        case CFGElement::Statement: { +          const CFGStmt *CS = cast<CFGStmt>(&*BI); +          LocksetBuilder.Visit(const_cast<Stmt*>(CS->getStmt())); +          break; +        } +        // Ignore BaseDtor, MemberDtor, and TemporaryDtor for now. +        case CFGElement::AutomaticObjectDtor: { +          const CFGAutomaticObjDtor *AD = cast<CFGAutomaticObjDtor>(&*BI); +          CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>( +            AD->getDestructorDecl(AC.getASTContext())); +          if (!DD->hasAttrs()) +            break; + +          // Create a dummy expression, +          VarDecl *VD = const_cast<VarDecl*>(AD->getVarDecl()); +          DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, +                          AD->getTriggerStmt()->getLocEnd()); +          LocksetBuilder.handleCall(&DRE, DD); +          break; +        } +        default: +          break; +      } +    } +    CurrBlockInfo->ExitSet = LocksetBuilder.LSet; + +    // For every back edge from CurrBlock (the end of the loop) to another block +    // (FirstLoopBlock) we need to check that the Lockset of Block is equal to +    // the one held at the beginning of FirstLoopBlock. We can look up the +    // Lockset held at the beginning of FirstLoopBlock in the EntryLockSets map. +    for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), +         SE  = CurrBlock->succ_end(); SI != SE; ++SI) { + +      // if CurrBlock -> *SI is *not* a back edge +      if (*SI == 0 || !VisitedBlocks.alreadySet(*SI)) +        continue; + +      CFGBlock *FirstLoopBlock = *SI; +      CFGBlockInfo &PreLoop = BlockInfo[FirstLoopBlock->getBlockID()]; +      CFGBlockInfo &LoopEnd = BlockInfo[CurrBlockID]; +      intersectAndWarn(LoopEnd, CBS_Exit, PreLoop, CBS_Entry, +                       LEK_LockedSomeLoopIterations); +    } +  } + +  CFGBlockInfo &Initial = BlockInfo[CFGraph->getEntry().getBlockID()]; +  CFGBlockInfo &Final = BlockInfo[CFGraph->getExit().getBlockID()]; + +  // FIXME: Should we call this function for all blocks which exit the function? +  intersectAndWarn(Initial, CBS_Entry, Final, CBS_Exit, +                   LEK_LockedAtEndOfFunction); +} + +} // end anonymous namespace + + +namespace clang { +namespace thread_safety { + +/// \brief Check a function's CFG for thread-safety violations. +/// +/// We traverse the blocks in the CFG, compute the set of mutexes that are held +/// at the end of each block, and issue warnings for thread safety violations. +/// Each block in the CFG is traversed exactly once. +void runThreadSafetyAnalysis(AnalysisDeclContext &AC, +                             ThreadSafetyHandler &Handler) { +  ThreadSafetyAnalyzer Analyzer(Handler); +  Analyzer.runAnalysis(AC); +} + +/// \brief Helper function that returns a LockKind required for the given level +/// of access. +LockKind getLockKindFromAccessKind(AccessKind AK) { +  switch (AK) { +    case AK_Read : +      return LK_Shared; +    case AK_Written : +      return LK_Exclusive; +  } +  llvm_unreachable("Unknown AccessKind"); +} + +}} // end namespace clang::thread_safety diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp new file mode 100644 index 0000000..1c7e6b6 --- /dev/null +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -0,0 +1,725 @@ +//==- UninitializedValues.cpp - Find Uninitialized Values -------*- 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 uninitialized values analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#include <utility> +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/PackedVector.h" +#include "llvm/ADT/DenseMap.h" +#include "clang/AST/Decl.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" +#include "clang/Analysis/Analyses/UninitializedValues.h" +#include "llvm/Support/SaveAndRestore.h" + +using namespace clang; + +static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { +  if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && +      !vd->isExceptionVariable() && +      vd->getDeclContext() == dc) { +    QualType ty = vd->getType(); +    return ty->isScalarType() || ty->isVectorType(); +  } +  return false; +} + +//------------------------------------------------------------------------====// +// DeclToIndex: a mapping from Decls we track to value indices. +//====------------------------------------------------------------------------// + +namespace { +class DeclToIndex { +  llvm::DenseMap<const VarDecl *, unsigned> map; +public: +  DeclToIndex() {} +   +  /// Compute the actual mapping from declarations to bits. +  void computeMap(const DeclContext &dc); +   +  /// Return the number of declarations in the map. +  unsigned size() const { return map.size(); } +   +  /// Returns the bit vector index for a given declaration. +  llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const; +}; +} + +void DeclToIndex::computeMap(const DeclContext &dc) { +  unsigned count = 0; +  DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()), +                                               E(dc.decls_end()); +  for ( ; I != E; ++I) { +    const VarDecl *vd = *I; +    if (isTrackedVar(vd, &dc)) +      map[vd] = count++; +  } +} + +llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const { +  llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d); +  if (I == map.end()) +    return llvm::Optional<unsigned>(); +  return I->second; +} + +//------------------------------------------------------------------------====// +// CFGBlockValues: dataflow values for CFG blocks. +//====------------------------------------------------------------------------// + +// These values are defined in such a way that a merge can be done using +// a bitwise OR. +enum Value { Unknown = 0x0,         /* 00 */ +             Initialized = 0x1,     /* 01 */ +             Uninitialized = 0x2,   /* 10 */ +             MayUninitialized = 0x3 /* 11 */ }; + +static bool isUninitialized(const Value v) { +  return v >= Uninitialized; +} +static bool isAlwaysUninit(const Value v) { +  return v == Uninitialized; +} + +namespace { + +typedef llvm::PackedVector<Value, 2> ValueVector; +typedef std::pair<ValueVector *, ValueVector *> BVPair; + +class CFGBlockValues { +  const CFG &cfg; +  BVPair *vals; +  ValueVector scratch; +  DeclToIndex declToIndex; +   +  ValueVector &lazyCreate(ValueVector *&bv); +public: +  CFGBlockValues(const CFG &cfg); +  ~CFGBlockValues(); +   +  unsigned getNumEntries() const { return declToIndex.size(); } +   +  void computeSetOfDeclarations(const DeclContext &dc);   +  ValueVector &getValueVector(const CFGBlock *block, +                                const CFGBlock *dstBlock); + +  BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate); + +  void mergeIntoScratch(ValueVector const &source, bool isFirst); +  bool updateValueVectorWithScratch(const CFGBlock *block); +  bool updateValueVectors(const CFGBlock *block, const BVPair &newVals); +   +  bool hasNoDeclarations() const { +    return declToIndex.size() == 0; +  } + +  void resetScratch(); +  ValueVector &getScratch() { return scratch; } +   +  ValueVector::reference operator[](const VarDecl *vd); +};   +} // end anonymous namespace + +CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) { +  unsigned n = cfg.getNumBlockIDs(); +  if (!n) +    return; +  vals = new std::pair<ValueVector*, ValueVector*>[n]; +  memset((void*)vals, 0, sizeof(*vals) * n); +} + +CFGBlockValues::~CFGBlockValues() { +  unsigned n = cfg.getNumBlockIDs(); +  if (n == 0) +    return; +  for (unsigned i = 0; i < n; ++i) { +    delete vals[i].first; +    delete vals[i].second; +  } +  delete [] vals; +} + +void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { +  declToIndex.computeMap(dc); +  scratch.resize(declToIndex.size()); +} + +ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) { +  if (!bv) +    bv = new ValueVector(declToIndex.size()); +  return *bv; +} + +/// This function pattern matches for a '&&' or '||' that appears at +/// the beginning of a CFGBlock that also (1) has a terminator and  +/// (2) has no other elements.  If such an expression is found, it is returned. +static const BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { +  if (block->empty()) +    return 0; + +  CFGElement front = block->front(); +  const CFGStmt *cstmt = front.getAs<CFGStmt>(); +  if (!cstmt) +    return 0; + +  const BinaryOperator *b = dyn_cast_or_null<BinaryOperator>(cstmt->getStmt()); +   +  if (!b || !b->isLogicalOp()) +    return 0; +   +  if (block->pred_size() == 2) { +    if (block->getTerminatorCondition() == b) { +      if (block->succ_size() == 2) +      return b; +    } +    else if (block->size() == 1) +      return b; +  } + +  return 0; +} + +ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block, +                                            const CFGBlock *dstBlock) { +  unsigned idx = block->getBlockID(); +  if (dstBlock && getLogicalOperatorInChain(block)) { +    if (*block->succ_begin() == dstBlock) +      return lazyCreate(vals[idx].first); +    assert(*(block->succ_begin()+1) == dstBlock); +    return lazyCreate(vals[idx].second); +  } + +  assert(vals[idx].second == 0); +  return lazyCreate(vals[idx].first); +} + +BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block, +                                        bool shouldLazyCreate) { +  unsigned idx = block->getBlockID(); +  lazyCreate(vals[idx].first); +  if (shouldLazyCreate) +    lazyCreate(vals[idx].second); +  return vals[idx]; +} + +#if 0 +static void printVector(const CFGBlock *block, ValueVector &bv, +                        unsigned num) { +   +  llvm::errs() << block->getBlockID() << " :"; +  for (unsigned i = 0; i < bv.size(); ++i) { +    llvm::errs() << ' ' << bv[i]; +  } +  llvm::errs() << " : " << num << '\n'; +} + +static void printVector(const char *name, ValueVector const &bv) { +  llvm::errs() << name << " : "; +  for (unsigned i = 0; i < bv.size(); ++i) { +    llvm::errs() << ' ' << bv[i]; +  } +  llvm::errs() << "\n"; +} +#endif + +void CFGBlockValues::mergeIntoScratch(ValueVector const &source, +                                      bool isFirst) { +  if (isFirst) +    scratch = source; +  else +    scratch |= source; +} + +bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) { +  ValueVector &dst = getValueVector(block, 0); +  bool changed = (dst != scratch); +  if (changed) +    dst = scratch; +#if 0 +  printVector(block, scratch, 0); +#endif +  return changed; +} + +bool CFGBlockValues::updateValueVectors(const CFGBlock *block, +                                      const BVPair &newVals) { +  BVPair &vals = getValueVectors(block, true); +  bool changed = *newVals.first != *vals.first || +                 *newVals.second != *vals.second; +  *vals.first = *newVals.first; +  *vals.second = *newVals.second; +#if 0 +  printVector(block, *vals.first, 1); +  printVector(block, *vals.second, 2); +#endif +  return changed; +} + +void CFGBlockValues::resetScratch() { +  scratch.reset(); +} + +ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) { +  const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd); +  assert(idx.hasValue()); +  return scratch[idx.getValue()]; +} + +//------------------------------------------------------------------------====// +// Worklist: worklist for dataflow analysis. +//====------------------------------------------------------------------------// + +namespace { +class DataflowWorklist { +  SmallVector<const CFGBlock *, 20> worklist; +  llvm::BitVector enqueuedBlocks; +public: +  DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {} +   +  void enqueueSuccessors(const CFGBlock *block); +  const CFGBlock *dequeue(); +}; +} + +void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { +  unsigned OldWorklistSize = worklist.size(); +  for (CFGBlock::const_succ_iterator I = block->succ_begin(), +       E = block->succ_end(); I != E; ++I) { +    const CFGBlock *Successor = *I; +    if (!Successor || enqueuedBlocks[Successor->getBlockID()]) +      continue; +    worklist.push_back(Successor); +    enqueuedBlocks[Successor->getBlockID()] = true; +  } +  if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) +    return; + +  // Rotate the newly added blocks to the start of the worklist so that it forms +  // a proper queue when we pop off the end of the worklist. +  std::rotate(worklist.begin(), worklist.begin() + OldWorklistSize, +              worklist.end()); +} + +const CFGBlock *DataflowWorklist::dequeue() { +  if (worklist.empty()) +    return 0; +  const CFGBlock *b = worklist.back(); +  worklist.pop_back(); +  enqueuedBlocks[b->getBlockID()] = false; +  return b; +} + +//------------------------------------------------------------------------====// +// Transfer function for uninitialized values analysis. +//====------------------------------------------------------------------------// + +namespace { +class FindVarResult { +  const VarDecl *vd; +  const DeclRefExpr *dr; +public: +  FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {} +   +  const DeclRefExpr *getDeclRefExpr() const { return dr; } +  const VarDecl *getDecl() const { return vd; } +}; +   +class TransferFunctions : public StmtVisitor<TransferFunctions> { +  CFGBlockValues &vals; +  const CFG &cfg; +  AnalysisDeclContext ∾ +  UninitVariablesHandler *handler; +   +  /// The last DeclRefExpr seen when analyzing a block.  Used to +  /// cheat when detecting cases when the address of a variable is taken. +  DeclRefExpr *lastDR; +   +  /// The last lvalue-to-rvalue conversion of a variable whose value +  /// was uninitialized.  Normally this results in a warning, but it is +  /// possible to either silence the warning in some cases, or we +  /// propagate the uninitialized value. +  CastExpr *lastLoad; +   +  /// For some expressions, we want to ignore any post-processing after +  /// visitation. +  bool skipProcessUses; +   +public: +  TransferFunctions(CFGBlockValues &vals, const CFG &cfg, +                    AnalysisDeclContext &ac, +                    UninitVariablesHandler *handler) +    : vals(vals), cfg(cfg), ac(ac), handler(handler), +      lastDR(0), lastLoad(0), +      skipProcessUses(false) {} +   +  void reportUninit(const DeclRefExpr *ex, const VarDecl *vd, +                    bool isAlwaysUninit); + +  void VisitBlockExpr(BlockExpr *be); +  void VisitDeclStmt(DeclStmt *ds); +  void VisitDeclRefExpr(DeclRefExpr *dr); +  void VisitUnaryOperator(UnaryOperator *uo); +  void VisitBinaryOperator(BinaryOperator *bo); +  void VisitCastExpr(CastExpr *ce); +  void VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); +  void Visit(Stmt *s); +   +  bool isTrackedVar(const VarDecl *vd) { +    return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl())); +  } +   +  FindVarResult findBlockVarDecl(Expr *ex); +   +  void ProcessUses(Stmt *s = 0); +}; +} + +static const Expr *stripCasts(ASTContext &C, const Expr *Ex) { +  while (Ex) { +    Ex = Ex->IgnoreParenNoopCasts(C); +    if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) { +      if (CE->getCastKind() == CK_LValueBitCast) { +        Ex = CE->getSubExpr(); +        continue; +      } +    } +    break; +  } +  return Ex; +} + +void TransferFunctions::reportUninit(const DeclRefExpr *ex, +                                     const VarDecl *vd, bool isAlwaysUnit) { +  if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit); +} + +FindVarResult TransferFunctions::findBlockVarDecl(Expr *ex) { +  if (DeclRefExpr *dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts())) +    if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) +      if (isTrackedVar(vd)) +        return FindVarResult(vd, dr);   +  return FindVarResult(0, 0); +} + +void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs) { +  // This represents an initialization of the 'element' value. +  Stmt *element = fs->getElement(); +  const VarDecl *vd = 0; +   +  if (DeclStmt *ds = dyn_cast<DeclStmt>(element)) { +    vd = cast<VarDecl>(ds->getSingleDecl()); +    if (!isTrackedVar(vd)) +      vd = 0; +  } else { +    // Initialize the value of the reference variable. +    const FindVarResult &res = findBlockVarDecl(cast<Expr>(element)); +    vd = res.getDecl(); +  } +   +  if (vd) +    vals[vd] = Initialized; +} + +void TransferFunctions::VisitBlockExpr(BlockExpr *be) { +  const BlockDecl *bd = be->getBlockDecl(); +  for (BlockDecl::capture_const_iterator i = bd->capture_begin(), +        e = bd->capture_end() ; i != e; ++i) { +    const VarDecl *vd = i->getVariable(); +    if (!isTrackedVar(vd)) +      continue; +    if (i->isByRef()) { +      vals[vd] = Initialized; +      continue; +    } +    Value v = vals[vd]; +    if (handler && isUninitialized(v)) +      handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v)); +  } +} + +void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { +  // Record the last DeclRefExpr seen.  This is an lvalue computation. +  // We use this value to later detect if a variable "escapes" the analysis. +  if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) +    if (isTrackedVar(vd)) { +      ProcessUses(); +      lastDR = dr; +    } +} + +void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { +  for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); +       DI != DE; ++DI) { +    if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) { +      if (isTrackedVar(vd)) { +        if (Expr *init = vd->getInit()) { +          // If the initializer consists solely of a reference to itself, we +          // explicitly mark the variable as uninitialized. This allows code +          // like the following: +          // +          //   int x = x; +          // +          // to deliberately leave a variable uninitialized. Different analysis +          // clients can detect this pattern and adjust their reporting +          // appropriately, but we need to continue to analyze subsequent uses +          // of the variable. +          if (init == lastLoad) { +            const DeclRefExpr *DR +              = cast<DeclRefExpr>(stripCasts(ac.getASTContext(), +                                             lastLoad->getSubExpr())); +            if (DR->getDecl() == vd) { +              // int x = x; +              // Propagate uninitialized value, but don't immediately report +              // a problem. +              vals[vd] = Uninitialized; +              lastLoad = 0; +              lastDR = 0; +              if (handler) +                handler->handleSelfInit(vd); +              return; +            } +          } + +          // All other cases: treat the new variable as initialized. +          // This is a minor optimization to reduce the propagation +          // of the analysis, since we will have already reported +          // the use of the uninitialized value (which visiting the +          // initializer). +          vals[vd] = Initialized; +        } +      } +    } +  } +} + +void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { +  if (bo->isAssignmentOp()) { +    const FindVarResult &res = findBlockVarDecl(bo->getLHS()); +    if (const VarDecl *vd = res.getDecl()) { +      ValueVector::reference val = vals[vd]; +      if (isUninitialized(val)) { +        if (bo->getOpcode() != BO_Assign) +          reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); +        else +          val = Initialized; +      } +    } +  } +} + +void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { +  switch (uo->getOpcode()) { +    case clang::UO_PostDec: +    case clang::UO_PostInc: +    case clang::UO_PreDec: +    case clang::UO_PreInc: { +      const FindVarResult &res = findBlockVarDecl(uo->getSubExpr()); +      if (const VarDecl *vd = res.getDecl()) { +        assert(res.getDeclRefExpr() == lastDR); +        // We null out lastDR to indicate we have fully processed it +        // and we don't want the auto-value setting in Visit(). +        lastDR = 0; + +        ValueVector::reference val = vals[vd]; +        if (isUninitialized(val)) +          reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); +      } +      break; +    } +    default: +      break; +  } +} + +void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { +  if (ce->getCastKind() == CK_LValueToRValue) { +    const FindVarResult &res = findBlockVarDecl(ce->getSubExpr()); +    if (res.getDecl()) { +      assert(res.getDeclRefExpr() == lastDR); +      lastLoad = ce; +    } +  } +  else if (ce->getCastKind() == CK_NoOp || +           ce->getCastKind() == CK_LValueBitCast) { +    skipProcessUses = true; +  } +  else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) { +    if (cse->getType()->isVoidType()) { +      // e.g. (void) x; +      if (lastLoad == cse->getSubExpr()) { +        // Squelch any detected load of an uninitialized value if +        // we cast it to void. +        lastLoad = 0; +        lastDR = 0; +      } +    } +  } +} + +void TransferFunctions::Visit(clang::Stmt *s) { +  skipProcessUses = false; +  StmtVisitor<TransferFunctions>::Visit(s); +  if (!skipProcessUses) +    ProcessUses(s); +} + +void TransferFunctions::ProcessUses(Stmt *s) { +  // This method is typically called after visiting a CFGElement statement +  // in the CFG.  We delay processing of reporting many loads of uninitialized +  // values until here. +  if (lastLoad) { +    // If we just visited the lvalue-to-rvalue cast, there is nothing +    // left to do. +    if (lastLoad == s) +      return; + +    const DeclRefExpr *DR = +      cast<DeclRefExpr>(stripCasts(ac.getASTContext(), +                                   lastLoad->getSubExpr())); +    const VarDecl *VD = cast<VarDecl>(DR->getDecl()); + +    // If we reach here, we may have seen a load of an uninitialized value +    // and it hasn't been casted to void or otherwise handled.  In this +    // situation, report the incident. +    if (isUninitialized(vals[VD])) +      reportUninit(DR, VD, isAlwaysUninit(vals[VD])); + +    lastLoad = 0; + +    if (DR == lastDR) { +      lastDR = 0; +      return; +    } +  } + +  // Any other uses of 'lastDR' involve taking an lvalue of variable. +  // In this case, it "escapes" the analysis. +  if (lastDR && lastDR != s) { +    vals[cast<VarDecl>(lastDR->getDecl())] = Initialized; +    lastDR = 0; +  } +} + +//------------------------------------------------------------------------====// +// High-level "driver" logic for uninitialized values analysis. +//====------------------------------------------------------------------------// + +static bool runOnBlock(const CFGBlock *block, const CFG &cfg, +                       AnalysisDeclContext &ac, CFGBlockValues &vals, +                       llvm::BitVector &wasAnalyzed, +                       UninitVariablesHandler *handler = 0) { +   +  wasAnalyzed[block->getBlockID()] = true; +   +  if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { +    CFGBlock::const_pred_iterator itr = block->pred_begin(); +    BVPair vA = vals.getValueVectors(*itr, false); +    ++itr; +    BVPair vB = vals.getValueVectors(*itr, false); + +    BVPair valsAB; +     +    if (b->getOpcode() == BO_LAnd) { +      // Merge the 'F' bits from the first and second. +      vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true); +      vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false); +      valsAB.first = vA.first; +      valsAB.second = &vals.getScratch(); +    } else { +      // Merge the 'T' bits from the first and second. +      assert(b->getOpcode() == BO_LOr); +      vals.mergeIntoScratch(*vA.first, true); +      vals.mergeIntoScratch(*vB.first, false); +      valsAB.first = &vals.getScratch(); +      valsAB.second = vA.second ? vA.second : vA.first; +    } +    return vals.updateValueVectors(block, valsAB); +  } + +  // Default behavior: merge in values of predecessor blocks. +  vals.resetScratch(); +  bool isFirst = true; +  for (CFGBlock::const_pred_iterator I = block->pred_begin(), +       E = block->pred_end(); I != E; ++I) { +    const CFGBlock *pred = *I; +    if (wasAnalyzed[pred->getBlockID()]) { +      vals.mergeIntoScratch(vals.getValueVector(pred, block), isFirst); +      isFirst = false; +    } +  } +  // Apply the transfer function. +  TransferFunctions tf(vals, cfg, ac, handler); +  for (CFGBlock::const_iterator I = block->begin(), E = block->end();  +       I != E; ++I) { +    if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) { +      tf.Visit(const_cast<Stmt*>(cs->getStmt())); +    } +  } +  tf.ProcessUses(); +  return vals.updateValueVectorWithScratch(block); +} + +void clang::runUninitializedVariablesAnalysis( +    const DeclContext &dc, +    const CFG &cfg, +    AnalysisDeclContext &ac, +    UninitVariablesHandler &handler, +    UninitVariablesAnalysisStats &stats) { +  CFGBlockValues vals(cfg); +  vals.computeSetOfDeclarations(dc); +  if (vals.hasNoDeclarations()) +    return; + +  stats.NumVariablesAnalyzed = vals.getNumEntries(); + +  // Mark all variables uninitialized at the entry. +  const CFGBlock &entry = cfg.getEntry(); +  for (CFGBlock::const_succ_iterator i = entry.succ_begin(),  +        e = entry.succ_end(); i != e; ++i) { +    if (const CFGBlock *succ = *i) { +      ValueVector &vec = vals.getValueVector(&entry, succ); +      const unsigned n = vals.getNumEntries(); +      for (unsigned j = 0; j < n ; ++j) { +        vec[j] = Uninitialized; +      } +    } +  } + +  // Proceed with the workist. +  DataflowWorklist worklist(cfg); +  llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); +  worklist.enqueueSuccessors(&cfg.getEntry()); +  llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); +  wasAnalyzed[cfg.getEntry().getBlockID()] = true; + +  while (const CFGBlock *block = worklist.dequeue()) { +    // Did the block change? +    bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed); +    ++stats.NumBlockVisits; +    if (changed || !previouslyVisited[block->getBlockID()]) +      worklist.enqueueSuccessors(block);     +    previouslyVisited[block->getBlockID()] = true; +  } +   +  // Run through the blocks one more time, and report uninitialized variabes. +  for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { +    const CFGBlock *block = *BI; +    if (wasAnalyzed[block->getBlockID()]) { +      runOnBlock(block, cfg, ac, vals, wasAnalyzed, &handler); +      ++stats.NumBlockVisits; +    } +  } +} + +UninitVariablesHandler::~UninitVariablesHandler() {}  | 
