DependencyGraph.cpp 4.4 KB

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