clang  8.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,
54  SrcMgr::CharacteristicKind FileType) override;
55 
56  void EndOfMainFile() override {
57  OutputGraphFile();
58  }
59 
60 };
61 }
62 
63 void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
64  StringRef SysRoot) {
65  PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile,
66  SysRoot));
67 }
68 
69 void DependencyGraphCallback::InclusionDirective(
70  SourceLocation HashLoc,
71  const Token &IncludeTok,
72  StringRef FileName,
73  bool IsAngled,
74  CharSourceRange FilenameRange,
75  const FileEntry *File,
76  StringRef SearchPath,
77  StringRef RelativePath,
78  const Module *Imported,
79  SrcMgr::CharacteristicKind FileType) {
80  if (!File)
81  return;
82 
83  SourceManager &SM = PP->getSourceManager();
84  const FileEntry *FromFile
85  = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
86  if (!FromFile)
87  return;
88 
89  Dependencies[FromFile].push_back(File);
90 
91  AllFiles.insert(File);
92  AllFiles.insert(FromFile);
93 }
94 
95 raw_ostream &
96 DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
97  const FileEntry *Node) {
98  OS << "header_" << Node->getUID();
99  return OS;
100 }
101 
102 void DependencyGraphCallback::OutputGraphFile() {
103  std::error_code EC;
104  llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
105  if (EC) {
106  PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
107  << EC.message();
108  return;
109  }
110 
111  OS << "digraph \"dependencies\" {\n";
112 
113  // Write the nodes
114  for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
115  // Write the node itself.
116  OS.indent(2);
117  writeNodeReference(OS, AllFiles[I]);
118  OS << " [ shape=\"box\", label=\"";
119  StringRef FileName = AllFiles[I]->getName();
120  if (FileName.startswith(SysRoot))
121  FileName = FileName.substr(SysRoot.size());
122 
123  OS << DOT::EscapeString(FileName)
124  << "\"];\n";
125  }
126 
127  // Write the edges
128  for (DependencyMap::iterator F = Dependencies.begin(),
129  FEnd = Dependencies.end();
130  F != FEnd; ++F) {
131  for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
132  OS.indent(2);
133  writeNodeReference(OS, F->first);
134  OS << " -> ";
135  writeNodeReference(OS, F->second[I]);
136  OS << ";\n";
137  }
138  }
139  OS << "}\n";
140 }
141 
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:78
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:90
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...
return Out str()
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:1490
Encodes a location in the source.
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:60
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:125