1 //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
11
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
15
16 using namespace clang;
17 using namespace tooling;
18 using namespace dependencies;
19
getFullCommandLine(std::function<StringRef (ClangModuleDep)> LookupPCMPath,std::function<const ModuleDeps & (ClangModuleDep)> LookupModuleDeps) const20 std::vector<std::string> ModuleDeps::getFullCommandLine(
21 std::function<StringRef(ClangModuleDep)> LookupPCMPath,
22 std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps) const {
23 std::vector<std::string> Ret = NonPathCommandLine;
24
25 // TODO: Build full command line. That also means capturing the original
26 // command line into NonPathCommandLine.
27
28 dependencies::detail::appendCommonModuleArguments(
29 ClangModuleDeps, LookupPCMPath, LookupModuleDeps, Ret);
30
31 return Ret;
32 }
33
appendCommonModuleArguments(llvm::ArrayRef<ClangModuleDep> Modules,std::function<StringRef (ClangModuleDep)> LookupPCMPath,std::function<const ModuleDeps & (ClangModuleDep)> LookupModuleDeps,std::vector<std::string> & Result)34 void dependencies::detail::appendCommonModuleArguments(
35 llvm::ArrayRef<ClangModuleDep> Modules,
36 std::function<StringRef(ClangModuleDep)> LookupPCMPath,
37 std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps,
38 std::vector<std::string> &Result) {
39 llvm::StringSet<> AlreadyAdded;
40
41 std::function<void(llvm::ArrayRef<ClangModuleDep>)> AddArgs =
42 [&](llvm::ArrayRef<ClangModuleDep> Modules) {
43 for (const ClangModuleDep &CMD : Modules) {
44 if (!AlreadyAdded.insert(CMD.ModuleName + CMD.ContextHash).second)
45 continue;
46 const ModuleDeps &M = LookupModuleDeps(CMD);
47 // Depth first traversal.
48 AddArgs(M.ClangModuleDeps);
49 Result.push_back(("-fmodule-file=" + LookupPCMPath(CMD)).str());
50 if (!M.ClangModuleMapFile.empty()) {
51 Result.push_back("-fmodule-map-file=" + M.ClangModuleMapFile);
52 }
53 }
54 };
55
56 Result.push_back("-fno-implicit-modules");
57 Result.push_back("-fno-implicit-module-maps");
58 AddArgs(Modules);
59 }
60
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)61 void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
62 FileChangeReason Reason,
63 SrcMgr::CharacteristicKind FileType,
64 FileID PrevFID) {
65 if (Reason != PPCallbacks::EnterFile)
66 return;
67
68 // This has to be delayed as the context hash can change at the start of
69 // `CompilerInstance::ExecuteAction`.
70 if (MDC.ContextHash.empty()) {
71 MDC.ContextHash = Instance.getInvocation().getModuleHash();
72 MDC.Consumer.handleContextHash(MDC.ContextHash);
73 }
74
75 SourceManager &SM = Instance.getSourceManager();
76
77 // Dependency generation really does want to go all the way to the
78 // file entry for a source location to find out what is depended on.
79 // We do not want #line markers to affect dependency generation!
80 if (Optional<StringRef> Filename =
81 SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc))))
82 MDC.MainDeps.push_back(
83 std::string(llvm::sys::path::remove_leading_dotslash(*Filename)));
84 }
85
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)86 void ModuleDepCollectorPP::InclusionDirective(
87 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
88 bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
89 StringRef SearchPath, StringRef RelativePath, const Module *Imported,
90 SrcMgr::CharacteristicKind FileType) {
91 if (!File && !Imported) {
92 // This is a non-modular include that HeaderSearch failed to find. Add it
93 // here as `FileChanged` will never see it.
94 MDC.MainDeps.push_back(std::string(FileName));
95 }
96 handleImport(Imported);
97 }
98
moduleImport(SourceLocation ImportLoc,ModuleIdPath Path,const Module * Imported)99 void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc,
100 ModuleIdPath Path,
101 const Module *Imported) {
102 handleImport(Imported);
103 }
104
handleImport(const Module * Imported)105 void ModuleDepCollectorPP::handleImport(const Module *Imported) {
106 if (!Imported)
107 return;
108
109 MDC.Deps[MDC.ContextHash + Imported->getTopLevelModule()->getFullModuleName()]
110 .ImportedByMainFile = true;
111 DirectDeps.insert(Imported->getTopLevelModule());
112 }
113
EndOfMainFile()114 void ModuleDepCollectorPP::EndOfMainFile() {
115 FileID MainFileID = Instance.getSourceManager().getMainFileID();
116 MDC.MainFile = std::string(
117 Instance.getSourceManager().getFileEntryForID(MainFileID)->getName());
118
119 for (const Module *M : DirectDeps) {
120 handleTopLevelModule(M);
121 }
122
123 for (auto &&I : MDC.Deps)
124 MDC.Consumer.handleModuleDependency(I.second);
125
126 for (auto &&I : MDC.MainDeps)
127 MDC.Consumer.handleFileDependency(*MDC.Opts, I);
128 }
129
handleTopLevelModule(const Module * M)130 void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
131 assert(M == M->getTopLevelModule() && "Expected top level module!");
132
133 auto ModI = MDC.Deps.insert(
134 std::make_pair(MDC.ContextHash + M->getFullModuleName(), ModuleDeps{}));
135
136 if (!ModI.first->second.ModuleName.empty())
137 return;
138
139 ModuleDeps &MD = ModI.first->second;
140
141 const FileEntry *ModuleMap = Instance.getPreprocessor()
142 .getHeaderSearchInfo()
143 .getModuleMap()
144 .getContainingModuleMapFile(M);
145
146 MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : "");
147 MD.ModuleName = M->getFullModuleName();
148 MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
149 MD.ContextHash = MDC.ContextHash;
150 serialization::ModuleFile *MF =
151 MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
152 MDC.Instance.getASTReader()->visitInputFiles(
153 *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) {
154 MD.FileDeps.insert(IF.getFile()->getName());
155 });
156
157 llvm::DenseSet<const Module *> AddedModules;
158 addAllSubmoduleDeps(M, MD, AddedModules);
159 }
160
addAllSubmoduleDeps(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & AddedModules)161 void ModuleDepCollectorPP::addAllSubmoduleDeps(
162 const Module *M, ModuleDeps &MD,
163 llvm::DenseSet<const Module *> &AddedModules) {
164 addModuleDep(M, MD, AddedModules);
165
166 for (const Module *SubM : M->submodules())
167 addAllSubmoduleDeps(SubM, MD, AddedModules);
168 }
169
addModuleDep(const Module * M,ModuleDeps & MD,llvm::DenseSet<const Module * > & AddedModules)170 void ModuleDepCollectorPP::addModuleDep(
171 const Module *M, ModuleDeps &MD,
172 llvm::DenseSet<const Module *> &AddedModules) {
173 for (const Module *Import : M->Imports) {
174 if (Import->getTopLevelModule() != M->getTopLevelModule()) {
175 if (AddedModules.insert(Import->getTopLevelModule()).second)
176 MD.ClangModuleDeps.push_back(
177 {std::string(Import->getTopLevelModuleName()),
178 Instance.getInvocation().getModuleHash()});
179 handleTopLevelModule(Import->getTopLevelModule());
180 }
181 }
182 }
183
ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,CompilerInstance & I,DependencyConsumer & C)184 ModuleDepCollector::ModuleDepCollector(
185 std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I,
186 DependencyConsumer &C)
187 : Instance(I), Consumer(C), Opts(std::move(Opts)) {}
188
attachToPreprocessor(Preprocessor & PP)189 void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
190 PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this));
191 }
192
attachToASTReader(ASTReader & R)193 void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
194