zcov: / lib/AST/InheritViz.cpp


Files: 1 Branches Taken: 0.0% 0 / 24
Generated: 2010-02-10 01:31 Branches Executed: 0.0% 0 / 24
Line Coverage: 0.0% 0 / 61


Programs: 1 Runs 2897


       1                 : //===- InheritViz.cpp - Graphviz visualization for inheritance --*- C++ -*-===//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : //  This file implements CXXRecordDecl::viewInheritance, which
      11                 : //  generates a GraphViz DOT file that depicts the class inheritance
      12                 : //  diagram and then calls Graphviz/dot+gv on it.
      13                 : //
      14                 : //===----------------------------------------------------------------------===//
      15                 : 
      16                 : #include "clang/AST/ASTContext.h"
      17                 : #include "clang/AST/Decl.h"
      18                 : #include "clang/AST/DeclCXX.h"
      19                 : #include "clang/AST/TypeOrdering.h"
      20                 : #include "llvm/Support/GraphWriter.h"
      21                 : #include "llvm/Support/raw_ostream.h"
      22                 : #include <map>
      23                 : 
      24                 : using namespace llvm;
      25                 : 
      26                 : namespace clang {
      27                 : 
      28                 : /// InheritanceHierarchyWriter - Helper class that writes out a
      29                 : /// GraphViz file that diagrams the inheritance hierarchy starting at
      30                 : /// a given C++ class type. Note that we do not use LLVM's
      31                 : /// GraphWriter, because the interface does not permit us to properly
      32                 : /// differentiate between uses of types as virtual bases
      33                 : /// vs. non-virtual bases.
      34                0: class InheritanceHierarchyWriter {
      35                 :   ASTContext& Context;
      36                 :   llvm::raw_ostream &Out;
      37                 :   std::map<QualType, int, QualTypeOrdering> DirectBaseCount;
      38                 :   std::set<QualType, QualTypeOrdering> KnownVirtualBases;
      39                 : 
      40                 : public:
      41                0:   InheritanceHierarchyWriter(ASTContext& Context, llvm::raw_ostream& Out)
      42                0:     : Context(Context), Out(Out) { }
      43                 : 
      44                0:   void WriteGraph(QualType Type) {
      45                0:     Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n";
      46                0:     WriteNode(Type, false);
      47                0:     Out << "}\n";
      48                0:   }
      49                 : 
      50                 : protected:
      51                 :   /// WriteNode - Write out the description of node in the inheritance
      52                 :   /// diagram, which may be a base class or it may be the root node.
      53                 :   void WriteNode(QualType Type, bool FromVirtual);
      54                 : 
      55                 :   /// WriteNodeReference - Write out a reference to the given node,
      56                 :   /// using a unique identifier for each direct base and for the
      57                 :   /// (only) virtual base.
      58                 :   llvm::raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual);
      59                 : };
      60                 : 
      61                0: void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
      62                0:   QualType CanonType = Context.getCanonicalType(Type);
      63                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
      64                0:   if (FromVirtual) {
                        0: branch 3 not taken
                        0: branch 4 not taken
      65                0:     if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end())
      66                0:       return;
      67                 : 
      68                 :     // We haven't seen this virtual base before, so display it and
      69                 :     // its bases.
      70                0:     KnownVirtualBases.insert(CanonType);
      71                 :   }
      72                 : 
      73                 :   // Declare the node itself.
      74                0:   Out << "  ";
      75                0:   WriteNodeReference(Type, FromVirtual);
      76                 : 
      77                 :   // Give the node a label based on the name of the class.
      78                0:   std::string TypeName = Type.getAsString();
      79                0:   Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName);
      80                 : 
      81                 :   // If the name of the class was a typedef or something different
      82                 :   // from the "real" class name, show the real class name in
      83                 :   // parentheses so we don't confuse ourselves.
                        0: branch 3 not taken
                        0: branch 4 not taken
      84                0:   if (TypeName != CanonType.getAsString()) {
      85                0:     Out << "\\n(" << CanonType.getAsString() << ")";
      86                 :   }
      87                 : 
      88                 :   // Finished describing the node.
      89                0:   Out << " \"];\n";
      90                 : 
      91                 :   // Display the base classes.
      92                 :   const CXXRecordDecl *Decl
      93                0:     = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
                        0: branch 2 not taken
                        0: branch 3 not taken
      94                0:   for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin();
      95                 :        Base != Decl->bases_end(); ++Base) {
      96                0:     QualType CanonBaseType = Context.getCanonicalType(Base->getType());
      97                 : 
      98                 :     // If this is not virtual inheritance, bump the direct base
      99                 :     // count for the type.
                        0: branch 1 not taken
                        0: branch 2 not taken
     100                0:     if (!Base->isVirtual())
     101                0:       ++DirectBaseCount[CanonBaseType];
     102                 : 
     103                 :     // Write out the node (if we need to).
     104                0:     WriteNode(Base->getType(), Base->isVirtual());
     105                 : 
     106                 :     // Write out the edge.
     107                0:     Out << "  ";
     108                0:     WriteNodeReference(Type, FromVirtual);
     109                0:     Out << " -> ";
     110                0:     WriteNodeReference(Base->getType(), Base->isVirtual());
     111                 : 
     112                 :     // Write out edge attributes to show the kind of inheritance.
                        0: branch 1 not taken
                        0: branch 2 not taken
     113                0:     if (Base->isVirtual()) {
     114                0:       Out << " [ style=\"dashed\" ]";
     115                 :     }
     116                0:     Out << ";";
     117                0:   }
     118                 : }
     119                 : 
     120                 : /// WriteNodeReference - Write out a reference to the given node,
     121                 : /// using a unique identifier for each direct base and for the
     122                 : /// (only) virtual base.
     123                 : llvm::raw_ostream&
     124                 : InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
     125                0:                                                bool FromVirtual) {
     126                0:   QualType CanonType = Context.getCanonicalType(Type);
     127                 : 
     128                0:   Out << "Class_" << CanonType.getAsOpaquePtr();
                        0: branch 0 not taken
                        0: branch 1 not taken
     129                0:   if (!FromVirtual)
     130                0:     Out << "_" << DirectBaseCount[CanonType];
     131                0:   return Out;
     132                 : }
     133                 : 
     134                 : /// viewInheritance - Display the inheritance hierarchy of this C++
     135                 : /// class using GraphViz.
     136                0: void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
     137                0:   QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
     138                0:   std::string ErrMsg;
     139                0:   sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
                        0: branch 1 not taken
                        0: branch 2 not taken
     140                0:   if (Filename.isEmpty()) {
     141                0:     llvm::errs() << "Error: " << ErrMsg << "\n";
     142                0:     return;
     143                 :   }
     144                0:   Filename.appendComponent(Self.getAsString() + ".dot");
                        0: branch 1 not taken
                        0: branch 2 not taken
     145                0:   if (Filename.makeUnique(true,&ErrMsg)) {
     146                0:     llvm::errs() << "Error: " << ErrMsg << "\n";
     147                 :     return;
     148                 :   }
     149                 : 
     150                0:   llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
     151                 : 
     152                0:   llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
     153                 : 
                        0: branch 1 not taken
                        0: branch 2 not taken
     154                0:   if (ErrMsg.empty()) {
     155                0:     InheritanceHierarchyWriter Writer(Context, O);
     156                0:     Writer.WriteGraph(Self);
     157                0:     llvm::errs() << " done. \n";
     158                 : 
     159                0:     O.close();
     160                 : 
     161                 :     // Display the graph
     162                0:     DisplayGraph(Filename);
     163                 :   } else {
     164                0:     llvm::errs() << "error opening file for writing!\n";
                        0: branch 2 not taken
                        0: branch 3 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
     165                0:   }
     166                 : }
     167                 : 
     168                 : }

Generated: 2010-02-10 01:31 by zcov