DependencyGraph.cpp revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
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 25using namespace clang; 26namespace DOT = llvm::DOT; 27 28namespace { 29class 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 39private: 40 raw_ostream &writeNodeReference(raw_ostream &OS, 41 const FileEntry *Node); 42 void OutputGraphFile(); 43 44public: 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) override; 54 55 void EndOfMainFile() override { 56 OutputGraphFile(); 57 } 58 59}; 60} 61 62void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, 63 StringRef SysRoot) { 64 PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot)); 65} 66 67void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, 68 const Token &IncludeTok, 69 StringRef FileName, 70 bool IsAngled, 71 CharSourceRange FilenameRange, 72 const FileEntry *File, 73 StringRef SearchPath, 74 StringRef RelativePath, 75 const Module *Imported) { 76 if (!File) 77 return; 78 79 SourceManager &SM = PP->getSourceManager(); 80 const FileEntry *FromFile 81 = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc))); 82 if (!FromFile) 83 return; 84 85 Dependencies[FromFile].push_back(File); 86 87 AllFiles.insert(File); 88 AllFiles.insert(FromFile); 89} 90 91raw_ostream & 92DependencyGraphCallback::writeNodeReference(raw_ostream &OS, 93 const FileEntry *Node) { 94 OS << "header_" << Node->getUID(); 95 return OS; 96} 97 98void DependencyGraphCallback::OutputGraphFile() { 99 std::string Err; 100 llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text); 101 if (!Err.empty()) { 102 PP->getDiagnostics().Report(diag::err_fe_error_opening) 103 << OutputFile << Err; 104 return; 105 } 106 107 OS << "digraph \"dependencies\" {\n"; 108 109 // Write the nodes 110 for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) { 111 // Write the node itself. 112 OS.indent(2); 113 writeNodeReference(OS, AllFiles[I]); 114 OS << " [ shape=\"box\", label=\""; 115 StringRef FileName = AllFiles[I]->getName(); 116 if (FileName.startswith(SysRoot)) 117 FileName = FileName.substr(SysRoot.size()); 118 119 OS << DOT::EscapeString(FileName) 120 << "\"];\n"; 121 } 122 123 // Write the edges 124 for (DependencyMap::iterator F = Dependencies.begin(), 125 FEnd = Dependencies.end(); 126 F != FEnd; ++F) { 127 for (unsigned I = 0, N = F->second.size(); I != N; ++I) { 128 OS.indent(2); 129 writeNodeReference(OS, F->first); 130 OS << " -> "; 131 writeNodeReference(OS, F->second[I]); 132 OS << ";\n"; 133 } 134 } 135 OS << "}\n"; 136} 137 138