1c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//===--- DependencyGraph.cpp - Generate dependency file -------------------===// 2c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// 3c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// The LLVM Compiler Infrastructure 4c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// 5c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// This file is distributed under the University of Illinois Open Source 6c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// License. See LICENSE.TXT for details. 7c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// 8c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//===----------------------------------------------------------------------===// 9c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// 10773303a505c23d73da624f1e6abcf41a393dad2bDouglas Gregor// This code generates a header dependency graph in DOT format, for use 11773303a505c23d73da624f1e6abcf41a393dad2bDouglas Gregor// with, e.g., GraphViz. 12c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor// 13c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor//===----------------------------------------------------------------------===// 14c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 15c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Frontend/Utils.h" 16c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Basic/FileManager.h" 17c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Basic/SourceManager.h" 18c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Frontend/FrontendDiagnostic.h" 19c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Lex/PPCallbacks.h" 20c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "clang/Lex/Preprocessor.h" 21c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "llvm/ADT/SetVector.h" 22c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor#include "llvm/Support/GraphWriter.h" 2355fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "llvm/Support/raw_ostream.h" 24c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 25c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorusing namespace clang; 26c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregornamespace DOT = llvm::DOT; 27c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 28c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregornamespace { 29c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorclass DependencyGraphCallback : public PPCallbacks { 30c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const Preprocessor *PP; 31c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor std::string OutputFile; 32c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor std::string SysRoot; 33c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor llvm::SetVector<const FileEntry *> AllFiles; 34cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko typedef llvm::DenseMap<const FileEntry *, 35cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko SmallVector<const FileEntry *, 2> > DependencyMap; 36c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 37c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor DependencyMap Dependencies; 38c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 39c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorprivate: 40cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko raw_ostream &writeNodeReference(raw_ostream &OS, 41cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko const FileEntry *Node); 42c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor void OutputGraphFile(); 43c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 44c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorpublic: 45c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile, 46c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef SysRoot) 47c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { } 48c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 49c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor virtual void InclusionDirective(SourceLocation HashLoc, 50c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const Token &IncludeTok, 51c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef FileName, 52c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor bool IsAngled, 53da313592441db36cf4b06be97c4bcc238ee6fa9cArgyrios Kyrtzidis CharSourceRange FilenameRange, 54c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const FileEntry *File, 55c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef SearchPath, 56f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis StringRef RelativePath, 57f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis const Module *Imported); 58c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 59c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor virtual void EndOfMainFile() { 60c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OutputGraphFile(); 61c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor } 62c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 63c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor}; 64c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor} 65c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 66c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorvoid clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, 67c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef SysRoot) { 68c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot)); 69c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor} 70c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 71c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorvoid DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, 72c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const Token &IncludeTok, 73c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef FileName, 74c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor bool IsAngled, 75da313592441db36cf4b06be97c4bcc238ee6fa9cArgyrios Kyrtzidis CharSourceRange FilenameRange, 76c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const FileEntry *File, 77c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef SearchPath, 78f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis StringRef RelativePath, 79f8afcffe6a0213760b64c211812b1750e1e1e967Argyrios Kyrtzidis const Module *Imported) { 80c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor if (!File) 81c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor return; 82c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 83c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor SourceManager &SM = PP->getSourceManager(); 84c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const FileEntry *FromFile 85c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc))); 86c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor if (FromFile == 0) 87c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor return; 88c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 89c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor Dependencies[FromFile].push_back(File); 90c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 91c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor AllFiles.insert(File); 92c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor AllFiles.insert(FromFile); 93c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor} 94c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 95cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenkoraw_ostream & 96cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri GribenkoDependencyGraphCallback::writeNodeReference(raw_ostream &OS, 97c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor const FileEntry *Node) { 98c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << "header_" << Node->getUID(); 99c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor return OS; 100c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor} 101c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 102c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregorvoid DependencyGraphCallback::OutputGraphFile() { 103c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor std::string Err; 104c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor llvm::raw_fd_ostream OS(OutputFile.c_str(), Err); 105c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor if (!Err.empty()) { 106c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor PP->getDiagnostics().Report(diag::err_fe_error_opening) 107c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor << OutputFile << Err; 108c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor return; 109c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor } 110c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 111c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << "digraph \"dependencies\" {\n"; 112c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 113c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor // Write the nodes 114c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) { 115c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor // Write the node itself. 116c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS.indent(2); 117c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor writeNodeReference(OS, AllFiles[I]); 118c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << " [ shape=\"box\", label=\""; 119c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor StringRef FileName = AllFiles[I]->getName(); 120c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor if (FileName.startswith(SysRoot)) 121c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor FileName = FileName.substr(SysRoot.size()); 122c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 123c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << DOT::EscapeString(FileName) 124c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor << "\"];\n"; 125c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor } 126c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 127c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor // Write the edges 128c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor for (DependencyMap::iterator F = Dependencies.begin(), 129c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor FEnd = Dependencies.end(); 130c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor F != FEnd; ++F) { 131c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor for (unsigned I = 0, N = F->second.size(); I != N; ++I) { 132c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS.indent(2); 133c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor writeNodeReference(OS, F->first); 134c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << " -> "; 135c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor writeNodeReference(OS, F->second[I]); 136c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << ";\n"; 137c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor } 138c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor } 139c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor OS << "}\n"; 140c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor} 141c69a181049ab52da29f8f69316a34c90c3ea3b8eDouglas Gregor 142