brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.0 KiB · 80c187a Raw
156 lines · cpp
1//===--- DependencyGraph.cpp - Generate dependency file -------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This code generates a header dependency graph in DOT format, for use10// with, e.g., GraphViz.11//12//===----------------------------------------------------------------------===//13 14#include "clang/Basic/DiagnosticFrontend.h"15#include "clang/Basic/FileManager.h"16#include "clang/Basic/SourceManager.h"17#include "clang/Frontend/Utils.h"18#include "clang/Lex/PPCallbacks.h"19#include "clang/Lex/Preprocessor.h"20#include "llvm/ADT/SetVector.h"21#include "llvm/Support/GraphWriter.h"22#include "llvm/Support/raw_ostream.h"23 24using namespace clang;25namespace DOT = llvm::DOT;26 27namespace {28class DependencyGraphCallback : public PPCallbacks {29  const Preprocessor *PP;30  std::string OutputFile;31  std::string SysRoot;32  llvm::SetVector<FileEntryRef> AllFiles;33  using DependencyMap =34      llvm::DenseMap<FileEntryRef, SmallVector<FileEntryRef, 2>>;35 36  DependencyMap Dependencies;37 38private:39  raw_ostream &writeNodeReference(raw_ostream &OS,40                                  const FileEntry *Node);41  void OutputGraphFile();42 43public:44  DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,45                          StringRef SysRoot)46      : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) {}47 48  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,49                          StringRef FileName, bool IsAngled,50                          CharSourceRange FilenameRange,51                          OptionalFileEntryRef File, StringRef SearchPath,52                          StringRef RelativePath, const Module *SuggestedModule,53                          bool ModuleImported,54                          SrcMgr::CharacteristicKind FileType) override;55 56  void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled,57                      OptionalFileEntryRef File,58                      const LexEmbedParametersResult &Params) override;59 60  void EndOfMainFile() override {61    OutputGraphFile();62  }63 64};65}66 67void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,68                                     StringRef SysRoot) {69  PP.addPPCallbacks(std::make_unique<DependencyGraphCallback>(&PP, OutputFile,70                                                               SysRoot));71}72 73void DependencyGraphCallback::InclusionDirective(74    SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,75    bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,76    StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,77    bool ModuleImported, SrcMgr::CharacteristicKind FileType) {78  if (!File)79    return;80 81  SourceManager &SM = PP->getSourceManager();82  OptionalFileEntryRef FromFile =83      SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));84  if (!FromFile)85    return;86 87  Dependencies[*FromFile].push_back(*File);88 89  AllFiles.insert(*File);90  AllFiles.insert(*FromFile);91}92 93void DependencyGraphCallback::EmbedDirective(SourceLocation HashLoc, StringRef,94                                             bool, OptionalFileEntryRef File,95                                             const LexEmbedParametersResult &) {96  if (!File)97    return;98 99  SourceManager &SM = PP->getSourceManager();100  OptionalFileEntryRef FromFile =101      SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));102  if (!FromFile)103    return;104 105  Dependencies[*FromFile].push_back(*File);106 107  AllFiles.insert(*File);108  AllFiles.insert(*FromFile);109}110 111raw_ostream &112DependencyGraphCallback::writeNodeReference(raw_ostream &OS,113                                            const FileEntry *Node) {114  OS << "header_" << Node->getUID();115  return OS;116}117 118void DependencyGraphCallback::OutputGraphFile() {119  std::error_code EC;120  llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);121  if (EC) {122    PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile123                                                            << EC.message();124    return;125  }126 127  OS << "digraph \"dependencies\" {\n";128 129  // Write the nodes130  for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {131    // Write the node itself.132    OS.indent(2);133    writeNodeReference(OS, AllFiles[I]);134    OS << " [ shape=\"box\", label=\"";135    StringRef FileName = AllFiles[I].getName();136    FileName.consume_front(SysRoot);137 138    OS << DOT::EscapeString(std::string(FileName)) << "\"];\n";139  }140 141  // Write the edges142  for (DependencyMap::iterator F = Dependencies.begin(),143                            FEnd = Dependencies.end();144       F != FEnd; ++F) {145    for (unsigned I = 0, N = F->second.size(); I != N; ++I) {146      OS.indent(2);147      writeNodeReference(OS, F->first);148      OS << " -> ";149      writeNodeReference(OS, F->second[I]);150      OS << ";\n";151    }152  }153  OS << "}\n";154}155 156