InheritViz.cpp revision 57c856b96e6bbfc64c2d61b950b116b523dc3e46
10218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//===- InheritViz.cpp - Graphviz visualization for inheritance --*- C++ -*-===//
20218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//
30218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//                     The LLVM Compiler Infrastructure
40218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//
50218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor// This file is distributed under the University of Illinois Open Source
60218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor// License. See LICENSE.TXT for details.
70218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//
80218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//===----------------------------------------------------------------------===//
90218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//
100218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//  This file implements CXXRecordDecl::viewInheritance, which
110218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//  generates a GraphViz DOT file that depicts the class inheritance
120218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//  diagram and then calls Graphviz/dot+gv on it.
130218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//
140218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor//===----------------------------------------------------------------------===//
150218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
160218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include "clang/AST/ASTContext.h"
170218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include "clang/AST/Decl.h"
180218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include "clang/AST/DeclCXX.h"
190218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include "clang/AST/TypeOrdering.h"
200218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include "llvm/Support/GraphWriter.h"
210218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include <fstream>
220218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include <map>
230218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
240218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorusing namespace llvm;
250218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
260218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregornamespace clang {
270218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
287a64a0329af04474f35b7e4a49629acbec28be15Douglas Gregor#ifndef NDEBUG
290218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// InheritanceHierarchyWriter - Helper class that writes out a
300218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// GraphViz file that diagrams the inheritance hierarchy starting at
310218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// a given C++ class type. Note that we do not use LLVM's
320218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// GraphWriter, because the interface does not permit us to properly
330218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// differentiate between uses of types as virtual bases
340218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// vs. non-virtual bases.
350218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorclass InheritanceHierarchyWriter {
360218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  ASTContext& Context;
370218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::ostream &Out;
380218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::map<QualType, int, QualTypeOrdering> DirectBaseCount;
390218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::set<QualType, QualTypeOrdering> KnownVirtualBases;
400218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
410218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorpublic:
420218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  InheritanceHierarchyWriter(ASTContext& Context, std::ostream& Out)
430218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    : Context(Context), Out(Out) { }
440218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
450218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  void WriteGraph(QualType Type) {
460218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n";
470218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNode(Type, false);
480218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "}\n";
490218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
500218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
510218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorprotected:
520218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// WriteNode - Write out the description of node in the inheritance
530218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// diagram, which may be a base class or it may be the root node.
540218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  void WriteNode(QualType Type, bool FromVirtual);
550218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
560218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// WriteNodeReference - Write out a reference to the given node,
570218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// using a unique identifier for each direct base and for the
580218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// (only) virtual base.
590218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::ostream& WriteNodeReference(QualType Type, bool FromVirtual);
600218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor};
610218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
620218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorvoid InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
630218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  QualType CanonType = Context.getCanonicalType(Type);
640218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
650218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (FromVirtual) {
660218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end())
670218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      return;
680218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
690218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // We haven't seen this virtual base before, so display it and
700218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // its bases.
710218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    KnownVirtualBases.insert(CanonType);
720218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
730218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
740218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Declare the node itself.
750218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << "  ";
760218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  WriteNodeReference(Type, FromVirtual);
770218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
780218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Give the node a label based on the name of the class.
790218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::string TypeName = Type.getAsString();
800218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName);
810218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
820218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // If the name of the class was a typedef or something different
830218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // from the "real" class name, show the real class name in
840218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // parentheses so we don't confuse ourselves.
850218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (TypeName != CanonType.getAsString()) {
860218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "\\n(" << CanonType.getAsString() << ")";
870218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
880218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
890218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Finished describing the node.
900218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << " \"];\n";
910218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
920218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Display the base classes.
930218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  const CXXRecordDecl *Decl
940218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    = static_cast<const CXXRecordDecl *>(Type->getAsRecordType()->getDecl());
9557c856b96e6bbfc64c2d61b950b116b523dc3e46Douglas Gregor  for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin();
9657c856b96e6bbfc64c2d61b950b116b523dc3e46Douglas Gregor       Base != Decl->bases_end(); ++Base) {
970218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    QualType CanonBaseType = Context.getCanonicalType(Base->getType());
980218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
990218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // If this is not virtual inheritance, bump the direct base
1000218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // count for the type.
1010218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (!Base->isVirtual())
1020218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      ++DirectBaseCount[CanonBaseType];
1030218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1040218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out the node (if we need to).
1050218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNode(Base->getType(), Base->isVirtual());
1060218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1070218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out the edge.
1080218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "  ";
1090218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNodeReference(Type, FromVirtual);
1100218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << " -> ";
1110218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNodeReference(Base->getType(), Base->isVirtual());
1120218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1130218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out edge attributes to show the kind of inheritance.
1140218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (Base->isVirtual()) {
1150218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      Out << " [ style=\"dashed\" ]";
1160218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    }
1170218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << ";";
1180218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1190218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1200218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1210218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// WriteNodeReference - Write out a reference to the given node,
1220218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// using a unique identifier for each direct base and for the
1230218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// (only) virtual base.
1240218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorstd::ostream&
1250218936235b137bbdcd29a6c36d61d9215bb4eddDouglas GregorInheritanceHierarchyWriter::WriteNodeReference(QualType Type,
1260218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor                                               bool FromVirtual) {
1270218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  QualType CanonType = Context.getCanonicalType(Type);
1280218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1290218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << "Class_" << CanonType.getAsOpaquePtr();
1300218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (!FromVirtual)
1310218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "_" << DirectBaseCount[CanonType];
1320218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  return Out;
1330218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1347a64a0329af04474f35b7e4a49629acbec28be15Douglas Gregor#endif
1350218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1360218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// viewInheritance - Display the inheritance hierarchy of this C++
1370218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// class using GraphViz.
1380218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorvoid QualType::viewInheritance(ASTContext& Context) {
1390218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (!(*this)->getAsRecordType()) {
1400218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    cerr << "Type " << getAsString() << " is not a C++ class type.\n";
1415dea18948c88cb67acb2217cc86cab490d51aa76Douglas Gregor    return;
1420218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1430218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#ifndef NDEBUG
1440218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::string ErrMsg;
1450218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
1460218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (Filename.isEmpty()) {
1470218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    cerr << "Error: " << ErrMsg << "\n";
1480218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    return;
1490218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1500218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Filename.appendComponent(getAsString() + ".dot");
1510218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (Filename.makeUnique(true,&ErrMsg)) {
1520218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    cerr << "Error: " << ErrMsg << "\n";
1530218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    return;
1540218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1550218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1560218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  cerr << "Writing '" << Filename << "'... ";
1570218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1580218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::ofstream O(Filename.c_str());
1590218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1600218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (O.good()) {
1610218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    InheritanceHierarchyWriter Writer(Context, O);
1620218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Writer.WriteGraph(*this);
1630218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    cerr << " done. \n";
1640218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1650218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    O.close();
1660218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1670218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Display the graph
1680218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    DisplayGraph(Filename);
1690218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  } else {
1700218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    cerr << "error opening file for writing!\n";
1710218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Filename.clear();
1720218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1730218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#else
1740218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  cerr << "QualType::viewInheritance is only available in debug "
1750218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor       << "builds on systems with Graphviz or gv!\n";
1760218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#endif
1770218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1780218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1790218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
180