llvm-project

Форк
0
/
DependencyGraph.cpp 
154 строки · 5.0 Кб
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This code generates a header dependency graph in DOT format, for use
10
// with, e.g., GraphViz.
11
//
12
//===----------------------------------------------------------------------===//
13

14
#include "clang/Frontend/Utils.h"
15
#include "clang/Basic/FileManager.h"
16
#include "clang/Basic/SourceManager.h"
17
#include "clang/Frontend/FrontendDiagnostic.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

24
using namespace clang;
25
namespace DOT = llvm::DOT;
26

27
namespace {
28
class 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

38
private:
39
  raw_ostream &writeNodeReference(raw_ostream &OS,
40
                                  const FileEntry *Node);
41
  void OutputGraphFile();
42

43
public:
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

67
void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
68
                                     StringRef SysRoot) {
69
  PP.addPPCallbacks(std::make_unique<DependencyGraphCallback>(&PP, OutputFile,
70
                                                               SysRoot));
71
}
72

73
void 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

93
void 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

111
raw_ostream &
112
DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
113
                                            const FileEntry *Node) {
114
  OS << "header_" << Node->getUID();
115
  return OS;
116
}
117

118
void 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) << OutputFile
123
                                                            << EC.message();
124
    return;
125
  }
126

127
  OS << "digraph \"dependencies\" {\n";
128

129
  // Write the nodes
130
  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 edges
142
  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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.