Index: cfe/trunk/include/clang/Analysis/CFG.h =================================================================== --- cfe/trunk/include/clang/Analysis/CFG.h +++ cfe/trunk/include/clang/Analysis/CFG.h @@ -121,6 +121,12 @@ x |= Data1.getInt(); return (Kind) x; } + + void dumpToStream(llvm::raw_ostream &OS) const; + + void dump() const { + dumpToStream(llvm::errs()); + } }; class CFGStmt : public CFGElement { @@ -650,8 +656,17 @@ } bool operator!=(ElementRefImpl Other) const { return !(*this == Other); } - CFGElement operator*() { return (*Parent)[Index]; } - CFGElementPtr operator->() { return &*(Parent->begin() + Index); } + CFGElement operator*() const { return (*Parent)[Index]; } + CFGElementPtr operator->() const { return &*(Parent->begin() + Index); } + + void dumpToStream(llvm::raw_ostream &OS) const { + OS << getIndexInBlock() + 1 << ": "; + (*this)->dumpToStream(OS); + } + + void dump() const { + dumpToStream(llvm::errs()); + } }; template class ElementRefIterator { Index: cfe/trunk/lib/Analysis/CFG.cpp =================================================================== --- cfe/trunk/lib/Analysis/CFG.cpp +++ cfe/trunk/lib/Analysis/CFG.cpp @@ -4999,6 +4999,8 @@ public: StmtPrinterHelper(const CFG* cfg, const LangOptions &LO) : LangOpts(LO) { + if (!cfg) + return; 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() ; @@ -5321,9 +5323,21 @@ } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, + const CFGElement &E); + +void CFGElement::dumpToStream(llvm::raw_ostream &OS) const { + StmtPrinterHelper Helper(nullptr, {}); + print_elem(OS, Helper, *this); +} + +static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CFGElement &E) { - if (Optional CS = E.getAs()) { - const Stmt *S = CS->getStmt(); + switch (E.getKind()) { + case CFGElement::Kind::Statement: + case CFGElement::Kind::CXXRecordTypedCall: + case CFGElement::Kind::Constructor: { + CFGStmt CS = E.castAs(); + const Stmt *S = CS.getStmt(); assert(S != nullptr && "Expecting non-null Stmt"); // special printing for statement-expressions. @@ -5375,12 +5389,18 @@ // Expressions need a newline. if (isa(S)) OS << '\n'; - } else if (Optional IE = E.getAs()) { - print_initializer(OS, Helper, IE->getInitializer()); + + break; + } + + case CFGElement::Kind::Initializer: + print_initializer(OS, Helper, E.castAs().getInitializer()); OS << '\n'; - } else if (Optional DE = - E.getAs()) { - const VarDecl *VD = DE->getVarDecl(); + break; + + case CFGElement::Kind::AutomaticObjectDtor: { + CFGAutomaticObjDtor DE = E.castAs(); + const VarDecl *VD = DE.getVarDecl(); Helper.handleDecl(VD, OS); QualType T = VD->getType(); @@ -5390,53 +5410,75 @@ OS << ".~"; T.getUnqualifiedType().print(OS, PrintingPolicy(Helper.getLangOpts())); OS << "() (Implicit destructor)\n"; - } else if (Optional DE = E.getAs()) { - const VarDecl *VD = DE->getVarDecl(); - Helper.handleDecl(VD, OS); + break; + } + case CFGElement::Kind::LifetimeEnds: + Helper.handleDecl(E.castAs().getVarDecl(), OS); OS << " (Lifetime ends)\n"; - } else if (Optional LE = E.getAs()) { - const Stmt *LoopStmt = LE->getLoopStmt(); - OS << LoopStmt->getStmtClassName() << " (LoopExit)\n"; - } else if (Optional SB = E.getAs()) { + break; + + case CFGElement::Kind::LoopExit: + OS << E.castAs().getLoopStmt()->getStmtClassName() << " (LoopExit)\n"; + break; + + case CFGElement::Kind::ScopeBegin: OS << "CFGScopeBegin("; - if (const VarDecl *VD = SB->getVarDecl()) + if (const VarDecl *VD = E.castAs().getVarDecl()) OS << VD->getQualifiedNameAsString(); OS << ")\n"; - } else if (Optional SE = E.getAs()) { + break; + + case CFGElement::Kind::ScopeEnd: OS << "CFGScopeEnd("; - if (const VarDecl *VD = SE->getVarDecl()) + if (const VarDecl *VD = E.castAs().getVarDecl()) OS << VD->getQualifiedNameAsString(); OS << ")\n"; - } else if (Optional NE = E.getAs()) { + break; + + case CFGElement::Kind::NewAllocator: OS << "CFGNewAllocator("; - if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr()) + if (const CXXNewExpr *AllocExpr = E.castAs().getAllocatorExpr()) AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); OS << ")\n"; - } else if (Optional DE = E.getAs()) { - const CXXRecordDecl *RD = DE->getCXXRecordDecl(); + break; + + case CFGElement::Kind::DeleteDtor: { + CFGDeleteDtor DE = E.castAs(); + const CXXRecordDecl *RD = DE.getCXXRecordDecl(); if (!RD) return; CXXDeleteExpr *DelExpr = - const_cast(DE->getDeleteExpr()); + const_cast(DE.getDeleteExpr()); Helper.handledStmt(cast(DelExpr->getArgument()), OS); OS << "->~" << RD->getName().str() << "()"; OS << " (Implicit destructor)\n"; - } else if (Optional BE = E.getAs()) { - const CXXBaseSpecifier *BS = BE->getBaseSpecifier(); + break; + } + + case CFGElement::Kind::BaseDtor: { + const CXXBaseSpecifier *BS = E.castAs().getBaseSpecifier(); OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; OS << " (Base object destructor)\n"; - } else if (Optional ME = E.getAs()) { - const FieldDecl *FD = ME->getFieldDecl(); + break; + } + + case CFGElement::Kind::MemberDtor: { + const FieldDecl *FD = E.castAs().getFieldDecl(); const Type *T = FD->getType()->getBaseElementTypeUnsafe(); OS << "this->" << FD->getName(); OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; OS << " (Member object destructor)\n"; - } else if (Optional TE = E.getAs()) { - const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr(); + break; + } + + case CFGElement::Kind::TemporaryDtor: { + const CXXBindTemporaryExpr *BT = E.castAs().getBindTemporaryExpr(); OS << "~"; BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); OS << "() (Temporary object destructor)\n"; + break; + } } }