clang  3.7.0
DependencyGraph.cpp
Go to the documentation of this file.
1 //===--- DependencyGraph.cpp - Generate dependency file -------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This code generates a header dependency graph in DOT format, for use
11 // with, e.g., GraphViz.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/Frontend/Utils.h"
19 #include "clang/Lex/PPCallbacks.h"
20 #include "clang/Lex/Preprocessor.h"
21 #include "llvm/ADT/SetVector.h"
22 #include "llvm/Support/GraphWriter.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace clang;
26 namespace DOT = llvm::DOT;
27 
28 namespace {
29 class DependencyGraphCallback : public PPCallbacks {
30  const Preprocessor *PP;
31  std::string OutputFile;
32  std::string SysRoot;
33  llvm::SetVector<const FileEntry *> AllFiles;
34  typedef llvm::DenseMap<const FileEntry *,
35  SmallVector<const FileEntry *, 2> > DependencyMap;
36 
37  DependencyMap Dependencies;
38 
39 private:
40  raw_ostream &writeNodeReference(raw_ostream &OS,
41  const FileEntry *Node);
42  void OutputGraphFile();
43 
44 public:
45  DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
46  StringRef SysRoot)
47  : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
48 
49  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
50  StringRef FileName, bool IsAngled,
51  CharSourceRange FilenameRange, const FileEntry *File,
52  StringRef SearchPath, StringRef RelativePath,
53  const Module *Imported) override;
54 
55  void EndOfMainFile() override {
56  OutputGraphFile();
57  }
58 
59 };
60 }
61 
62 void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
63  StringRef SysRoot) {
64  PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile,
65  SysRoot));
66 }
67 
68 void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
69  const Token &IncludeTok,
70  StringRef FileName,
71  bool IsAngled,
72  CharSourceRange FilenameRange,
73  const FileEntry *File,
74  StringRef SearchPath,
75  StringRef RelativePath,
76  const Module *Imported) {
77  if (!File)
78  return;
79 
80  SourceManager &SM = PP->getSourceManager();
81  const FileEntry *FromFile
82  = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
83  if (!FromFile)
84  return;
85 
86  Dependencies[FromFile].push_back(File);
87 
88  AllFiles.insert(File);
89  AllFiles.insert(FromFile);
90 }
91 
92 raw_ostream &
93 DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
94  const FileEntry *Node) {
95  OS << "header_" << Node->getUID();
96  return OS;
97 }
98 
99 void DependencyGraphCallback::OutputGraphFile() {
100  std::error_code EC;
101  llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
102  if (EC) {
103  PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
104  << EC.message();
105  return;
106  }
107 
108  OS << "digraph \"dependencies\" {\n";
109 
110  // Write the nodes
111  for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
112  // Write the node itself.
113  OS.indent(2);
114  writeNodeReference(OS, AllFiles[I]);
115  OS << " [ shape=\"box\", label=\"";
116  StringRef FileName = AllFiles[I]->getName();
117  if (FileName.startswith(SysRoot))
118  FileName = FileName.substr(SysRoot.size());
119 
120  OS << DOT::EscapeString(FileName)
121  << "\"];\n";
122  }
123 
124  // Write the edges
125  for (DependencyMap::iterator F = Dependencies.begin(),
126  FEnd = Dependencies.end();
127  F != FEnd; ++F) {
128  for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
129  OS.indent(2);
130  writeNodeReference(OS, F->first);
131  OS << " -> ";
132  writeNodeReference(OS, F->second[I]);
133  OS << ";\n";
134  }
135  }
136  OS << "}\n";
137 }
138 
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
This interface provides a way to observe the actions of the preprocessor as it does its thing...
Definition: PPCallbacks.h:38
Describes a module or submodule.
Definition: Basic/Module.h:49
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceManager & SM
Represents a character-granular source range.
Defines the clang::Preprocessor interface.
Record the location of an inclusion directive, such as an #include or #import statement.
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:53
void AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, StringRef SysRoot)
ast_type_traits::DynTypedNode Node
unsigned getUID() const
Definition: FileManager.h:87
Defines the PPCallbacks interface.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Definition: Preprocessor.h:773
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:96