llvm/clang/lib/Analysis/CFG.cpp

//===- CFG.cpp - Classes for representing and building CFGs ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file defines the CFG and CFGBuilder classes for representing and
//  building Control-Flow Graphs (CFGs) from ASTs.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/CFG.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/ConstructionContext.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

usingnamespaceclang;

static SourceLocation GetEndLoc(Decl *D) {}

/// Returns true on constant values based around a single IntegerLiteral.
/// Allow for use of parentheses, integer casts, and negative signs.
/// FIXME: it would be good to unify this function with
/// getIntegerLiteralSubexpressionValue at some point given the similarity
/// between the functions.

static bool IsIntegerLiteralConstantExpr(const Expr *E) {}

/// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral
/// constant expression or EnumConstantDecl from the given Expr. If it fails,
/// returns nullptr.
static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) {}

/// Tries to interpret a binary operator into `Expr Op NumExpr` form, if
/// NumExpr is an integer literal or an enum constant.
///
/// If this fails, at least one of the returned DeclRefExpr or Expr will be
/// null.
static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
tryNormalizeBinaryOperator(const BinaryOperator *B) {}

/// For an expression `x == Foo && x == Bar`, this determines whether the
/// `Foo` and `Bar` are either of the same enumeration type, or both integer
/// literals.
///
/// It's an error to pass this arguments that are not either IntegerLiterals
/// or DeclRefExprs (that have decls of type EnumConstantDecl)
static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) {}

namespace {

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 {};

/// 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 {};

} // namespace

/// 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) {}

/// Calculates the closest parent of this iterator
/// that is in a scope reachable through the parents of L.
/// I.e. when using 'goto' from this to L, the lifetime of all variables
/// between this and shared_parent(L) end.
LocalScope::const_iterator
LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {}

namespace {

/// Structure for specifying position in CFG during its build process. It
/// consists of CFGBlock that specifies position in CFG and
/// LocalScope::const_iterator that specifies position in LocalScope graph.
struct BlockScopePosPair {};

/// 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 {};

} // namespace

static TryResult bothKnownTrue(TryResult R1, TryResult R2) {}

namespace {

class reverse_children {};

} // namespace

reverse_children::reverse_children(Stmt *S) {}

namespace {

/// 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;
///     std::unique_ptr<CFG> cfg = builder.buildCFG(decl, 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 {};

} // namespace

Expr *
clang::extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE) {}

inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
                                     const Stmt *stmt) const {}

bool CFGBuilder::alwaysAdd(const Stmt *stmt) {}

// 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) {}

void CFGBuilder::consumeConstructionContext(
    const ConstructionContextLayer *Layer, Expr *E) {}

void CFGBuilder::findConstructionContexts(
    const ConstructionContextLayer *Layer, Stmt *Child) {}

void CFGBuilder::cleanupConstructionContext(Expr *E) {}

/// 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.
std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {}

/// createBlock - Used to lazily create blocks that are connected
///  to the current (global) successor.
CFGBlock *CFGBuilder::createBlock(bool add_successor) {}

/// 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() {}

/// addInitializer - Add C++ base or member initializer element to CFG.
CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {}

/// Retrieve the type of the temporary object whose lifetime was
/// extended by a local reference with the given initializer.
static QualType getReferenceInitTemporaryType(const Expr *Init,
                                              bool *FoundMTE = nullptr) {}

// TODO: Support adding LoopExit element to the CFG in case where the loop is
// ended by ReturnStmt, GotoStmt or ThrowExpr.
void CFGBuilder::addLoopExit(const Stmt *LoopStmt){}

/// Adds the CFG elements for leaving the scope of automatic objects in
/// range [B, E). This include following:
///   * AutomaticObjectDtor for variables with non-trivial destructor
///   * LifetimeEnds for all variables
///   * ScopeEnd for each scope left
void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
                                         LocalScope::const_iterator E,
                                         Stmt *S) {}

/// Add CFG elements corresponding to call destructor and end of lifetime
/// of all automatic variables with non-trivial destructor in range [B, E).
/// This include AutomaticObjectDtor and LifetimeEnds elements.
void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
                                            LocalScope::const_iterator E,
                                            Stmt *S) {}

/// Add CFG elements corresponding to leaving a scope.
/// Assumes that range [B, E) corresponds to single scope.
/// This add following elements:
///   * LifetimeEnds for all variables with non-trivial destructor
///   * ScopeEnd for each scope left
void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
                                      LocalScope::const_iterator E, Stmt *S) {}

/// addScopeChangesHandling - appends information about destruction, lifetime
/// and cfgScopeEnd for variables in the scope that was left by the jump, and
/// appends cfgScopeBegin for all scopes that where entered.
/// We insert the cfgScopeBegin at the end of the jump node, as depending on
/// the sourceBlock, each goto, may enter different amount of scopes.
void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
                                         LocalScope::const_iterator DstPos,
                                         Stmt *S) {}

/// createScopeChangesHandlingBlock - Creates a block with cfgElements
/// corresponding to changing the scope from the source scope of the GotoStmt,
/// to destination scope. Add destructor, lifetime and cfgScopeEnd
/// CFGElements to newly created CFGBlock, that will have the CFG terminator
/// transferred.
CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
    LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
    LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {}

/// addImplicitDtorsForDestructor - Add implicit destructors generated for
/// base and member objects in destructor.
void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {}

/// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either
/// way return valid LocalScope object.
LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* 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) {}

/// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will
/// reuse Scope if not NULL.
LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
                                                 LocalScope* Scope) {}

bool CFGBuilder::needsAutomaticDestruction(const VarDecl *VD) const {}

