/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
20 | | std::vector<std::string> ModuleDeps::getFullCommandLine( |
21 | | std::function<StringRef(ClangModuleDep)> LookupPCMPath, |
22 | 3 | std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps) const { |
23 | 3 | 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 | 3 | dependencies::detail::appendCommonModuleArguments( |
29 | 3 | ClangModuleDeps, LookupPCMPath, LookupModuleDeps, Ret); |
30 | | |
31 | 3 | return Ret; |
32 | 3 | } |
33 | | |
34 | | void dependencies::detail::appendCommonModuleArguments( |
35 | | llvm::ArrayRef<ClangModuleDep> Modules, |
36 | | std::function<StringRef(ClangModuleDep)> LookupPCMPath, |
37 | | std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps, |
38 | 7 | std::vector<std::string> &Result) { |
39 | 7 | llvm::StringSet<> AlreadyAdded; |
40 | | |
41 | 7 | std::function<void(llvm::ArrayRef<ClangModuleDep>)> AddArgs = |
42 | 13 | [&](llvm::ArrayRef<ClangModuleDep> Modules) { |
43 | 6 | for (const ClangModuleDep &CMD : Modules) { |
44 | 6 | if (!AlreadyAdded.insert(CMD.ModuleName + CMD.ContextHash).second) |
45 | 0 | continue; |
46 | 6 | const ModuleDeps &M = LookupModuleDeps(CMD); |
47 | | // Depth first traversal. |
48 | 6 | AddArgs(M.ClangModuleDeps); |
49 | 6 | Result.push_back(("-fmodule-file=" + LookupPCMPath(CMD)).str()); |
50 | 6 | if (!M.ClangModuleMapFile.empty()) { |
51 | 6 | Result.push_back("-fmodule-map-file=" + M.ClangModuleMapFile); |
52 | 6 | } |
53 | 6 | } |
54 | 13 | }; |
55 | | |
56 | 7 | Result.push_back("-fno-implicit-modules"); |
57 | 7 | Result.push_back("-fno-implicit-module-maps"); |
58 | 7 | AddArgs(Modules); |
59 | 7 | } |
60 | | |
61 | | void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, |
62 | | FileChangeReason Reason, |
63 | | SrcMgr::CharacteristicKind FileType, |
64 | 24 | FileID PrevFID) { |
65 | 24 | if (Reason != PPCallbacks::EnterFile) |
66 | 12 | return; |
67 | | |
68 | | // This has to be delayed as the context hash can change at the start of |
69 | | // `CompilerInstance::ExecuteAction`. |
70 | 12 | if (MDC.ContextHash.empty()) { |
71 | 4 | MDC.ContextHash = Instance.getInvocation().getModuleHash(); |
72 | 4 | MDC.Consumer.handleContextHash(MDC.ContextHash); |
73 | 4 | } |
74 | | |
75 | 12 | 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 | 12 | if (Optional<StringRef> Filename = |
81 | 4 | SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc)))) |
82 | 4 | MDC.MainDeps.push_back( |
83 | 4 | std::string(llvm::sys::path::remove_leading_dotslash(*Filename))); |
84 | 12 | } |
85 | | |
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 | 4 | SrcMgr::CharacteristicKind FileType) { |
91 | 4 | if (!File && !Imported0 ) { |
92 | | // This is a non-modular include that HeaderSearch failed to find. Add it |
93 | | // here as `FileChanged` will never see it. |
94 | 0 | MDC.MainDeps.push_back(std::string(FileName)); |
95 | 0 | } |
96 | 4 | handleImport(Imported); |
97 | 4 | } |
98 | | |
99 | | void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, |
100 | | ModuleIdPath Path, |
101 | 0 | const Module *Imported) { |
102 | 0 | handleImport(Imported); |
103 | 0 | } |
104 | | |
105 | 4 | void ModuleDepCollectorPP::handleImport(const Module *Imported) { |
106 | 4 | if (!Imported) |
107 | 0 | return; |
108 | | |
109 | 4 | MDC.Deps[MDC.ContextHash + Imported->getTopLevelModule()->getFullModuleName()] |
110 | 4 | .ImportedByMainFile = true; |
111 | 4 | DirectDeps.insert(Imported->getTopLevelModule()); |
112 | 4 | } |
113 | | |
114 | 4 | void ModuleDepCollectorPP::EndOfMainFile() { |
115 | 4 | FileID MainFileID = Instance.getSourceManager().getMainFileID(); |
116 | 4 | MDC.MainFile = std::string( |
117 | 4 | Instance.getSourceManager().getFileEntryForID(MainFileID)->getName()); |
118 | | |
119 | 4 | for (const Module *M : DirectDeps) { |
120 | 4 | handleTopLevelModule(M); |
121 | 4 | } |
122 | | |
123 | 4 | for (auto &&I : MDC.Deps) |
124 | 5 | MDC.Consumer.handleModuleDependency(I.second); |
125 | | |
126 | 4 | for (auto &&I : MDC.MainDeps) |
127 | 4 | MDC.Consumer.handleFileDependency(*MDC.Opts, I); |
128 | 4 | } |
129 | | |
130 | 5 | void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { |
131 | 5 | assert(M == M->getTopLevelModule() && "Expected top level module!"); |
132 | | |
133 | 5 | auto ModI = MDC.Deps.insert( |
134 | 5 | std::make_pair(MDC.ContextHash + M->getFullModuleName(), ModuleDeps{})); |
135 | | |
136 | 5 | if (!ModI.first->second.ModuleName.empty()) |
137 | 0 | return; |
138 | | |
139 | 5 | ModuleDeps &MD = ModI.first->second; |
140 | | |
141 | 5 | const FileEntry *ModuleMap = Instance.getPreprocessor() |
142 | 5 | .getHeaderSearchInfo() |
143 | 5 | .getModuleMap() |
144 | 5 | .getContainingModuleMapFile(M); |
145 | | |
146 | 5 | MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : ""0 ); |
147 | 5 | MD.ModuleName = M->getFullModuleName(); |
148 | 5 | MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName()); |
149 | 5 | MD.ContextHash = MDC.ContextHash; |
150 | 5 | serialization::ModuleFile *MF = |
151 | 5 | MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile()); |
152 | 5 | MDC.Instance.getASTReader()->visitInputFiles( |
153 | 10 | *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { |
154 | 10 | MD.FileDeps.insert(IF.getFile()->getName()); |
155 | 10 | }); |
156 | | |
157 | 5 | llvm::DenseSet<const Module *> AddedModules; |
158 | 5 | addAllSubmoduleDeps(M, MD, AddedModules); |
159 | 5 | } |
160 | | |
161 | | void ModuleDepCollectorPP::addAllSubmoduleDeps( |
162 | | const Module *M, ModuleDeps &MD, |
163 | 5 | llvm::DenseSet<const Module *> &AddedModules) { |
164 | 5 | addModuleDep(M, MD, AddedModules); |
165 | | |
166 | 5 | for (const Module *SubM : M->submodules()) |
167 | 0 | addAllSubmoduleDeps(SubM, MD, AddedModules); |
168 | 5 | } |
169 | | |
170 | | void ModuleDepCollectorPP::addModuleDep( |
171 | | const Module *M, ModuleDeps &MD, |
172 | 5 | llvm::DenseSet<const Module *> &AddedModules) { |
173 | 1 | for (const Module *Import : M->Imports) { |
174 | 1 | if (Import->getTopLevelModule() != M->getTopLevelModule()) { |
175 | 1 | if (AddedModules.insert(Import->getTopLevelModule()).second) |
176 | 1 | MD.ClangModuleDeps.push_back( |
177 | 1 | {std::string(Import->getTopLevelModuleName()), |
178 | 1 | Instance.getInvocation().getModuleHash()}); |
179 | 1 | handleTopLevelModule(Import->getTopLevelModule()); |
180 | 1 | } |
181 | 1 | } |
182 | 5 | } |
183 | | |
184 | | ModuleDepCollector::ModuleDepCollector( |
185 | | std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I, |
186 | | DependencyConsumer &C) |
187 | 2 | : Instance(I), Consumer(C), Opts(std::move(Opts)) {} |
188 | | |
189 | 4 | void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { |
190 | 4 | PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this)); |
191 | 4 | } |
192 | | |
193 | 4 | void ModuleDepCollector::attachToASTReader(ASTReader &R) {} |