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/raw_ostream.h" 00023 #include "llvm/Support/GraphWriter.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 llvm::SmallVector<const FileEntry *, 2> > 00036 DependencyMap; 00037 00038 DependencyMap Dependencies; 00039 00040 private: 00041 llvm::raw_ostream &writeNodeReference(llvm::raw_ostream &OS, 00042 const FileEntry *Node); 00043 void OutputGraphFile(); 00044 00045 public: 00046 DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile, 00047 StringRef SysRoot) 00048 : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { } 00049 00050 virtual void InclusionDirective(SourceLocation HashLoc, 00051 const Token &IncludeTok, 00052 StringRef FileName, 00053 bool IsAngled, 00054 const FileEntry *File, 00055 SourceLocation EndLoc, 00056 StringRef SearchPath, 00057 StringRef RelativePath); 00058 00059 virtual void EndOfMainFile() { 00060 OutputGraphFile(); 00061 } 00062 00063 }; 00064 } 00065 00066 void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, 00067 StringRef SysRoot) { 00068 PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot)); 00069 } 00070 00071 void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, 00072 const Token &IncludeTok, 00073 StringRef FileName, 00074 bool IsAngled, 00075 const FileEntry *File, 00076 SourceLocation EndLoc, 00077 StringRef SearchPath, 00078 StringRef RelativePath) { 00079 if (!File) 00080 return; 00081 00082 SourceManager &SM = PP->getSourceManager(); 00083 const FileEntry *FromFile 00084 = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc))); 00085 if (FromFile == 0) 00086 return; 00087 00088 Dependencies[FromFile].push_back(File); 00089 00090 AllFiles.insert(File); 00091 AllFiles.insert(FromFile); 00092 } 00093 00094 llvm::raw_ostream & 00095 DependencyGraphCallback::writeNodeReference(llvm::raw_ostream &OS, 00096 const FileEntry *Node) { 00097 OS << "header_" << Node->getUID(); 00098 return OS; 00099 } 00100 00101 void DependencyGraphCallback::OutputGraphFile() { 00102 std::string Err; 00103 llvm::raw_fd_ostream OS(OutputFile.c_str(), Err); 00104 if (!Err.empty()) { 00105 PP->getDiagnostics().Report(diag::err_fe_error_opening) 00106 << OutputFile << Err; 00107 return; 00108 } 00109 00110 OS << "digraph \"dependencies\" {\n"; 00111 00112 // Write the nodes 00113 for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) { 00114 // Write the node itself. 00115 OS.indent(2); 00116 writeNodeReference(OS, AllFiles[I]); 00117 OS << " [ shape=\"box\", label=\""; 00118 StringRef FileName = AllFiles[I]->getName(); 00119 if (FileName.startswith(SysRoot)) 00120 FileName = FileName.substr(SysRoot.size()); 00121 00122 OS << DOT::EscapeString(FileName) 00123 << "\"];\n"; 00124 } 00125 00126 // Write the edges 00127 for (DependencyMap::iterator F = Dependencies.begin(), 00128 FEnd = Dependencies.end(); 00129 F != FEnd; ++F) { 00130 for (unsigned I = 0, N = F->second.size(); I != N; ++I) { 00131 OS.indent(2); 00132 writeNodeReference(OS, F->first); 00133 OS << " -> "; 00134 writeNodeReference(OS, F->second[I]); 00135 OS << ";\n"; 00136 } 00137 } 00138 OS << "}\n"; 00139 } 00140