bool CFGBuilder::hasTrivialDestructor(const VarDecl *VD) const {}

/// 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) {}

/// 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) {}

/// 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,
                            bool ExternallyDestructed) {}

CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {}

/// VisitChildren - Visit the children of a Stmt.
CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {}

CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
                                         AddStmtChoice asc) {}

static bool isFallthroughStatement(const AttributedStmt *A) {}

CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
                                          AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {}

std::pair<CFGBlock*, CFGBlock*>
CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
                                 Stmt *Term,
                                 CFGBlock *TrueBlock,
                                 CFGBlock *FalseBlock) {}

CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
                                          AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {}

static bool CanThrow(Expr *E, ASTContext &Ctx) {}

CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
                                      AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C,
                                        bool ExternallyDestructed) {}

CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
                                               AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {}

/// VisitDeclSubExpr - Utility method to add block-level expressions for
/// DeclStmts and initializers in them.
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {}

CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {}

CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {}

CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
                                                AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {}

CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {}

CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {}

CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {}

CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {}

CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {}

CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {}

CFGBlock *
CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
                                          AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {}

CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {}

CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {}

CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {}

CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {}

CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A,
                                             AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {}

CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {}

CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {}

CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
                                           AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {}

CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {}

CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {}

CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
                                                    AddStmtChoice asc) {}

/// VisitStmtExpr - Utility method to handle (nested) statement
///  expressions (a GCC extension).
CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {}

static bool shouldAddCase(bool &switchExclusivelyCovered,
                          const Expr::EvalResult *switchCond,
                          const CaseStmt *CS,
                          ASTContext &Ctx) {}

CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {}

CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {}

CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {}

CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {}

CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {}

CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
    AddStmtChoice asc, bool ExternallyDestructed) {}

CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
                                                AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
                                            AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
                                      AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
                                         AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
                                                 AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
                                                  AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
                                            AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc) {}

CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {}

CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool ExternallyDestructed,
                                             TempDtorContext &Context) {}

CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
                                                     bool ExternallyDestructed,
                                                     TempDtorContext &Context) {}

CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
    BinaryOperator *E, bool ExternallyDestructed, TempDtorContext &Context) {}

CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
    CXXBindTemporaryExpr *E, bool ExternallyDestructed, TempDtorContext &Context) {}

void CFGBuilder::InsertTempDtorDecisionBlock(const TempDtorContext &Context,
                                             CFGBlock *FalseSucc) {}

CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
    AbstractConditionalOperator *E, bool ExternallyDestructed,
    TempDtorContext &Context) {}

CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
                                                  AddStmtChoice asc) {}

/// 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() {}

/// buildCFG - Constructs a CFG from an AST.
std::unique_ptr<CFG> CFG::buildCFG(const Decl *D, Stmt *Statement,
                                   ASTContext *C, const BuildOptions &BO) {}

bool CFG::isLinear() const {}

const CXXDestructorDecl *
CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {}

//===----------------------------------------------------------------------===//
// CFGBlock operations.
//===----------------------------------------------------------------------===//

CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable)
    :{}

CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock)
    :{}

void CFGBlock::addSuccessor(AdjacentBlock Succ,
                            BumpVectorContext &C) {}

bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
        const CFGBlock *From, const CFGBlock *To) {}

//===----------------------------------------------------------------------===//
// CFG pretty printing
//===----------------------------------------------------------------------===//

namespace {

class StmtPrinterHelper : public PrinterHelper  {};

class CFGBlockTerminatorPrint
    : public StmtVisitor<CFGBlockTerminatorPrint,void> {};

} // namespace

static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper,
                              const CXXCtorInitializer *I) {}

static void print_construction_context(raw_ostream &OS,
                                       StmtPrinterHelper &Helper,
                                       const ConstructionContext *CC) {}

static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
                       const CFGElement &E);

void CFGElement::dumpToStream(llvm::raw_ostream &OS) const {}

static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
                       const CFGElement &E) {}

static void print_block(raw_ostream &OS, const CFG* cfg,
                        const CFGBlock &B,
                        StmtPrinterHelper &Helper, bool print_edges,
                        bool ShowColors) {}

/// dump - A simple pretty printer of a CFG that outputs to stderr.
void CFG::dump(const LangOptions &LO, bool ShowColors) const {}

/// 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 {}

size_t CFGBlock::getIndexInCFG() const {}

/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
                    bool ShowColors) const {}

LLVM_DUMP_METHOD void CFGBlock::dump() const {}

/// 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 {}

/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
void CFGBlock::printTerminator(raw_ostream &OS,
                               const LangOptions &LO) const {}

/// printTerminatorJson - Pretty-prints the terminator in JSON format.
void CFGBlock::printTerminatorJson(raw_ostream &Out, const LangOptions &LO,
                                   bool AddQuotes) const {}

// Returns true if by simply looking at the block, we can be sure that it
// results in a sink during analysis. This is useful to know when the analysis
// was interrupted, and we try to figure out if it would sink eventually.
// There may be many more reasons why a sink would appear during analysis
// (eg. checkers may generate sinks arbitrarily), but here we only consider
// sinks that would be obvious by looking at the CFG.
static bool isImmediateSinkBlock(const CFGBlock *Blk) {}

bool CFGBlock::isInevitablySinking() const {}

const Expr *CFGBlock::getLastCondition() const {}

Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {}

//===----------------------------------------------------------------------===//
// CFG Graphviz Visualization
//===----------------------------------------------------------------------===//

static StmtPrinterHelper *GraphHelper;

void CFG::viewCFG(const LangOptions &LO) const {}

namespace llvm {

template<>
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {};

} // namespace llvm