]> granicus.if.org Git - clang/commitdiff
[CFG] Add dumps for CFGElement and CFGElementRef
authorKristof Umann <kristof.umann@ericsson.com>
Thu, 12 Sep 2019 19:52:34 +0000 (19:52 +0000)
committerKristof Umann <kristof.umann@ericsson.com>
Thu, 12 Sep 2019 19:52:34 +0000 (19:52 +0000)
Seems like we never had these, so here we go! I also did some refactoring as I
was chasing a bug unrelated to this revision.

Differential Revision: https://reviews.llvm.org/D66715

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371765 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/CFG.h
lib/Analysis/CFG.cpp

index 4c375c7a069e026b4f921ef73e6925aeda26a3b1..b24e32c96677704c85a9940719b2c2eddf84f7b0 100644 (file)
@@ -121,6 +121,12 @@ public:
     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 @@ class CFGBlock {
     }
 
     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 <bool IsReverse, bool IsConst> class ElementRefIterator {
index fb835d43680a01f806d9a9ff2fc5b45056371eea..1a45c9f532d92e7b2b3ea1efefa1780793d56ab4 100644 (file)
@@ -4999,6 +4999,8 @@ class StmtPrinterHelper : public PrinterHelper  {
 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() ;
@@ -5320,10 +5322,22 @@ static void print_construction_context(raw_ostream &OS,
     }
 }
 
+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<CFGStmt> CS = E.getAs<CFGStmt>()) {
-    const Stmt *S = CS->getStmt();
+  switch (E.getKind()) {
+  case CFGElement::Kind::Statement:
+  case CFGElement::Kind::CXXRecordTypedCall:
+  case CFGElement::Kind::Constructor: {
+    CFGStmt CS = E.castAs<CFGStmt>();
+    const Stmt *S = CS.getStmt();
     assert(S != nullptr && "Expecting non-null Stmt");
 
     // special printing for statement-expressions.
@@ -5375,12 +5389,18 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
     // Expressions need a newline.
     if (isa<Expr>(S))
       OS << '\n';
-  } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
-    print_initializer(OS, Helper, IE->getInitializer());
+
+    break;
+  }
+
+  case CFGElement::Kind::Initializer:
+    print_initializer(OS, Helper, E.castAs<CFGInitializer>().getInitializer());
     OS << '\n';
-  } else if (Optional<CFGAutomaticObjDtor> DE =
-                 E.getAs<CFGAutomaticObjDtor>()) {
-    const VarDecl *VD = DE->getVarDecl();
+    break;
+
+  case CFGElement::Kind::AutomaticObjectDtor: {
+    CFGAutomaticObjDtor DE = E.castAs<CFGAutomaticObjDtor>();
+    const VarDecl *VD = DE.getVarDecl();
     Helper.handleDecl(VD, OS);
 
     QualType T = VD->getType();
@@ -5390,53 +5410,75 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
     OS << ".~";
     T.getUnqualifiedType().print(OS, PrintingPolicy(Helper.getLangOpts()));
     OS << "() (Implicit destructor)\n";
-  } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) {
-    const VarDecl *VD = DE->getVarDecl();
-    Helper.handleDecl(VD, OS);
+    break;
+  }
 
+  case CFGElement::Kind::LifetimeEnds:
+    Helper.handleDecl(E.castAs<CFGLifetimeEnds>().getVarDecl(), OS);
     OS << " (Lifetime ends)\n";
-  } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) {
-    const Stmt *LoopStmt = LE->getLoopStmt();
-    OS << LoopStmt->getStmtClassName() << " (LoopExit)\n";
-  } else if (Optional<CFGScopeBegin> SB = E.getAs<CFGScopeBegin>()) {
+    break;
+
+  case CFGElement::Kind::LoopExit:
+    OS << E.castAs<CFGLoopExit>().getLoopStmt()->getStmtClassName() << " (LoopExit)\n";
+    break;
+
+  case CFGElement::Kind::ScopeBegin:
     OS << "CFGScopeBegin(";
-    if (const VarDecl *VD = SB->getVarDecl())
+    if (const VarDecl *VD = E.castAs<CFGScopeBegin>().getVarDecl())
       OS << VD->getQualifiedNameAsString();
     OS << ")\n";
-  } else if (Optional<CFGScopeEnd> SE = E.getAs<CFGScopeEnd>()) {
+    break;
+
+  case CFGElement::Kind::ScopeEnd:
     OS << "CFGScopeEnd(";
-    if (const VarDecl *VD = SE->getVarDecl())
+    if (const VarDecl *VD = E.castAs<CFGScopeEnd>().getVarDecl())
       OS << VD->getQualifiedNameAsString();
     OS << ")\n";
-  } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
+    break;
+
+  case CFGElement::Kind::NewAllocator:
     OS << "CFGNewAllocator(";
-    if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
+    if (const CXXNewExpr *AllocExpr = E.castAs<CFGNewAllocator>().getAllocatorExpr())
       AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
     OS << ")\n";
-  } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
-    const CXXRecordDecl *RD = DE->getCXXRecordDecl();
+    break;
+
+  case CFGElement::Kind::DeleteDtor: {
+    CFGDeleteDtor DE = E.castAs<CFGDeleteDtor>();
+    const CXXRecordDecl *RD = DE.getCXXRecordDecl();
     if (!RD)
       return;
     CXXDeleteExpr *DelExpr =
-        const_cast<CXXDeleteExpr*>(DE->getDeleteExpr());
+        const_cast<CXXDeleteExpr*>(DE.getDeleteExpr());
     Helper.handledStmt(cast<Stmt>(DelExpr->getArgument()), OS);
     OS << "->~" << RD->getName().str() << "()";
     OS << " (Implicit destructor)\n";
-  } else if (Optional<CFGBaseDtor> BE = E.getAs<CFGBaseDtor>()) {
-    const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
+    break;
+  }
+
+  case CFGElement::Kind::BaseDtor: {
+    const CXXBaseSpecifier *BS = E.castAs<CFGBaseDtor>().getBaseSpecifier();
     OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
     OS << " (Base object destructor)\n";
-  } else if (Optional<CFGMemberDtor> ME = E.getAs<CFGMemberDtor>()) {
-    const FieldDecl *FD = ME->getFieldDecl();
+    break;
+  }
+
+  case CFGElement::Kind::MemberDtor: {
+    const FieldDecl *FD = E.castAs<CFGMemberDtor>().getFieldDecl();
     const Type *T = FD->getType()->getBaseElementTypeUnsafe();
     OS << "this->" << FD->getName();
     OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
     OS << " (Member object destructor)\n";
-  } else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
-    const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
+    break;
+  }
+
+  case CFGElement::Kind::TemporaryDtor: {
+    const CXXBindTemporaryExpr *BT = E.castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
     OS << "~";
     BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
     OS << "() (Temporary object destructor)\n";
+    break;
+  }
   }
 }