1c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//===--- DependencyGraph.cpp - Generate dependency file -------------------===//
2c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//
3c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//                     The LLVM Compiler Infrastructure
4c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//
5c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// This file is distributed under the University of Illinois Open Source
6c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// License. See LICENSE.TXT for details.
7c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//
8c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//===----------------------------------------------------------------------===//
9c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//
10773303a505c23d73da624f1e6abcf41a393dad2bDouglas Gregor// This code generates a header dependency graph in DOT format, for use
11773303a505c23d73da624f1e6abcf41a393dad2bDouglas Gregor// with, e.g., GraphViz.
12c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//
13c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//===----------------------------------------------------------------------===//
14c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
15c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Frontend/Utils.h"
16c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Basic/FileManager.h"
17c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Basic/SourceManager.h"
18c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Frontend/FrontendDiagnostic.h"
19c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Lex/PPCallbacks.h"
20c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Lex/Preprocessor.h"
21c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "llvm/ADT/SetVector.h"
22c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "llvm/Support/GraphWriter.h"
2355fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "llvm/Support/raw_ostream.h"
24c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
25c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorusing namespace clang;
26c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregornamespace DOT = llvm::DOT;
27c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
28c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregornamespace {
29c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorclass DependencyGraphCallback : public PPCallbacks {
30c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  const Preprocessor *PP;
31c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  std::string OutputFile;
32c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  std::string SysRoot;
33c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  llvm::SetVector<const FileEntry *> AllFiles;
34cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  typedef llvm::DenseMap<const FileEntry *,
35cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko                         SmallVector<const FileEntry *, 2> > DependencyMap;
36c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
37c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  DependencyMap Dependencies;
38c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
39c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorprivate:
40cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  raw_ostream &writeNodeReference(raw_ostream &OS,
41cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko                                  const FileEntry *Node);
42c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  void OutputGraphFile();
43c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
44c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorpublic:
45c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
46c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                          StringRef SysRoot)
47c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
48c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
49c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  virtual void InclusionDirective(SourceLocation HashLoc,
50c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                  const Token &IncludeTok,
51c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                  StringRef FileName,
52c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                  bool IsAngled,
53da313592441db36cf4b06be97c4bcc238ee6fa9cArgyrios Kyrtzidis                                  CharSourceRange FilenameRange,
54c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                  const FileEntry *File,
55c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                  StringRef SearchPath,
56f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis                                  StringRef RelativePath,
57f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis                                  const Module *Imported);
58c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
59c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  virtual void EndOfMainFile() {
60c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    OutputGraphFile();
61c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  }
62c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
63c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor};
64c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor}
65c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
66c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorvoid clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
67c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                     StringRef SysRoot) {
68c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot));
69c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor}
70c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
71c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorvoid DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
72c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                                 const Token &IncludeTok,
73c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                                 StringRef FileName,
74c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                                 bool IsAngled,
75da313592441db36cf4b06be97c4bcc238ee6fa9cArgyrios Kyrtzidis                                                 CharSourceRange FilenameRange,
76c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                                 const FileEntry *File,
77c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                                 StringRef SearchPath,
78f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis                                                 StringRef RelativePath,
79f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis                                                 const Module *Imported) {
80c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  if (!File)
81c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    return;
82c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
83c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  SourceManager &SM = PP->getSourceManager();
84c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  const FileEntry *FromFile
85c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
86c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  if (FromFile == 0)
87c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    return;
88c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
89c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  Dependencies[FromFile].push_back(File);
90c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
91c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  AllFiles.insert(File);
92c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  AllFiles.insert(FromFile);
93c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor}
94c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
95cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenkoraw_ostream &
96cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri GribenkoDependencyGraphCallback::writeNodeReference(raw_ostream &OS,
97c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                                            const FileEntry *Node) {
98c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  OS << "header_" << Node->getUID();
99c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  return OS;
100c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor}
101c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
102c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorvoid DependencyGraphCallback::OutputGraphFile() {
103c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  std::string Err;
104c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
105c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  if (!Err.empty()) {
106c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    PP->getDiagnostics().Report(diag::err_fe_error_opening)
107c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      << OutputFile << Err;
108c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    return;
109c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  }
110c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
111c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  OS << "digraph \"dependencies\" {\n";
112c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
113c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  // Write the nodes
114c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
115c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    // Write the node itself.
116c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    OS.indent(2);
117c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    writeNodeReference(OS, AllFiles[I]);
118c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    OS << " [ shape=\"box\", label=\"";
119c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    StringRef FileName = AllFiles[I]->getName();
120c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    if (FileName.startswith(SysRoot))
121c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      FileName = FileName.substr(SysRoot.size());
122c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
123c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    OS << DOT::EscapeString(FileName)
124c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    << "\"];\n";
125c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  }
126c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
127c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  // Write the edges
128c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  for (DependencyMap::iterator F = Dependencies.begin(),
129c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor                            FEnd = Dependencies.end();
130c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor       F != FEnd; ++F) {
131c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
132c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      OS.indent(2);
133c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      writeNodeReference(OS, F->first);
134c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      OS << " -> ";
135c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      writeNodeReference(OS, F->second[I]);
136c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor      OS << ";\n";
137c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor    }
138c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  }
139c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor  OS << "}\n";
140c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor}
141c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor
142