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