clang  6.0.0svn
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:36
unsigned getUID() const
Definition: FileManager.h:88
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
Describes a module or submodule.
Definition: Module.h:65
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
Represents a character-granular source range.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Defines the clang::Preprocessor interface.
Record the location of an inclusion directive, such as an #include or #import statement.
const SourceManager & SM
Definition: Format.cpp:1337
Encodes a location in the source.
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:59
void AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, StringRef SysRoot)
AttachDependencyGraphGen - Create a dependency graph generator, and attach it to the given preprocess...
ast_type_traits::DynTypedNode Node
Dataflow Directional Tag Classes.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
Defines the PPCallbacks interface.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Definition: Preprocessor.h:908
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:127