DependencyGraph.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //===--- DependencyGraph.cpp - Generate dependency file -------------------===//
  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 code generates a header dependency graph in DOT format, for use
  11. // with, e.g., GraphViz.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "clang/Frontend/Utils.h"
  15. #include "clang/Basic/FileManager.h"
  16. #include "clang/Basic/SourceManager.h"
  17. #include "clang/Frontend/FrontendDiagnostic.h"
  18. #include "clang/Lex/PPCallbacks.h"
  19. #include "clang/Lex/Preprocessor.h"
  20. #include "llvm/ADT/SetVector.h"
  21. #include "llvm/Support/raw_ostream.h"
  22. #include "llvm/Support/GraphWriter.h"
  23. using namespace clang;
  24. namespace DOT = llvm::DOT;
  25. namespace {
  26. class DependencyGraphCallback : public PPCallbacks {
  27. const Preprocessor *PP;
  28. std::string OutputFile;
  29. std::string SysRoot;
  30. llvm::SetVector<const FileEntry *> AllFiles;
  31. typedef llvm::DenseMap<const FileEntry *,
  32. llvm::SmallVector<const FileEntry *, 2> >
  33. DependencyMap;
  34. DependencyMap Dependencies;
  35. private:
  36. llvm::raw_ostream &writeNodeReference(llvm::raw_ostream &OS,
  37. const FileEntry *Node);
  38. void OutputGraphFile();
  39. public:
  40. DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
  41. StringRef SysRoot)
  42. : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
  43. virtual void InclusionDirective(SourceLocation HashLoc,
  44. const Token &IncludeTok,
  45. StringRef FileName,
  46. bool IsAngled,
  47. const FileEntry *File,
  48. SourceLocation EndLoc,
  49. StringRef SearchPath,
  50. StringRef RelativePath);
  51. virtual void EndOfMainFile() {
  52. OutputGraphFile();
  53. }
  54. };
  55. }
  56. void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
  57. StringRef SysRoot) {
  58. PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot));
  59. }
  60. void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
  61. const Token &IncludeTok,
  62. StringRef FileName,
  63. bool IsAngled,
  64. const FileEntry *File,
  65. SourceLocation EndLoc,
  66. StringRef SearchPath,
  67. StringRef RelativePath) {
  68. if (!File)
  69. return;
  70. SourceManager &SM = PP->getSourceManager();
  71. const FileEntry *FromFile
  72. = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
  73. if (FromFile == 0)
  74. return;
  75. Dependencies[FromFile].push_back(File);
  76. AllFiles.insert(File);
  77. AllFiles.insert(FromFile);
  78. }
  79. llvm::raw_ostream &
  80. DependencyGraphCallback::writeNodeReference(llvm::raw_ostream &OS,
  81. const FileEntry *Node) {
  82. OS << "header_" << Node->getUID();
  83. return OS;
  84. }
  85. void DependencyGraphCallback::OutputGraphFile() {
  86. std::string Err;
  87. llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
  88. if (!Err.empty()) {
  89. PP->getDiagnostics().Report(diag::err_fe_error_opening)
  90. << OutputFile << Err;
  91. return;
  92. }
  93. OS << "digraph \"dependencies\" {\n";
  94. // Write the nodes
  95. for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
  96. // Write the node itself.
  97. OS.indent(2);
  98. writeNodeReference(OS, AllFiles[I]);
  99. OS << " [ shape=\"box\", label=\"";
  100. StringRef FileName = AllFiles[I]->getName();
  101. if (FileName.startswith(SysRoot))
  102. FileName = FileName.substr(SysRoot.size());
  103. OS << DOT::EscapeString(FileName)
  104. << "\"];\n";
  105. }
  106. // Write the edges
  107. for (DependencyMap::iterator F = Dependencies.begin(),
  108. FEnd = Dependencies.end();
  109. F != FEnd; ++F) {
  110. for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
  111. OS.indent(2);
  112. writeNodeReference(OS, F->first);
  113. OS << " -> ";
  114. writeNodeReference(OS, F->second[I]);
  115. OS << ";\n";
  116. }
  117. }
  118. OS << "}\n";
  119. }