1 //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// 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 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 10 11 #include "clang/Basic/MakeSupport.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Lex/Preprocessor.h" 14 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 15 #include "llvm/Support/BLAKE3.h" 16 #include "llvm/Support/StringSaver.h" 17 #include <optional> 18 19 using namespace clang; 20 using namespace tooling; 21 using namespace dependencies; 22 23 static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, 24 ASTReader &Reader, 25 const serialization::ModuleFile &MF) { 26 // Only preserve search paths that were used during the dependency scan. 27 std::vector<HeaderSearchOptions::Entry> Entries = Opts.UserEntries; 28 Opts.UserEntries.clear(); 29 30 llvm::BitVector SearchPathUsage(Entries.size()); 31 llvm::DenseSet<const serialization::ModuleFile *> Visited; 32 std::function<void(const serialization::ModuleFile *)> VisitMF = 33 [&](const serialization::ModuleFile *MF) { 34 SearchPathUsage |= MF->SearchPathUsage; 35 Visited.insert(MF); 36 for (const serialization::ModuleFile *Import : MF->Imports) 37 if (!Visited.contains(Import)) 38 VisitMF(Import); 39 }; 40 VisitMF(&MF); 41 42 for (auto Idx : SearchPathUsage.set_bits()) 43 Opts.UserEntries.push_back(Entries[Idx]); 44 } 45 46 static std::vector<std::string> splitString(std::string S, char Separator) { 47 SmallVector<StringRef> Segments; 48 StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false); 49 std::vector<std::string> Result; 50 Result.reserve(Segments.size()); 51 for (StringRef Segment : Segments) 52 Result.push_back(Segment.str()); 53 return Result; 54 } 55 56 void ModuleDepCollector::addOutputPaths(CompilerInvocation &CI, 57 ModuleDeps &Deps) { 58 CI.getFrontendOpts().OutputFile = 59 Controller.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile); 60 if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 61 CI.getDiagnosticOpts().DiagnosticSerializationFile = 62 Controller.lookupModuleOutput( 63 Deps.ID, ModuleOutputKind::DiagnosticSerializationFile); 64 if (!CI.getDependencyOutputOpts().OutputFile.empty()) { 65 CI.getDependencyOutputOpts().OutputFile = Controller.lookupModuleOutput( 66 Deps.ID, ModuleOutputKind::DependencyFile); 67 CI.getDependencyOutputOpts().Targets = 68 splitString(Controller.lookupModuleOutput( 69 Deps.ID, ModuleOutputKind::DependencyTargets), 70 '\0'); 71 if (!CI.getDependencyOutputOpts().OutputFile.empty() && 72 CI.getDependencyOutputOpts().Targets.empty()) { 73 // Fallback to -o as dependency target, as in the driver. 74 SmallString<128> Target; 75 quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target); 76 CI.getDependencyOutputOpts().Targets.push_back(std::string(Target)); 77 } 78 } 79 } 80 81 CompilerInvocation 82 ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs( 83 const ModuleDeps &Deps, 84 llvm::function_ref<void(CompilerInvocation &)> Optimize) const { 85 // Make a deep copy of the original Clang invocation. 86 CompilerInvocation CI(OriginalInvocation); 87 88 CI.resetNonModularOptions(); 89 CI.clearImplicitModuleBuildOptions(); 90 91 // Remove options incompatible with explicit module build or are likely to 92 // differ between identical modules discovered from different translation 93 // units. 94 CI.getFrontendOpts().Inputs.clear(); 95 CI.getFrontendOpts().OutputFile.clear(); 96 97 // TODO: Figure out better way to set options to their default value. 98 CI.getCodeGenOpts().MainFileName.clear(); 99 CI.getCodeGenOpts().DwarfDebugFlags.clear(); 100 if (!CI.getLangOpts()->ModulesCodegen) { 101 CI.getCodeGenOpts().DebugCompilationDir.clear(); 102 CI.getCodeGenOpts().CoverageCompilationDir.clear(); 103 CI.getCodeGenOpts().CoverageDataFile.clear(); 104 CI.getCodeGenOpts().CoverageNotesFile.clear(); 105 } 106 107 // Map output paths that affect behaviour to "-" so their existence is in the 108 // context hash. The final path will be computed in addOutputPaths. 109 if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty()) 110 CI.getDiagnosticOpts().DiagnosticSerializationFile = "-"; 111 if (!CI.getDependencyOutputOpts().OutputFile.empty()) 112 CI.getDependencyOutputOpts().OutputFile = "-"; 113 CI.getDependencyOutputOpts().Targets.clear(); 114 115 CI.getFrontendOpts().ProgramAction = frontend::GenerateModule; 116 CI.getFrontendOpts().ARCMTAction = FrontendOptions::ARCMT_None; 117 CI.getFrontendOpts().ObjCMTAction = FrontendOptions::ObjCMT_None; 118 CI.getFrontendOpts().MTMigrateDir.clear(); 119 CI.getLangOpts()->ModuleName = Deps.ID.ModuleName; 120 CI.getFrontendOpts().IsSystemModule = Deps.IsSystem; 121 122 // Inputs 123 InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(), 124 InputKind::Format::ModuleMap); 125 CI.getFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile, 126 ModuleMapInputKind); 127 128 auto CurrentModuleMapEntry = 129 ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile); 130 assert(CurrentModuleMapEntry && "module map file entry not found"); 131 132 auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps); 133 for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) { 134 // TODO: Track these as `FileEntryRef` to simplify the equality check below. 135 auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile); 136 assert(ModuleMapEntry && "module map file entry not found"); 137 138 // Don't report module maps describing eagerly-loaded dependency. This 139 // information will be deserialized from the PCM. 140 // TODO: Verify this works fine when modulemap for module A is eagerly 141 // loaded from A.pcm, and module map passed on the command line contains 142 // definition of a submodule: "explicit module A.Private { ... }". 143 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry)) 144 continue; 145 146 // Don't report module map file of the current module unless it also 147 // describes a dependency (for symmetry). 148 if (*ModuleMapEntry == *CurrentModuleMapEntry && 149 !DepModuleMapFiles.contains(*ModuleMapEntry)) 150 continue; 151 152 CI.getFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile); 153 } 154 155 // Report the prebuilt modules this module uses. 156 for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) 157 CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); 158 159 // Add module file inputs from dependencies. 160 addModuleFiles(CI, Deps.ClangModuleDeps); 161 162 // Remove any macro definitions that are explicitly ignored. 163 if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) { 164 llvm::erase_if( 165 CI.getPreprocessorOpts().Macros, 166 [&CI](const std::pair<std::string, bool> &Def) { 167 StringRef MacroDef = Def.first; 168 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains( 169 llvm::CachedHashString(MacroDef.split('=').first)); 170 }); 171 // Remove the now unused option. 172 CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear(); 173 } 174 175 Optimize(CI); 176 177 return CI; 178 } 179 180 llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles( 181 ArrayRef<ModuleID> ClangModuleDeps) const { 182 llvm::DenseSet<const FileEntry *> ModuleMapFiles; 183 for (const ModuleID &MID : ClangModuleDeps) { 184 ModuleDeps *MD = ModuleDepsByID.lookup(MID); 185 assert(MD && "Inconsistent dependency info"); 186 // TODO: Track ClangModuleMapFile as `FileEntryRef`. 187 auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile); 188 assert(FE && "Missing module map file that was previously found"); 189 ModuleMapFiles.insert(*FE); 190 } 191 return ModuleMapFiles; 192 } 193 194 void ModuleDepCollector::addModuleMapFiles( 195 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 196 if (EagerLoadModules) 197 return; // Only pcm is needed for eager load. 198 199 for (const ModuleID &MID : ClangModuleDeps) { 200 ModuleDeps *MD = ModuleDepsByID.lookup(MID); 201 assert(MD && "Inconsistent dependency info"); 202 CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile); 203 } 204 } 205 206 void ModuleDepCollector::addModuleFiles( 207 CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const { 208 for (const ModuleID &MID : ClangModuleDeps) { 209 std::string PCMPath = 210 Controller.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); 211 if (EagerLoadModules) 212 CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); 213 else 214 CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert( 215 {MID.ModuleName, std::move(PCMPath)}); 216 } 217 } 218 219 static bool needsModules(FrontendInputFile FIF) { 220 switch (FIF.getKind().getLanguage()) { 221 case Language::Unknown: 222 case Language::Asm: 223 case Language::LLVM_IR: 224 return false; 225 default: 226 return true; 227 } 228 } 229 230 void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) { 231 CI.clearImplicitModuleBuildOptions(); 232 233 if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) { 234 Preprocessor &PP = ScanInstance.getPreprocessor(); 235 if (Module *CurrentModule = PP.getCurrentModuleImplementation()) 236 if (OptionalFileEntryRef CurrentModuleMap = 237 PP.getHeaderSearchInfo() 238 .getModuleMap() 239 .getModuleMapFileForUniquing(CurrentModule)) 240 CI.getFrontendOpts().ModuleMapFiles.emplace_back( 241 CurrentModuleMap->getNameAsRequested()); 242 243 SmallVector<ModuleID> DirectDeps; 244 for (const auto &KV : ModularDeps) 245 if (KV.second->ImportedByMainFile) 246 DirectDeps.push_back(KV.second->ID); 247 248 // TODO: Report module maps the same way it's done for modular dependencies. 249 addModuleMapFiles(CI, DirectDeps); 250 251 addModuleFiles(CI, DirectDeps); 252 253 for (const auto &KV : DirectPrebuiltModularDeps) 254 CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile); 255 } 256 } 257 258 static std::string getModuleContextHash(const ModuleDeps &MD, 259 const CompilerInvocation &CI, 260 bool EagerLoadModules) { 261 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, 262 llvm::support::endianness::native> 263 HashBuilder; 264 SmallString<32> Scratch; 265 266 // Hash the compiler version and serialization version to ensure the module 267 // will be readable. 268 HashBuilder.add(getClangFullRepositoryVersion()); 269 HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); 270 271 // Hash the BuildInvocation without any input files. 272 SmallVector<const char *, 32> Args; 273 llvm::BumpPtrAllocator Alloc; 274 llvm::StringSaver Saver(Alloc); 275 CI.generateCC1CommandLine( 276 Args, [&](const Twine &Arg) { return Saver.save(Arg).data(); }); 277 HashBuilder.addRange(Args); 278 279 // Hash the module dependencies. These paths may differ even if the invocation 280 // is identical if they depend on the contents of the files in the TU -- for 281 // example, case-insensitive paths to modulemap files. Usually such a case 282 // would indicate a missed optimization to canonicalize, but it may be 283 // difficult to canonicalize all cases when there is a VFS. 284 for (const auto &ID : MD.ClangModuleDeps) { 285 HashBuilder.add(ID.ModuleName); 286 HashBuilder.add(ID.ContextHash); 287 } 288 289 HashBuilder.add(EagerLoadModules); 290 291 llvm::BLAKE3Result<16> Hash = HashBuilder.final(); 292 std::array<uint64_t, 2> Words; 293 static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words"); 294 std::memcpy(Words.data(), Hash.data(), sizeof(Hash)); 295 return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false); 296 } 297 298 void ModuleDepCollector::associateWithContextHash(const CompilerInvocation &CI, 299 ModuleDeps &Deps) { 300 Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules); 301 bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second; 302 (void)Inserted; 303 assert(Inserted && "duplicate module mapping"); 304 } 305 306 void ModuleDepCollectorPP::LexedFileChanged(FileID FID, 307 LexedFileChangeReason Reason, 308 SrcMgr::CharacteristicKind FileType, 309 FileID PrevFID, 310 SourceLocation Loc) { 311 if (Reason != LexedFileChangeReason::EnterFile) 312 return; 313 314 // This has to be delayed as the context hash can change at the start of 315 // `CompilerInstance::ExecuteAction`. 316 if (MDC.ContextHash.empty()) { 317 MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash(); 318 MDC.Consumer.handleContextHash(MDC.ContextHash); 319 } 320 321 SourceManager &SM = MDC.ScanInstance.getSourceManager(); 322 323 // Dependency generation really does want to go all the way to the 324 // file entry for a source location to find out what is depended on. 325 // We do not want #line markers to affect dependency generation! 326 if (std::optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(FID)) 327 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename)); 328 } 329 330 void ModuleDepCollectorPP::InclusionDirective( 331 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 332 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, 333 StringRef SearchPath, StringRef RelativePath, const Module *Imported, 334 SrcMgr::CharacteristicKind FileType) { 335 if (!File && !Imported) { 336 // This is a non-modular include that HeaderSearch failed to find. Add it 337 // here as `FileChanged` will never see it. 338 MDC.addFileDep(FileName); 339 } 340 handleImport(Imported); 341 } 342 343 void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, 344 ModuleIdPath Path, 345 const Module *Imported) { 346 if (MDC.ScanInstance.getPreprocessor().isInImportingCXXNamedModules()) { 347 P1689ModuleInfo RequiredModule; 348 RequiredModule.ModuleName = Path[0].first->getName().str(); 349 RequiredModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 350 MDC.RequiredStdCXXModules.push_back(RequiredModule); 351 return; 352 } 353 354 handleImport(Imported); 355 } 356 357 void ModuleDepCollectorPP::handleImport(const Module *Imported) { 358 if (!Imported) 359 return; 360 361 const Module *TopLevelModule = Imported->getTopLevelModule(); 362 363 if (MDC.isPrebuiltModule(TopLevelModule)) 364 MDC.DirectPrebuiltModularDeps.insert( 365 {TopLevelModule, PrebuiltModuleDep{TopLevelModule}}); 366 else 367 DirectModularDeps.insert(TopLevelModule); 368 } 369 370 void ModuleDepCollectorPP::EndOfMainFile() { 371 FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID(); 372 MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager() 373 .getFileEntryForID(MainFileID) 374 ->getName()); 375 376 auto &PP = MDC.ScanInstance.getPreprocessor(); 377 if (PP.isInNamedModule()) { 378 P1689ModuleInfo ProvidedModule; 379 ProvidedModule.ModuleName = PP.getNamedModuleName(); 380 ProvidedModule.Type = P1689ModuleInfo::ModuleType::NamedCXXModule; 381 ProvidedModule.IsStdCXXModuleInterface = PP.isInNamedInterfaceUnit(); 382 // Don't put implementation (non partition) unit as Provide. 383 // Put the module as required instead. Since the implementation 384 // unit will import the primary module implicitly. 385 if (PP.isInImplementationUnit()) 386 MDC.RequiredStdCXXModules.push_back(ProvidedModule); 387 else 388 MDC.ProvidedStdCXXModule = ProvidedModule; 389 } 390 391 if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 392 MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude); 393 394 for (const Module *M : 395 MDC.ScanInstance.getPreprocessor().getAffectingClangModules()) 396 if (!MDC.isPrebuiltModule(M)) 397 DirectModularDeps.insert(M); 398 399 for (const Module *M : DirectModularDeps) 400 handleTopLevelModule(M); 401 402 MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts); 403 404 if (MDC.IsStdModuleP1689Format) 405 MDC.Consumer.handleProvidedAndRequiredStdCXXModules( 406 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules); 407 408 for (auto &&I : MDC.ModularDeps) 409 MDC.Consumer.handleModuleDependency(*I.second); 410 411 for (auto &&I : MDC.FileDeps) 412 MDC.Consumer.handleFileDependency(I); 413 414 for (auto &&I : MDC.DirectPrebuiltModularDeps) 415 MDC.Consumer.handlePrebuiltModuleDependency(I.second); 416 } 417 418 std::optional<ModuleID> 419 ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { 420 assert(M == M->getTopLevelModule() && "Expected top level module!"); 421 422 // A top-level module might not be actually imported as a module when 423 // -fmodule-name is used to compile a translation unit that imports this 424 // module. In that case it can be skipped. The appropriate header 425 // dependencies will still be reported as expected. 426 if (!M->getASTFile()) 427 return {}; 428 429 // If this module has been handled already, just return its ID. 430 auto ModI = MDC.ModularDeps.insert({M, nullptr}); 431 if (!ModI.second) 432 return ModI.first->second->ID; 433 434 ModI.first->second = std::make_unique<ModuleDeps>(); 435 ModuleDeps &MD = *ModI.first->second; 436 437 MD.ID.ModuleName = M->getFullModuleName(); 438 MD.ImportedByMainFile = DirectModularDeps.contains(M); 439 MD.IsSystem = M->IsSystem; 440 441 ModuleMap &ModMapInfo = 442 MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); 443 444 OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M); 445 446 if (ModuleMap) { 447 SmallString<128> Path = ModuleMap->getNameAsRequested(); 448 ModMapInfo.canonicalizeModuleMapPath(Path); 449 MD.ClangModuleMapFile = std::string(Path); 450 } 451 452 serialization::ModuleFile *MF = 453 MDC.ScanInstance.getASTReader()->getModuleManager().lookup( 454 M->getASTFile()); 455 MDC.ScanInstance.getASTReader()->visitInputFiles( 456 *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { 457 // __inferred_module.map is the result of the way in which an implicit 458 // module build handles inferred modules. It adds an overlay VFS with 459 // this file in the proper directory and relies on the rest of Clang to 460 // handle it like normal. With explicitly built modules we don't need 461 // to play VFS tricks, so replace it with the correct module map. 462 if (IF.getFile()->getName().endswith("__inferred_module.map")) { 463 MDC.addFileDep(MD, ModuleMap->getName()); 464 return; 465 } 466 MDC.addFileDep(MD, IF.getFile()->getName()); 467 }); 468 469 llvm::DenseSet<const Module *> SeenDeps; 470 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps); 471 addAllSubmoduleDeps(M, MD, SeenDeps); 472 addAllAffectingClangModules(M, MD, SeenDeps); 473 474 MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps( 475 *MF, [&](FileEntryRef FE) { 476 if (FE.getNameAsRequested().endswith("__inferred_module.map")) 477 return; 478 MD.ModuleMapFileDeps.emplace_back(FE.getNameAsRequested()); 479 }); 480 481 CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs( 482 MD, [&](CompilerInvocation &BuildInvocation) { 483 if (MDC.OptimizeArgs) 484 optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), 485 *MDC.ScanInstance.getASTReader(), *MF); 486 }); 487 488 MDC.associateWithContextHash(CI, MD); 489 490 // Finish the compiler invocation. Requires dependencies and the context hash. 491 MDC.addOutputPaths(CI, MD); 492 493 MD.BuildArguments = CI.getCC1CommandLine(); 494 495 return MD.ID; 496 } 497 498 static void forEachSubmoduleSorted(const Module *M, 499 llvm::function_ref<void(const Module *)> F) { 500 // Submodule order depends on order of header includes for inferred submodules 501 // we don't care about the exact order, so sort so that it's consistent across 502 // TUs to improve sharing. 503 SmallVector<const Module *> Submodules(M->submodules()); 504 llvm::stable_sort(Submodules, [](const Module *A, const Module *B) { 505 return A->Name < B->Name; 506 }); 507 for (const Module *SubM : Submodules) 508 F(SubM); 509 } 510 511 void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps( 512 const Module *M, ModuleDeps &MD, 513 llvm::DenseSet<const Module *> &SeenSubmodules) { 514 addModulePrebuiltDeps(M, MD, SeenSubmodules); 515 516 forEachSubmoduleSorted(M, [&](const Module *SubM) { 517 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules); 518 }); 519 } 520 521 void ModuleDepCollectorPP::addModulePrebuiltDeps( 522 const Module *M, ModuleDeps &MD, 523 llvm::DenseSet<const Module *> &SeenSubmodules) { 524 for (const Module *Import : M->Imports) 525 if (Import->getTopLevelModule() != M->getTopLevelModule()) 526 if (MDC.isPrebuiltModule(Import->getTopLevelModule())) 527 if (SeenSubmodules.insert(Import->getTopLevelModule()).second) 528 MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); 529 } 530 531 void ModuleDepCollectorPP::addAllSubmoduleDeps( 532 const Module *M, ModuleDeps &MD, 533 llvm::DenseSet<const Module *> &AddedModules) { 534 addModuleDep(M, MD, AddedModules); 535 536 forEachSubmoduleSorted(M, [&](const Module *SubM) { 537 addAllSubmoduleDeps(SubM, MD, AddedModules); 538 }); 539 } 540 541 void ModuleDepCollectorPP::addModuleDep( 542 const Module *M, ModuleDeps &MD, 543 llvm::DenseSet<const Module *> &AddedModules) { 544 for (const Module *Import : M->Imports) { 545 if (Import->getTopLevelModule() != M->getTopLevelModule() && 546 !MDC.isPrebuiltModule(Import)) { 547 if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule())) 548 if (AddedModules.insert(Import->getTopLevelModule()).second) 549 MD.ClangModuleDeps.push_back(*ImportID); 550 } 551 } 552 } 553 554 void ModuleDepCollectorPP::addAllAffectingClangModules( 555 const Module *M, ModuleDeps &MD, 556 llvm::DenseSet<const Module *> &AddedModules) { 557 addAffectingClangModule(M, MD, AddedModules); 558 559 for (const Module *SubM : M->submodules()) 560 addAllAffectingClangModules(SubM, MD, AddedModules); 561 } 562 563 void ModuleDepCollectorPP::addAffectingClangModule( 564 const Module *M, ModuleDeps &MD, 565 llvm::DenseSet<const Module *> &AddedModules) { 566 for (const Module *Affecting : M->AffectingClangModules) { 567 assert(Affecting == Affecting->getTopLevelModule() && 568 "Not quite import not top-level module"); 569 if (Affecting != M->getTopLevelModule() && 570 !MDC.isPrebuiltModule(Affecting)) { 571 if (auto ImportID = handleTopLevelModule(Affecting)) 572 if (AddedModules.insert(Affecting).second) 573 MD.ClangModuleDeps.push_back(*ImportID); 574 } 575 } 576 } 577 578 ModuleDepCollector::ModuleDepCollector( 579 std::unique_ptr<DependencyOutputOptions> Opts, 580 CompilerInstance &ScanInstance, DependencyConsumer &C, 581 DependencyActionController &Controller, CompilerInvocation OriginalCI, 582 bool OptimizeArgs, bool EagerLoadModules, bool IsStdModuleP1689Format) 583 : ScanInstance(ScanInstance), Consumer(C), Controller(Controller), 584 Opts(std::move(Opts)), OriginalInvocation(std::move(OriginalCI)), 585 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), 586 IsStdModuleP1689Format(IsStdModuleP1689Format) {} 587 588 void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { 589 PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this)); 590 } 591 592 void ModuleDepCollector::attachToASTReader(ASTReader &R) {} 593 594 bool ModuleDepCollector::isPrebuiltModule(const Module *M) { 595 std::string Name(M->getTopLevelModuleName()); 596 const auto &PrebuiltModuleFiles = 597 ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles; 598 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); 599 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) 600 return false; 601 assert("Prebuilt module came from the expected AST file" && 602 PrebuiltModuleFileIt->second == M->getASTFile()->getName()); 603 return true; 604 } 605 606 static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, 607 SmallVectorImpl<char> &Storage) { 608 if (llvm::sys::path::is_absolute(Path) && 609 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)) 610 return Path; 611 Storage.assign(Path.begin(), Path.end()); 612 CI.getFileManager().makeAbsolutePath(Storage); 613 llvm::sys::path::make_preferred(Storage); 614 return StringRef(Storage.data(), Storage.size()); 615 } 616 617 void ModuleDepCollector::addFileDep(StringRef Path) { 618 llvm::SmallString<256> Storage; 619 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 620 FileDeps.push_back(std::string(Path)); 621 } 622 623 void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) { 624 llvm::SmallString<256> Storage; 625 Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage); 626 MD.FileDeps.insert(Path); 627 } 628