xref: /minix3/external/bsd/llvm/dist/clang/lib/Frontend/DependencyGraph.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===--- DependencyGraph.cpp - Generate dependency file -------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This code generates a header dependency graph in DOT format, for use
11f4a2713aSLionel Sambuc // with, e.g., GraphViz.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc 
15f4a2713aSLionel Sambuc #include "clang/Frontend/Utils.h"
16f4a2713aSLionel Sambuc #include "clang/Basic/FileManager.h"
17f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
18f4a2713aSLionel Sambuc #include "clang/Frontend/FrontendDiagnostic.h"
19f4a2713aSLionel Sambuc #include "clang/Lex/PPCallbacks.h"
20f4a2713aSLionel Sambuc #include "clang/Lex/Preprocessor.h"
21f4a2713aSLionel Sambuc #include "llvm/ADT/SetVector.h"
22f4a2713aSLionel Sambuc #include "llvm/Support/GraphWriter.h"
23f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
24f4a2713aSLionel Sambuc 
25f4a2713aSLionel Sambuc using namespace clang;
26f4a2713aSLionel Sambuc namespace DOT = llvm::DOT;
27f4a2713aSLionel Sambuc 
28f4a2713aSLionel Sambuc namespace {
29f4a2713aSLionel Sambuc class DependencyGraphCallback : public PPCallbacks {
30f4a2713aSLionel Sambuc   const Preprocessor *PP;
31f4a2713aSLionel Sambuc   std::string OutputFile;
32f4a2713aSLionel Sambuc   std::string SysRoot;
33f4a2713aSLionel Sambuc   llvm::SetVector<const FileEntry *> AllFiles;
34f4a2713aSLionel Sambuc   typedef llvm::DenseMap<const FileEntry *,
35f4a2713aSLionel Sambuc                          SmallVector<const FileEntry *, 2> > DependencyMap;
36f4a2713aSLionel Sambuc 
37f4a2713aSLionel Sambuc   DependencyMap Dependencies;
38f4a2713aSLionel Sambuc 
39f4a2713aSLionel Sambuc private:
40f4a2713aSLionel Sambuc   raw_ostream &writeNodeReference(raw_ostream &OS,
41f4a2713aSLionel Sambuc                                   const FileEntry *Node);
42f4a2713aSLionel Sambuc   void OutputGraphFile();
43f4a2713aSLionel Sambuc 
44f4a2713aSLionel Sambuc public:
DependencyGraphCallback(const Preprocessor * _PP,StringRef OutputFile,StringRef SysRoot)45f4a2713aSLionel Sambuc   DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
46f4a2713aSLionel Sambuc                           StringRef SysRoot)
47f4a2713aSLionel Sambuc     : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
48f4a2713aSLionel Sambuc 
49*0a6a1f1dSLionel Sambuc   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
50*0a6a1f1dSLionel Sambuc                           StringRef FileName, bool IsAngled,
51*0a6a1f1dSLionel Sambuc                           CharSourceRange FilenameRange, const FileEntry *File,
52*0a6a1f1dSLionel Sambuc                           StringRef SearchPath, StringRef RelativePath,
53*0a6a1f1dSLionel Sambuc                           const Module *Imported) override;
54f4a2713aSLionel Sambuc 
EndOfMainFile()55*0a6a1f1dSLionel Sambuc   void EndOfMainFile() override {
56f4a2713aSLionel Sambuc     OutputGraphFile();
57f4a2713aSLionel Sambuc   }
58f4a2713aSLionel Sambuc 
59f4a2713aSLionel Sambuc };
60f4a2713aSLionel Sambuc }
61f4a2713aSLionel Sambuc 
AttachDependencyGraphGen(Preprocessor & PP,StringRef OutputFile,StringRef SysRoot)62f4a2713aSLionel Sambuc void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
63f4a2713aSLionel Sambuc                                      StringRef SysRoot) {
64*0a6a1f1dSLionel Sambuc   PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile,
65*0a6a1f1dSLionel Sambuc                                                                SysRoot));
66f4a2713aSLionel Sambuc }
67f4a2713aSLionel Sambuc 
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,const FileEntry * File,StringRef SearchPath,StringRef RelativePath,const Module * Imported)68f4a2713aSLionel Sambuc void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
69f4a2713aSLionel Sambuc                                                  const Token &IncludeTok,
70f4a2713aSLionel Sambuc                                                  StringRef FileName,
71f4a2713aSLionel Sambuc                                                  bool IsAngled,
72f4a2713aSLionel Sambuc                                                  CharSourceRange FilenameRange,
73f4a2713aSLionel Sambuc                                                  const FileEntry *File,
74f4a2713aSLionel Sambuc                                                  StringRef SearchPath,
75f4a2713aSLionel Sambuc                                                  StringRef RelativePath,
76f4a2713aSLionel Sambuc                                                  const Module *Imported) {
77f4a2713aSLionel Sambuc   if (!File)
78f4a2713aSLionel Sambuc     return;
79f4a2713aSLionel Sambuc 
80f4a2713aSLionel Sambuc   SourceManager &SM = PP->getSourceManager();
81f4a2713aSLionel Sambuc   const FileEntry *FromFile
82f4a2713aSLionel Sambuc     = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
83*0a6a1f1dSLionel Sambuc   if (!FromFile)
84f4a2713aSLionel Sambuc     return;
85f4a2713aSLionel Sambuc 
86f4a2713aSLionel Sambuc   Dependencies[FromFile].push_back(File);
87f4a2713aSLionel Sambuc 
88f4a2713aSLionel Sambuc   AllFiles.insert(File);
89f4a2713aSLionel Sambuc   AllFiles.insert(FromFile);
90f4a2713aSLionel Sambuc }
91f4a2713aSLionel Sambuc 
92f4a2713aSLionel Sambuc raw_ostream &
writeNodeReference(raw_ostream & OS,const FileEntry * Node)93f4a2713aSLionel Sambuc DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
94f4a2713aSLionel Sambuc                                             const FileEntry *Node) {
95f4a2713aSLionel Sambuc   OS << "header_" << Node->getUID();
96f4a2713aSLionel Sambuc   return OS;
97f4a2713aSLionel Sambuc }
98f4a2713aSLionel Sambuc 
OutputGraphFile()99f4a2713aSLionel Sambuc void DependencyGraphCallback::OutputGraphFile() {
100*0a6a1f1dSLionel Sambuc   std::error_code EC;
101*0a6a1f1dSLionel Sambuc   llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
102*0a6a1f1dSLionel Sambuc   if (EC) {
103*0a6a1f1dSLionel Sambuc     PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
104*0a6a1f1dSLionel Sambuc                                                             << EC.message();
105f4a2713aSLionel Sambuc     return;
106f4a2713aSLionel Sambuc   }
107f4a2713aSLionel Sambuc 
108f4a2713aSLionel Sambuc   OS << "digraph \"dependencies\" {\n";
109f4a2713aSLionel Sambuc 
110f4a2713aSLionel Sambuc   // Write the nodes
111f4a2713aSLionel Sambuc   for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
112f4a2713aSLionel Sambuc     // Write the node itself.
113f4a2713aSLionel Sambuc     OS.indent(2);
114f4a2713aSLionel Sambuc     writeNodeReference(OS, AllFiles[I]);
115f4a2713aSLionel Sambuc     OS << " [ shape=\"box\", label=\"";
116f4a2713aSLionel Sambuc     StringRef FileName = AllFiles[I]->getName();
117f4a2713aSLionel Sambuc     if (FileName.startswith(SysRoot))
118f4a2713aSLionel Sambuc       FileName = FileName.substr(SysRoot.size());
119f4a2713aSLionel Sambuc 
120f4a2713aSLionel Sambuc     OS << DOT::EscapeString(FileName)
121f4a2713aSLionel Sambuc     << "\"];\n";
122f4a2713aSLionel Sambuc   }
123f4a2713aSLionel Sambuc 
124f4a2713aSLionel Sambuc   // Write the edges
125f4a2713aSLionel Sambuc   for (DependencyMap::iterator F = Dependencies.begin(),
126f4a2713aSLionel Sambuc                             FEnd = Dependencies.end();
127f4a2713aSLionel Sambuc        F != FEnd; ++F) {
128f4a2713aSLionel Sambuc     for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
129f4a2713aSLionel Sambuc       OS.indent(2);
130f4a2713aSLionel Sambuc       writeNodeReference(OS, F->first);
131f4a2713aSLionel Sambuc       OS << " -> ";
132f4a2713aSLionel Sambuc       writeNodeReference(OS, F->second[I]);
133f4a2713aSLionel Sambuc       OS << ";\n";
134f4a2713aSLionel Sambuc     }
135f4a2713aSLionel Sambuc   }
136f4a2713aSLionel Sambuc   OS << "}\n";
137f4a2713aSLionel Sambuc }
138f4a2713aSLionel Sambuc 
139