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 15 #include "clang/Frontend/Utils.h" 16 #include "clang/Basic/FileManager.h" 17 #include "clang/Basic/SourceManager.h" 18 #include "clang/Frontend/FrontendDiagnostic.h" 19 #include "clang/Lex/PPCallbacks.h" 20 #include "clang/Lex/Preprocessor.h" 21 #include "llvm/ADT/SetVector.h" 22 #include "llvm/Support/GraphWriter.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 using namespace clang; 26 namespace DOT = llvm::DOT; 27 28 namespace { 29 class DependencyGraphCallback : public PPCallbacks { 30 const Preprocessor *PP; 31 std::string OutputFile; 32 std::string SysRoot; 33 llvm::SetVector<const FileEntry *> AllFiles; 34 typedef llvm::DenseMap<const FileEntry *, 35 SmallVector<const FileEntry *, 2> > DependencyMap; 36 37 DependencyMap Dependencies; 38 39 private: 40 raw_ostream &writeNodeReference(raw_ostream &OS, 41 const FileEntry *Node); 42 void OutputGraphFile(); 43 44 public: 45 DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile, 46 StringRef SysRoot) 47 : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { } 48 49 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 50 StringRef FileName, bool IsAngled, 51 CharSourceRange FilenameRange, const FileEntry *File, 52 StringRef SearchPath, StringRef RelativePath, 53 const Module *Imported, 54 SrcMgr::CharacteristicKind FileType) override; 55 56 void EndOfMainFile() override { 57 OutputGraphFile(); 58 } 59 60 }; 61 } 62 63 void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, 64 StringRef SysRoot) { 65 PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile, 66 SysRoot)); 67 } 68 69 void DependencyGraphCallback::InclusionDirective( 70 SourceLocation HashLoc, 71 const Token &IncludeTok, 72 StringRef FileName, 73 bool IsAngled, 74 CharSourceRange FilenameRange, 75 const FileEntry *File, 76 StringRef SearchPath, 77 StringRef RelativePath, 78 const Module *Imported, 79 SrcMgr::CharacteristicKind FileType) { 80 if (!File) 81 return; 82 83 SourceManager &SM = PP->getSourceManager(); 84 const FileEntry *FromFile 85 = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc))); 86 if (!FromFile) 87 return; 88 89 Dependencies[FromFile].push_back(File); 90 91 AllFiles.insert(File); 92 AllFiles.insert(FromFile); 93 } 94 95 raw_ostream & 96 DependencyGraphCallback::writeNodeReference(raw_ostream &OS, 97 const FileEntry *Node) { 98 OS << "header_" << Node->getUID(); 99 return OS; 100 } 101 102 void DependencyGraphCallback::OutputGraphFile() { 103 std::error_code EC; 104 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text); 105 if (EC) { 106 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile 107 << EC.message(); 108 return; 109 } 110 111 OS << "digraph \"dependencies\" {\n"; 112 113 // Write the nodes 114 for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) { 115 // Write the node itself. 116 OS.indent(2); 117 writeNodeReference(OS, AllFiles[I]); 118 OS << " [ shape=\"box\", label=\""; 119 StringRef FileName = AllFiles[I]->getName(); 120 if (FileName.startswith(SysRoot)) 121 FileName = FileName.substr(SysRoot.size()); 122 123 OS << DOT::EscapeString(FileName) 124 << "\"];\n"; 125 } 126 127 // Write the edges 128 for (DependencyMap::iterator F = Dependencies.begin(), 129 FEnd = Dependencies.end(); 130 F != FEnd; ++F) { 131 for (unsigned I = 0, N = F->second.size(); I != N; ++I) { 132 OS.indent(2); 133 writeNodeReference(OS, F->first); 134 OS << " -> "; 135 writeNodeReference(OS, F->second[I]); 136 OS << ";\n"; 137 } 138 } 139 OS << "}\n"; 140 } 141 142