DependencyGraph.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. //===--- DependencyGraph.cpp - Generate dependency file -------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This code generates a header dependency graph in DOT format, for use
  10. // with, e.g., GraphViz.
  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/GraphWriter.h"
  21. #include "llvm/Support/raw_ostream.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. SmallVector<const FileEntry *, 2> > DependencyMap;
  32. DependencyMap Dependencies;
  33. private:
  34. raw_ostream &writeNodeReference(raw_ostream &OS,
  35. const FileEntry *Node);
  36. void OutputGraphFile();
  37. public:
  38. DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
  39. StringRef SysRoot)
  40. : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
  41. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  42. StringRef FileName, bool IsAngled,
  43. CharSourceRange FilenameRange, const FileEntry *File,
  44. StringRef SearchPath, StringRef RelativePath,
  45. const Module *Imported,
  46. SrcMgr::CharacteristicKind FileType) override;
  47. void EndOfMainFile() override {
  48. OutputGraphFile();
  49. }
  50. };
  51. }
  52. void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
  53. StringRef SysRoot) {
  54. PP.addPPCallbacks(std::make_unique<DependencyGraphCallback>(&PP, OutputFile,
  55. SysRoot));
  56. }
  57. void DependencyGraphCallback::InclusionDirective(
  58. SourceLocation HashLoc,
  59. const Token &IncludeTok,
  60. StringRef FileName,
  61. bool IsAngled,
  62. CharSourceRange FilenameRange,
  63. const FileEntry *File,
  64. StringRef SearchPath,
  65. StringRef RelativePath,
  66. const Module *Imported,
  67. SrcMgr::CharacteristicKind FileType) {
  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)
  74. return;
  75. Dependencies[FromFile].push_back(File);
  76. AllFiles.insert(File);
  77. AllFiles.insert(FromFile);
  78. }
  79. raw_ostream &
  80. DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
  81. const FileEntry *Node) {
  82. OS << "header_" << Node->getUID();
  83. return OS;
  84. }
  85. void DependencyGraphCallback::OutputGraphFile() {
  86. std::error_code EC;
  87. llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
  88. if (EC) {
  89. PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
  90. << EC.message();
  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(std::string(FileName)) << "\"];\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. }