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