DependencyGraph.cpp 4.3 KB

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