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"
20653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola#include "llvm/Support/FileSystem.h"
210218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include "llvm/Support/GraphWriter.h"
224ebd7f54ad9ed6fb64fa2cfbbbebc97dbd30fba6Ted Kremenek#include "llvm/Support/raw_ostream.h"
230218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor#include <map>
24e310d4473ffe22ee8e9161afa56fd8293cf2e013Rafael Espindola#include <set>
250218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
260218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorusing namespace llvm;
270218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
280218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregornamespace clang {
290218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
300218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// InheritanceHierarchyWriter - Helper class that writes out a
310218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// GraphViz file that diagrams the inheritance hierarchy starting at
320218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// a given C++ class type. Note that we do not use LLVM's
330218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// GraphWriter, because the interface does not permit us to properly
340218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// differentiate between uses of types as virtual bases
350218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// vs. non-virtual bases.
360218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorclass InheritanceHierarchyWriter {
370218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  ASTContext& Context;
385f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  raw_ostream &Out;
390218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::map<QualType, int, QualTypeOrdering> DirectBaseCount;
400218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::set<QualType, QualTypeOrdering> KnownVirtualBases;
410218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
420218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorpublic:
435f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  InheritanceHierarchyWriter(ASTContext& Context, raw_ostream& Out)
440218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    : Context(Context), Out(Out) { }
450218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
460218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  void WriteGraph(QualType Type) {
470218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n";
480218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNode(Type, false);
490218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "}\n";
500218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
510218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
520218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorprotected:
530218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// WriteNode - Write out the description of node in the inheritance
540218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// diagram, which may be a base class or it may be the root node.
550218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  void WriteNode(QualType Type, bool FromVirtual);
560218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
570218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// WriteNodeReference - Write out a reference to the given node,
580218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// using a unique identifier for each direct base and for the
590218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  /// (only) virtual base.
605f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual);
610218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor};
620218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
630218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregorvoid InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
640218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  QualType CanonType = Context.getCanonicalType(Type);
650218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
660218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (FromVirtual) {
670218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end())
680218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      return;
690218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
700218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // We haven't seen this virtual base before, so display it and
710218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // its bases.
720218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    KnownVirtualBases.insert(CanonType);
730218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
740218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
750218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Declare the node itself.
760218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << "  ";
770218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  WriteNodeReference(Type, FromVirtual);
780218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
790218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Give the node a label based on the name of the class.
800218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  std::string TypeName = Type.getAsString();
810218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName);
820218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
830218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // If the name of the class was a typedef or something different
840218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // from the "real" class name, show the real class name in
850218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // parentheses so we don't confuse ourselves.
860218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  if (TypeName != CanonType.getAsString()) {
870218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "\\n(" << CanonType.getAsString() << ")";
880218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
890218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
900218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Finished describing the node.
910218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  Out << " \"];\n";
920218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
930218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  // Display the base classes.
941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  const CXXRecordDecl *Decl
956217b80b7a1379b74cced1c076338262c3c980b3Ted Kremenek    = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
96651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (const auto &Base : Decl->bases()) {
97651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    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.
101651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!Base.isVirtual())
1020218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor      ++DirectBaseCount[CanonBaseType];
1030218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1040218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out the node (if we need to).
105651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    WriteNode(Base.getType(), Base.isVirtual());
1060218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1070218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out the edge.
1080218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << "  ";
1090218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    WriteNodeReference(Type, FromVirtual);
1100218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    Out << " -> ";
111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    WriteNodeReference(Base.getType(), Base.isVirtual());
1120218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1130218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    // Write out edge attributes to show the kind of inheritance.
114651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    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.
1245f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnerraw_ostream&
1251eb4433ac451dc16f4133a88af2d002ac26c58efMike StumpInheritanceHierarchyWriter::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}
1340218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1350218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// viewInheritance - Display the inheritance hierarchy of this C++
1360218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor/// class using GraphViz.
1371f81230ac57b9bda8bba9c8221652842ca786132Douglas Gregorvoid CXXRecordDecl::viewInheritance(ASTContext& Context) const {
1380446f51e1c0e16bc9e3f1311967e31ac6dc40babDmitri Gribenko  QualType Self = Context.getTypeDeclType(this);
139653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola
140653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  int FD;
141653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  SmallString<128> Filename;
142ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC =
1431ec4a86a867fc04f35d13bc9e33b04cf2171fe41Rafael Espindola      sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename);
144653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  if (EC) {
145653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola    llvm::errs() << "Error: " << EC.message() << "\n";
1460218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor    return;
1470218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor  }
1480218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
149653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  llvm::errs() << "Writing '" << Filename << "'... ";
1500218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
151653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  llvm::raw_fd_ostream O(FD, true);
1520218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
153653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  InheritanceHierarchyWriter Writer(Context, O);
154653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  Writer.WriteGraph(Self);
155653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  llvm::errs() << " done. \n";
1560218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
157653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  O.close();
158ef165c94cf743c7e5eb6f65bced28cdb9ba118f5Dan Gohman
159653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  // Display the graph
160653c657864a436cfa25ecbf2e03fa0ef1eea36f3Rafael Espindola  DisplayGraph(Filename);
1610218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
1620218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor
1630218936235b137bbdcd29a6c36d61d9215bb4eddDouglas Gregor}
164