diff tools/clang/lib/Frontend/DependencyGraph.cpp @ 0:95c75e76d11b LLVM3.4

LLVM 3.4
author Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
date Thu, 12 Dec 2013 13:56:28 +0900
parents
children 54457678186b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/clang/lib/Frontend/DependencyGraph.cpp	Thu Dec 12 13:56:28 2013 +0900
@@ -0,0 +1,141 @@
+//===--- DependencyGraph.cpp - Generate dependency file -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code generates a header dependency graph in DOT format, for use
+// with, e.g., GraphViz.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+namespace DOT = llvm::DOT;
+
+namespace {
+class DependencyGraphCallback : public PPCallbacks {
+  const Preprocessor *PP;
+  std::string OutputFile;
+  std::string SysRoot;
+  llvm::SetVector<const FileEntry *> AllFiles;
+  typedef llvm::DenseMap<const FileEntry *,
+                         SmallVector<const FileEntry *, 2> > DependencyMap;
+  
+  DependencyMap Dependencies;
+  
+private:
+  raw_ostream &writeNodeReference(raw_ostream &OS,
+                                  const FileEntry *Node);
+  void OutputGraphFile();
+
+public:
+  DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
+                          StringRef SysRoot)
+    : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
+
+  virtual void InclusionDirective(SourceLocation HashLoc,
+                                  const Token &IncludeTok,
+                                  StringRef FileName,
+                                  bool IsAngled,
+                                  CharSourceRange FilenameRange,
+                                  const FileEntry *File,
+                                  StringRef SearchPath,
+                                  StringRef RelativePath,
+                                  const Module *Imported);
+
+  virtual void EndOfMainFile() {
+    OutputGraphFile();
+  }
+  
+};
+}
+
+void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
+                                     StringRef SysRoot) {
+  PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot));
+}
+
+void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
+                                                 const Token &IncludeTok,
+                                                 StringRef FileName,
+                                                 bool IsAngled,
+                                                 CharSourceRange FilenameRange,
+                                                 const FileEntry *File,
+                                                 StringRef SearchPath,
+                                                 StringRef RelativePath,
+                                                 const Module *Imported) {
+  if (!File)
+    return;
+  
+  SourceManager &SM = PP->getSourceManager();
+  const FileEntry *FromFile
+    = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
+  if (FromFile == 0) 
+    return;
+
+  Dependencies[FromFile].push_back(File);
+  
+  AllFiles.insert(File);
+  AllFiles.insert(FromFile);
+}
+
+raw_ostream &
+DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
+                                            const FileEntry *Node) {
+  OS << "header_" << Node->getUID();
+  return OS;
+}
+
+void DependencyGraphCallback::OutputGraphFile() {
+  std::string Err;
+  llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
+  if (!Err.empty()) {
+    PP->getDiagnostics().Report(diag::err_fe_error_opening)
+      << OutputFile << Err;
+    return;
+  }
+
+  OS << "digraph \"dependencies\" {\n";
+  
+  // Write the nodes
+  for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
+    // Write the node itself.
+    OS.indent(2);
+    writeNodeReference(OS, AllFiles[I]);
+    OS << " [ shape=\"box\", label=\"";
+    StringRef FileName = AllFiles[I]->getName();
+    if (FileName.startswith(SysRoot))
+      FileName = FileName.substr(SysRoot.size());
+    
+    OS << DOT::EscapeString(FileName)
+    << "\"];\n";
+  }
+
+  // Write the edges
+  for (DependencyMap::iterator F = Dependencies.begin(), 
+                            FEnd = Dependencies.end();
+       F != FEnd; ++F) {    
+    for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
+      OS.indent(2);
+      writeNodeReference(OS, F->first);
+      OS << " -> ";
+      writeNodeReference(OS, F->second[I]);
+      OS << ";\n";
+    }
+  }
+  OS << "}\n";
+}
+