InheritViz.cpp revision 5f9e272e632e951b1efe824cd16acb4d96077930
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"
214ebd7f54ad9ed6fb64fa2cfbbbebc97dbd30fba6Ted Kremenek#include "llvm/Support/raw_ostream.h"
220218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include <map>
230218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
240218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorusing namespace llvm;
250218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
260218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregornamespace clang {
270218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
280218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// InheritanceHierarchyWriter - Helper class that writes out a
290218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// GraphViz file that diagrams the inheritance hierarchy starting at
300218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// a given C++ class type. Note that we do not use LLVM's
310218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// GraphWriter, because the interface does not permit us to properly
320218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// differentiate between uses of types as virtual bases
330218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// vs. non-virtual bases.
340218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorclass InheritanceHierarchyWriter {
350218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  ASTContext& Context;
365f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  raw_ostream &Out;
370218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::map<QualType, int, QualTypeOrdering> DirectBaseCount;
380218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::set<QualType, QualTypeOrdering> KnownVirtualBases;
390218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
400218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorpublic:
415f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  InheritanceHierarchyWriter(ASTContext& Context, raw_ostream& Out)
420218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    : Context(Context), Out(Out) { }
430218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
440218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  void WriteGraph(QualType Type) {
450218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n";
460218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNode(Type, false);
470218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "}\n";
480218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
490218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
500218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorprotected:
510218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// WriteNode - Write out the description of node in the inheritance
520218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// diagram, which may be a base class or it may be the root node.
530218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  void WriteNode(QualType Type, bool FromVirtual);
540218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
550218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// WriteNodeReference - Write out a reference to the given node,
560218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// using a unique identifier for each direct base and for the
570218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// (only) virtual base.
585f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual);
590218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor};
600218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
610218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorvoid InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
620218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  QualType CanonType = Context.getCanonicalType(Type);
630218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
640218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (FromVirtual) {
650218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end())
660218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      return;
670218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
680218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // We haven't seen this virtual base before, so display it and
690218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // its bases.
700218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    KnownVirtualBases.insert(CanonType);
710218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
720218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
730218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Declare the node itself.
740218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << "  ";
750218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  WriteNodeReference(Type, FromVirtual);
760218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
770218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Give the node a label based on the name of the class.
780218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::string TypeName = Type.getAsString();
790218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName);
800218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
810218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // If the name of the class was a typedef or something different
820218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // from the "real" class name, show the real class name in
830218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // parentheses so we don't confuse ourselves.
840218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (TypeName != CanonType.getAsString()) {
850218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "\\n(" << CanonType.getAsString() << ")";
860218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
870218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
880218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Finished describing the node.
890218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << " \"];\n";
900218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
910218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Display the base classes.
921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  const CXXRecordDecl *Decl
936217b80b7a1379b74cced1c076338262c3c980b3Ted Kremenek    = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
9457c856b96e6bbfc64c2d61b950b116b523dc3e46Douglas Gregor  for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin();
9557c856b96e6bbfc64c2d61b950b116b523dc3e46Douglas Gregor       Base != Decl->bases_end(); ++Base) {
960218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    QualType CanonBaseType = Context.getCanonicalType(Base->getType());
970218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
980218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // If this is not virtual inheritance, bump the direct base
990218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // count for the type.
1000218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (!Base->isVirtual())
1010218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      ++DirectBaseCount[CanonBaseType];
1020218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1030218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out the node (if we need to).
1040218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNode(Base->getType(), Base->isVirtual());
1050218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1060218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out the edge.
1070218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "  ";
1080218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNodeReference(Type, FromVirtual);
1090218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << " -> ";
1100218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNodeReference(Base->getType(), Base->isVirtual());
1110218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1120218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out edge attributes to show the kind of inheritance.
1130218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (Base->isVirtual()) {
1140218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      Out << " [ style=\"dashed\" ]";
1150218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    }
1160218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << ";";
1170218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1180218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1190218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1200218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// WriteNodeReference - Write out a reference to the given node,
1210218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// using a unique identifier for each direct base and for the
1220218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// (only) virtual base.
1235f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerraw_ostream&
1241eb4433ac451dc16f4133a88af2d002ac26c58efMike StumpInheritanceHierarchyWriter::WriteNodeReference(QualType Type,
1250218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor                                               bool FromVirtual) {
1260218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  QualType CanonType = Context.getCanonicalType(Type);
1270218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1280218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << "Class_" << CanonType.getAsOpaquePtr();
1290218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (!FromVirtual)
1300218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "_" << DirectBaseCount[CanonType];
1310218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  return Out;
1320218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1330218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1340218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// viewInheritance - Display the inheritance hierarchy of this C++
1350218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// class using GraphViz.
1361f81230ac57b9bda8bba9c8221652842ca786132Douglas Gregorvoid CXXRecordDecl::viewInheritance(ASTContext& Context) const {
1371f81230ac57b9bda8bba9c8221652842ca786132Douglas Gregor  QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
138ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  std::string ErrMsg;
139ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
140ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  if (Filename.isEmpty()) {
141ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    llvm::errs() << "Error: " << ErrMsg << "\n";
142ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    return;
143ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  }
144ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  Filename.appendComponent(Self.getAsString() + ".dot");
145ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  if (Filename.makeUnique(true,&ErrMsg)) {
146ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    llvm::errs() << "Error: " << ErrMsg << "\n";
1470218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    return;
1480218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1490218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
150ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
1510218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
152ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
1530218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
154ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  if (ErrMsg.empty()) {
155ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    InheritanceHierarchyWriter Writer(Context, O);
156ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    Writer.WriteGraph(Self);
157ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    llvm::errs() << " done. \n";
1580218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
159ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    O.close();
160ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman
161ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    // Display the graph
162ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    DisplayGraph(Filename);
163ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  } else {
164ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman    llvm::errs() << "error opening file for writing!\n";
165ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman  }
1660218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1670218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1680218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
169