clang API Documentation

DependencyGraph.cpp
Go to the documentation of this file.
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