DependencyGraph.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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/GraphWriter.h"
  22. #include "llvm/Support/raw_ostream.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. SmallVector<const FileEntry *, 2> > DependencyMap;
  33. DependencyMap Dependencies;
  34. private:
  35. raw_ostream &writeNodeReference(raw_ostream &OS,
  36. const FileEntry *Node);
  37. void OutputGraphFile();
  38. public:
  39. DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
  40. StringRef SysRoot)
  41. : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
  42. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  43. StringRef FileName, bool IsAngled,
  44. CharSourceRange FilenameRange, const FileEntry *File,
  45. StringRef SearchPath, StringRef RelativePath,
  46. const Module *Imported) override;
  47. void EndOfMainFile() override {
  48. OutputGraphFile();
  49. }
  50. };
  51. }
  52. void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
  53. StringRef SysRoot) {
  54. PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot));
  55. }
  56. void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
  57. const Token &IncludeTok,
  58. StringRef FileName,
  59. bool IsAngled,
  60. CharSourceRange FilenameRange,
  61. const FileEntry *File,
  62. StringRef SearchPath,
  63. StringRef RelativePath,
  64. const Module *Imported) {
  65. if (!File)
  66. return;
  67. SourceManager &SM = PP->getSourceManager();
  68. const FileEntry *FromFile
  69. = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
  70. if (FromFile == 0)
  71. return;
  72. Dependencies[FromFile].push_back(File);
  73. AllFiles.insert(File);
  74. AllFiles.insert(FromFile);
  75. }
  76. raw_ostream &
  77. DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
  78. const FileEntry *Node) {
  79. OS << "header_" << Node->getUID();
  80. return OS;
  81. }
  82. void DependencyGraphCallback::OutputGraphFile() {
  83. std::string Err;
  84. llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text);
  85. if (!Err.empty()) {
  86. PP->getDiagnostics().Report(diag::err_fe_error_opening)
  87. << OutputFile << Err;
  88. return;
  89. }
  90. OS << "digraph \"dependencies\" {\n";
  91. // Write the nodes
  92. for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
  93. // Write the node itself.
  94. OS.indent(2);
  95. writeNodeReference(OS, AllFiles[I]);
  96. OS << " [ shape=\"box\", label=\"";
  97. StringRef FileName = AllFiles[I]->getName();
  98. if (FileName.startswith(SysRoot))
  99. FileName = FileName.substr(SysRoot.size());
  100. OS << DOT::EscapeString(FileName)
  101. << "\"];\n";
  102. }
  103. // Write the edges
  104. for (DependencyMap::iterator F = Dependencies.begin(),
  105. FEnd = Dependencies.end();
  106. F != FEnd; ++F) {
  107. for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
  108. OS.indent(2);
  109. writeNodeReference(OS, F->first);
  110. OS << " -> ";
  111. writeNodeReference(OS, F->second[I]);
  112. OS << ";\n";
  113. }
  114. }
  115. OS << "}\n";
  116. }