clang API Documentation
00001 //===--- DependencyGraph.cpp - Generate dependency file -------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This code generates a header dependency graph in DOT format, for use 00011 // with, e.g., GraphViz. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "clang/Frontend/Utils.h" 00016 #include "clang/Basic/FileManager.h" 00017 #include "clang/Basic/SourceManager.h" 00018 #include "clang/Frontend/FrontendDiagnostic.h" 00019 #include "clang/Lex/PPCallbacks.h" 00020 #include "clang/Lex/Preprocessor.h" 00021 #include "llvm/ADT/SetVector.h" 00022 #include "llvm/Support/GraphWriter.h" 00023 #include "llvm/Support/raw_ostream.h" 00024 00025 using namespace clang; 00026 namespace DOT = llvm::DOT; 00027 00028 namespace { 00029 class DependencyGraphCallback : public PPCallbacks { 00030 const Preprocessor *PP; 00031 std::string OutputFile; 00032 std::string SysRoot; 00033 llvm::SetVector<const FileEntry *> AllFiles; 00034 typedef llvm::DenseMap<const FileEntry *, 00035 SmallVector<const FileEntry *, 2> > DependencyMap; 00036 00037 DependencyMap Dependencies; 00038 00039 private: 00040 raw_ostream &writeNodeReference(raw_ostream &OS, 00041 const FileEntry *Node); 00042 void OutputGraphFile(); 00043 00044 public: 00045 DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile, 00046 StringRef SysRoot) 00047 : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { } 00048 00049 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 00050 StringRef FileName, bool IsAngled, 00051 CharSourceRange FilenameRange, const FileEntry *File, 00052 StringRef SearchPath, StringRef RelativePath, 00053 const Module *Imported) override; 00054 00055 void EndOfMainFile() override { 00056 OutputGraphFile(); 00057 } 00058 00059 }; 00060 } 00061 00062 void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, 00063 StringRef SysRoot) { 00064 PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile, 00065 SysRoot)); 00066 } 00067 00068 void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, 00069 const Token &IncludeTok, 00070 StringRef FileName, 00071 bool IsAngled, 00072 CharSourceRange FilenameRange, 00073 const FileEntry *File, 00074 StringRef SearchPath, 00075 StringRef RelativePath, 00076 const Module *Imported) { 00077 if (!File) 00078 return; 00079 00080 SourceManager &SM = PP->getSourceManager(); 00081 const FileEntry *FromFile 00082 = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc))); 00083 if (!FromFile) 00084 return; 00085 00086 Dependencies[FromFile].push_back(File); 00087 00088 AllFiles.insert(File); 00089 AllFiles.insert(FromFile); 00090 } 00091 00092 raw_ostream & 00093 DependencyGraphCallback::writeNodeReference(raw_ostream &OS, 00094 const FileEntry *Node) { 00095 OS << "header_" << Node->getUID(); 00096 return OS; 00097 } 00098 00099 void DependencyGraphCallback::OutputGraphFile() { 00100 std::error_code EC; 00101 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text); 00102 if (EC) { 00103 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile 00104 << EC.message(); 00105 return; 00106 } 00107 00108 OS << "digraph \"dependencies\" {\n"; 00109 00110 // Write the nodes 00111 for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) { 00112 // Write the node itself. 00113 OS.indent(2); 00114 writeNodeReference(OS, AllFiles[I]); 00115 OS << " [ shape=\"box\", label=\""; 00116 StringRef FileName = AllFiles[I]->getName(); 00117 if (FileName.startswith(SysRoot)) 00118 FileName = FileName.substr(SysRoot.size()); 00119 00120 OS << DOT::EscapeString(FileName) 00121 << "\"];\n"; 00122 } 00123 00124 // Write the edges 00125 for (DependencyMap::iterator F = Dependencies.begin(), 00126 FEnd = Dependencies.end(); 00127 F != FEnd; ++F) { 00128 for (unsigned I = 0, N = F->second.size(); I != N; ++I) { 00129 OS.indent(2); 00130 writeNodeReference(OS, F->first); 00131 OS << " -> "; 00132 writeNodeReference(OS, F->second[I]); 00133 OS << ";\n"; 00134 } 00135 } 00136 OS << "}\n"; 00137 } 00138