xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Frontend/DependencyGraph.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- DependencyGraph.cpp - Generate dependency file -------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This code generates a header dependency graph in DOT format, for use
107330f729Sjoerg // with, e.g., GraphViz.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
147330f729Sjoerg #include "clang/Frontend/Utils.h"
157330f729Sjoerg #include "clang/Basic/FileManager.h"
167330f729Sjoerg #include "clang/Basic/SourceManager.h"
177330f729Sjoerg #include "clang/Frontend/FrontendDiagnostic.h"
187330f729Sjoerg #include "clang/Lex/PPCallbacks.h"
197330f729Sjoerg #include "clang/Lex/Preprocessor.h"
207330f729Sjoerg #include "llvm/ADT/SetVector.h"
217330f729Sjoerg #include "llvm/Support/GraphWriter.h"
227330f729Sjoerg #include "llvm/Support/raw_ostream.h"
237330f729Sjoerg 
247330f729Sjoerg using namespace clang;
257330f729Sjoerg namespace DOT = llvm::DOT;
267330f729Sjoerg 
277330f729Sjoerg namespace {
287330f729Sjoerg class DependencyGraphCallback : public PPCallbacks {
297330f729Sjoerg   const Preprocessor *PP;
307330f729Sjoerg   std::string OutputFile;
317330f729Sjoerg   std::string SysRoot;
327330f729Sjoerg   llvm::SetVector<const FileEntry *> AllFiles;
337330f729Sjoerg   typedef llvm::DenseMap<const FileEntry *,
347330f729Sjoerg                          SmallVector<const FileEntry *, 2> > DependencyMap;
357330f729Sjoerg 
367330f729Sjoerg   DependencyMap Dependencies;
377330f729Sjoerg 
387330f729Sjoerg private:
397330f729Sjoerg   raw_ostream &writeNodeReference(raw_ostream &OS,
407330f729Sjoerg                                   const FileEntry *Node);
417330f729Sjoerg   void OutputGraphFile();
427330f729Sjoerg 
437330f729Sjoerg public:
DependencyGraphCallback(const Preprocessor * _PP,StringRef OutputFile,StringRef SysRoot)447330f729Sjoerg   DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
457330f729Sjoerg                           StringRef SysRoot)
467330f729Sjoerg     : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
477330f729Sjoerg 
487330f729Sjoerg   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
497330f729Sjoerg                           StringRef FileName, bool IsAngled,
507330f729Sjoerg                           CharSourceRange FilenameRange, const FileEntry *File,
517330f729Sjoerg                           StringRef SearchPath, StringRef RelativePath,
527330f729Sjoerg                           const Module *Imported,
537330f729Sjoerg                           SrcMgr::CharacteristicKind FileType) override;
547330f729Sjoerg 
EndOfMainFile()557330f729Sjoerg   void EndOfMainFile() override {
567330f729Sjoerg     OutputGraphFile();
577330f729Sjoerg   }
587330f729Sjoerg 
597330f729Sjoerg };
607330f729Sjoerg }
617330f729Sjoerg 
AttachDependencyGraphGen(Preprocessor & PP,StringRef OutputFile,StringRef SysRoot)627330f729Sjoerg void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
637330f729Sjoerg                                      StringRef SysRoot) {
647330f729Sjoerg   PP.addPPCallbacks(std::make_unique<DependencyGraphCallback>(&PP, OutputFile,
657330f729Sjoerg                                                                SysRoot));
667330f729Sjoerg }
677330f729Sjoerg 
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,const FileEntry * File,StringRef SearchPath,StringRef RelativePath,const Module * Imported,SrcMgr::CharacteristicKind FileType)687330f729Sjoerg void DependencyGraphCallback::InclusionDirective(
697330f729Sjoerg     SourceLocation HashLoc,
707330f729Sjoerg     const Token &IncludeTok,
717330f729Sjoerg     StringRef FileName,
727330f729Sjoerg     bool IsAngled,
737330f729Sjoerg     CharSourceRange FilenameRange,
747330f729Sjoerg     const FileEntry *File,
757330f729Sjoerg     StringRef SearchPath,
767330f729Sjoerg     StringRef RelativePath,
777330f729Sjoerg     const Module *Imported,
787330f729Sjoerg     SrcMgr::CharacteristicKind FileType) {
797330f729Sjoerg   if (!File)
807330f729Sjoerg     return;
817330f729Sjoerg 
827330f729Sjoerg   SourceManager &SM = PP->getSourceManager();
837330f729Sjoerg   const FileEntry *FromFile
847330f729Sjoerg     = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
857330f729Sjoerg   if (!FromFile)
867330f729Sjoerg     return;
877330f729Sjoerg 
887330f729Sjoerg   Dependencies[FromFile].push_back(File);
897330f729Sjoerg 
907330f729Sjoerg   AllFiles.insert(File);
917330f729Sjoerg   AllFiles.insert(FromFile);
927330f729Sjoerg }
937330f729Sjoerg 
947330f729Sjoerg raw_ostream &
writeNodeReference(raw_ostream & OS,const FileEntry * Node)957330f729Sjoerg DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
967330f729Sjoerg                                             const FileEntry *Node) {
977330f729Sjoerg   OS << "header_" << Node->getUID();
987330f729Sjoerg   return OS;
997330f729Sjoerg }
1007330f729Sjoerg 
OutputGraphFile()1017330f729Sjoerg void DependencyGraphCallback::OutputGraphFile() {
1027330f729Sjoerg   std::error_code EC;
103*e038c9c4Sjoerg   llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
1047330f729Sjoerg   if (EC) {
1057330f729Sjoerg     PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
1067330f729Sjoerg                                                             << EC.message();
1077330f729Sjoerg     return;
1087330f729Sjoerg   }
1097330f729Sjoerg 
1107330f729Sjoerg   OS << "digraph \"dependencies\" {\n";
1117330f729Sjoerg 
1127330f729Sjoerg   // Write the nodes
1137330f729Sjoerg   for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
1147330f729Sjoerg     // Write the node itself.
1157330f729Sjoerg     OS.indent(2);
1167330f729Sjoerg     writeNodeReference(OS, AllFiles[I]);
1177330f729Sjoerg     OS << " [ shape=\"box\", label=\"";
1187330f729Sjoerg     StringRef FileName = AllFiles[I]->getName();
1197330f729Sjoerg     if (FileName.startswith(SysRoot))
1207330f729Sjoerg       FileName = FileName.substr(SysRoot.size());
1217330f729Sjoerg 
122*e038c9c4Sjoerg     OS << DOT::EscapeString(std::string(FileName)) << "\"];\n";
1237330f729Sjoerg   }
1247330f729Sjoerg 
1257330f729Sjoerg   // Write the edges
1267330f729Sjoerg   for (DependencyMap::iterator F = Dependencies.begin(),
1277330f729Sjoerg                             FEnd = Dependencies.end();
1287330f729Sjoerg        F != FEnd; ++F) {
1297330f729Sjoerg     for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
1307330f729Sjoerg       OS.indent(2);
1317330f729Sjoerg       writeNodeReference(OS, F->first);
1327330f729Sjoerg       OS << " -> ";
1337330f729Sjoerg       writeNodeReference(OS, F->second[I]);
1347330f729Sjoerg       OS << ";\n";
1357330f729Sjoerg     }
1367330f729Sjoerg   }
1377330f729Sjoerg   OS << "}\n";
1387330f729Sjoerg }
1397330f729Sjoerg 
140