1480093f4SDimitry Andric //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // The LLVM Compiler Infrastructure 4480093f4SDimitry Andric // 5480093f4SDimitry Andric // This file is distributed under the University of Illinois Open Source 6480093f4SDimitry Andric // License. See LICENSE.TXT for details. 7480093f4SDimitry Andric // 8480093f4SDimitry Andric //===----------------------------------------------------------------------===// 9480093f4SDimitry Andric 10480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 11480093f4SDimitry Andric 12480093f4SDimitry Andric #include "clang/Frontend/CompilerInstance.h" 13480093f4SDimitry Andric #include "clang/Lex/Preprocessor.h" 14480093f4SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 15*fe6060f1SDimitry Andric #include "llvm/Support/StringSaver.h" 16480093f4SDimitry Andric 17480093f4SDimitry Andric using namespace clang; 18480093f4SDimitry Andric using namespace tooling; 19480093f4SDimitry Andric using namespace dependencies; 20480093f4SDimitry Andric 21*fe6060f1SDimitry Andric CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths( 22*fe6060f1SDimitry Andric const ModuleDeps &Deps) const { 23*fe6060f1SDimitry Andric // Make a deep copy of the original Clang invocation. 24*fe6060f1SDimitry Andric CompilerInvocation CI(OriginalInvocation); 255ffd83dbSDimitry Andric 26*fe6060f1SDimitry Andric // Remove options incompatible with explicit module build. 27*fe6060f1SDimitry Andric CI.getFrontendOpts().Inputs.clear(); 28*fe6060f1SDimitry Andric CI.getFrontendOpts().OutputFile.clear(); 295ffd83dbSDimitry Andric 30*fe6060f1SDimitry Andric CI.getFrontendOpts().ProgramAction = frontend::GenerateModule; 31*fe6060f1SDimitry Andric CI.getLangOpts()->ModuleName = Deps.ID.ModuleName; 32*fe6060f1SDimitry Andric CI.getFrontendOpts().IsSystemModule = Deps.IsSystem; 335ffd83dbSDimitry Andric 34*fe6060f1SDimitry Andric CI.getLangOpts()->ImplicitModules = false; 35*fe6060f1SDimitry Andric 36*fe6060f1SDimitry Andric // Report the prebuilt modules this module uses. 37*fe6060f1SDimitry Andric for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) { 38*fe6060f1SDimitry Andric CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); 39*fe6060f1SDimitry Andric CI.getFrontendOpts().ModuleMapFiles.push_back(PrebuiltModule.ModuleMapFile); 405ffd83dbSDimitry Andric } 415ffd83dbSDimitry Andric 42*fe6060f1SDimitry Andric CI.getPreprocessorOpts().ImplicitPCHInclude.clear(); 43*fe6060f1SDimitry Andric 44*fe6060f1SDimitry Andric return CI; 45*fe6060f1SDimitry Andric } 46*fe6060f1SDimitry Andric 47*fe6060f1SDimitry Andric static std::vector<std::string> 48*fe6060f1SDimitry Andric serializeCompilerInvocation(const CompilerInvocation &CI) { 49*fe6060f1SDimitry Andric // Set up string allocator. 50*fe6060f1SDimitry Andric llvm::BumpPtrAllocator Alloc; 51*fe6060f1SDimitry Andric llvm::StringSaver Strings(Alloc); 52*fe6060f1SDimitry Andric auto SA = [&Strings](const Twine &Arg) { return Strings.save(Arg).data(); }; 53*fe6060f1SDimitry Andric 54*fe6060f1SDimitry Andric // Synthesize full command line from the CompilerInvocation, including "-cc1". 55*fe6060f1SDimitry Andric SmallVector<const char *, 32> Args{"-cc1"}; 56*fe6060f1SDimitry Andric CI.generateCC1CommandLine(Args, SA); 57*fe6060f1SDimitry Andric 58*fe6060f1SDimitry Andric // Convert arguments to the return type. 59*fe6060f1SDimitry Andric return std::vector<std::string>{Args.begin(), Args.end()}; 60*fe6060f1SDimitry Andric } 61*fe6060f1SDimitry Andric 62*fe6060f1SDimitry Andric std::vector<std::string> ModuleDeps::getCanonicalCommandLine( 63*fe6060f1SDimitry Andric std::function<StringRef(ModuleID)> LookupPCMPath, 64*fe6060f1SDimitry Andric std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const { 65*fe6060f1SDimitry Andric CompilerInvocation CI(Invocation); 66*fe6060f1SDimitry Andric FrontendOptions &FrontendOpts = CI.getFrontendOpts(); 67*fe6060f1SDimitry Andric 68*fe6060f1SDimitry Andric InputKind ModuleMapInputKind(FrontendOpts.DashX.getLanguage(), 69*fe6060f1SDimitry Andric InputKind::Format::ModuleMap); 70*fe6060f1SDimitry Andric FrontendOpts.Inputs.emplace_back(ClangModuleMapFile, ModuleMapInputKind); 71*fe6060f1SDimitry Andric FrontendOpts.OutputFile = std::string(LookupPCMPath(ID)); 72*fe6060f1SDimitry Andric 73*fe6060f1SDimitry Andric dependencies::detail::collectPCMAndModuleMapPaths( 74*fe6060f1SDimitry Andric ClangModuleDeps, LookupPCMPath, LookupModuleDeps, 75*fe6060f1SDimitry Andric FrontendOpts.ModuleFiles, FrontendOpts.ModuleMapFiles); 76*fe6060f1SDimitry Andric 77*fe6060f1SDimitry Andric return serializeCompilerInvocation(CI); 78*fe6060f1SDimitry Andric } 79*fe6060f1SDimitry Andric 80*fe6060f1SDimitry Andric std::vector<std::string> 81*fe6060f1SDimitry Andric ModuleDeps::getCanonicalCommandLineWithoutModulePaths() const { 82*fe6060f1SDimitry Andric return serializeCompilerInvocation(Invocation); 83*fe6060f1SDimitry Andric } 84*fe6060f1SDimitry Andric 85*fe6060f1SDimitry Andric void dependencies::detail::collectPCMAndModuleMapPaths( 86*fe6060f1SDimitry Andric llvm::ArrayRef<ModuleID> Modules, 87*fe6060f1SDimitry Andric std::function<StringRef(ModuleID)> LookupPCMPath, 88*fe6060f1SDimitry Andric std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps, 89*fe6060f1SDimitry Andric std::vector<std::string> &PCMPaths, std::vector<std::string> &ModMapPaths) { 905ffd83dbSDimitry Andric llvm::StringSet<> AlreadyAdded; 915ffd83dbSDimitry Andric 92*fe6060f1SDimitry Andric std::function<void(llvm::ArrayRef<ModuleID>)> AddArgs = 93*fe6060f1SDimitry Andric [&](llvm::ArrayRef<ModuleID> Modules) { 94*fe6060f1SDimitry Andric for (const ModuleID &MID : Modules) { 95*fe6060f1SDimitry Andric if (!AlreadyAdded.insert(MID.ModuleName + MID.ContextHash).second) 965ffd83dbSDimitry Andric continue; 97*fe6060f1SDimitry Andric const ModuleDeps &M = LookupModuleDeps(MID); 985ffd83dbSDimitry Andric // Depth first traversal. 995ffd83dbSDimitry Andric AddArgs(M.ClangModuleDeps); 100*fe6060f1SDimitry Andric PCMPaths.push_back(LookupPCMPath(MID).str()); 101*fe6060f1SDimitry Andric if (!M.ClangModuleMapFile.empty()) 102*fe6060f1SDimitry Andric ModMapPaths.push_back(M.ClangModuleMapFile); 1035ffd83dbSDimitry Andric } 1045ffd83dbSDimitry Andric }; 1055ffd83dbSDimitry Andric 1065ffd83dbSDimitry Andric AddArgs(Modules); 1075ffd83dbSDimitry Andric } 1085ffd83dbSDimitry Andric 109480093f4SDimitry Andric void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, 110480093f4SDimitry Andric FileChangeReason Reason, 111480093f4SDimitry Andric SrcMgr::CharacteristicKind FileType, 112480093f4SDimitry Andric FileID PrevFID) { 113480093f4SDimitry Andric if (Reason != PPCallbacks::EnterFile) 114480093f4SDimitry Andric return; 115480093f4SDimitry Andric 1165ffd83dbSDimitry Andric // This has to be delayed as the context hash can change at the start of 1175ffd83dbSDimitry Andric // `CompilerInstance::ExecuteAction`. 1185ffd83dbSDimitry Andric if (MDC.ContextHash.empty()) { 1195ffd83dbSDimitry Andric MDC.ContextHash = Instance.getInvocation().getModuleHash(); 1205ffd83dbSDimitry Andric MDC.Consumer.handleContextHash(MDC.ContextHash); 1215ffd83dbSDimitry Andric } 1225ffd83dbSDimitry Andric 123480093f4SDimitry Andric SourceManager &SM = Instance.getSourceManager(); 124480093f4SDimitry Andric 125480093f4SDimitry Andric // Dependency generation really does want to go all the way to the 126480093f4SDimitry Andric // file entry for a source location to find out what is depended on. 127480093f4SDimitry Andric // We do not want #line markers to affect dependency generation! 128e8d8bef9SDimitry Andric if (Optional<StringRef> Filename = 129e8d8bef9SDimitry Andric SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc)))) 130*fe6060f1SDimitry Andric MDC.FileDeps.push_back( 131e8d8bef9SDimitry Andric std::string(llvm::sys::path::remove_leading_dotslash(*Filename))); 132480093f4SDimitry Andric } 133480093f4SDimitry Andric 134480093f4SDimitry Andric void ModuleDepCollectorPP::InclusionDirective( 135480093f4SDimitry Andric SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, 136480093f4SDimitry Andric bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, 137480093f4SDimitry Andric StringRef SearchPath, StringRef RelativePath, const Module *Imported, 138480093f4SDimitry Andric SrcMgr::CharacteristicKind FileType) { 139480093f4SDimitry Andric if (!File && !Imported) { 140480093f4SDimitry Andric // This is a non-modular include that HeaderSearch failed to find. Add it 141480093f4SDimitry Andric // here as `FileChanged` will never see it. 142*fe6060f1SDimitry Andric MDC.FileDeps.push_back(std::string(FileName)); 1435ffd83dbSDimitry Andric } 1445ffd83dbSDimitry Andric handleImport(Imported); 145480093f4SDimitry Andric } 146480093f4SDimitry Andric 1475ffd83dbSDimitry Andric void ModuleDepCollectorPP::moduleImport(SourceLocation ImportLoc, 1485ffd83dbSDimitry Andric ModuleIdPath Path, 1495ffd83dbSDimitry Andric const Module *Imported) { 1505ffd83dbSDimitry Andric handleImport(Imported); 1515ffd83dbSDimitry Andric } 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric void ModuleDepCollectorPP::handleImport(const Module *Imported) { 154480093f4SDimitry Andric if (!Imported) 155480093f4SDimitry Andric return; 156480093f4SDimitry Andric 157*fe6060f1SDimitry Andric const Module *TopLevelModule = Imported->getTopLevelModule(); 158*fe6060f1SDimitry Andric 159*fe6060f1SDimitry Andric if (MDC.isPrebuiltModule(TopLevelModule)) 160*fe6060f1SDimitry Andric DirectPrebuiltModularDeps.insert(TopLevelModule); 161*fe6060f1SDimitry Andric else 162*fe6060f1SDimitry Andric DirectModularDeps.insert(TopLevelModule); 163480093f4SDimitry Andric } 164480093f4SDimitry Andric 165480093f4SDimitry Andric void ModuleDepCollectorPP::EndOfMainFile() { 166480093f4SDimitry Andric FileID MainFileID = Instance.getSourceManager().getMainFileID(); 1675ffd83dbSDimitry Andric MDC.MainFile = std::string( 1685ffd83dbSDimitry Andric Instance.getSourceManager().getFileEntryForID(MainFileID)->getName()); 169480093f4SDimitry Andric 170*fe6060f1SDimitry Andric if (!Instance.getPreprocessorOpts().ImplicitPCHInclude.empty()) 171*fe6060f1SDimitry Andric MDC.FileDeps.push_back(Instance.getPreprocessorOpts().ImplicitPCHInclude); 172*fe6060f1SDimitry Andric 173*fe6060f1SDimitry Andric for (const Module *M : DirectModularDeps) { 174*fe6060f1SDimitry Andric // A top-level module might not be actually imported as a module when 175*fe6060f1SDimitry Andric // -fmodule-name is used to compile a translation unit that imports this 176*fe6060f1SDimitry Andric // module. In that case it can be skipped. The appropriate header 177*fe6060f1SDimitry Andric // dependencies will still be reported as expected. 178*fe6060f1SDimitry Andric if (!M->getASTFile()) 179*fe6060f1SDimitry Andric continue; 180480093f4SDimitry Andric handleTopLevelModule(M); 181480093f4SDimitry Andric } 182480093f4SDimitry Andric 183*fe6060f1SDimitry Andric MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts); 184*fe6060f1SDimitry Andric 185*fe6060f1SDimitry Andric for (auto &&I : MDC.ModularDeps) 186480093f4SDimitry Andric MDC.Consumer.handleModuleDependency(I.second); 187480093f4SDimitry Andric 188*fe6060f1SDimitry Andric for (auto &&I : MDC.FileDeps) 189*fe6060f1SDimitry Andric MDC.Consumer.handleFileDependency(I); 190*fe6060f1SDimitry Andric 191*fe6060f1SDimitry Andric for (auto &&I : DirectPrebuiltModularDeps) 192*fe6060f1SDimitry Andric MDC.Consumer.handlePrebuiltModuleDependency(PrebuiltModuleDep{I}); 193480093f4SDimitry Andric } 194480093f4SDimitry Andric 195*fe6060f1SDimitry Andric ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { 196480093f4SDimitry Andric assert(M == M->getTopLevelModule() && "Expected top level module!"); 197480093f4SDimitry Andric 198*fe6060f1SDimitry Andric // If this module has been handled already, just return its ID. 199*fe6060f1SDimitry Andric auto ModI = MDC.ModularDeps.insert({M, ModuleDeps{}}); 200*fe6060f1SDimitry Andric if (!ModI.second) 201*fe6060f1SDimitry Andric return ModI.first->second.ID; 202480093f4SDimitry Andric 203480093f4SDimitry Andric ModuleDeps &MD = ModI.first->second; 204480093f4SDimitry Andric 205*fe6060f1SDimitry Andric MD.ID.ModuleName = M->getFullModuleName(); 206*fe6060f1SDimitry Andric MD.ImportedByMainFile = DirectModularDeps.contains(M); 207*fe6060f1SDimitry Andric MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName()); 208*fe6060f1SDimitry Andric MD.IsSystem = M->IsSystem; 209*fe6060f1SDimitry Andric 210480093f4SDimitry Andric const FileEntry *ModuleMap = Instance.getPreprocessor() 211480093f4SDimitry Andric .getHeaderSearchInfo() 212480093f4SDimitry Andric .getModuleMap() 213*fe6060f1SDimitry Andric .getModuleMapFileForUniquing(M); 2145ffd83dbSDimitry Andric MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : ""); 215*fe6060f1SDimitry Andric 216480093f4SDimitry Andric serialization::ModuleFile *MF = 217480093f4SDimitry Andric MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile()); 218480093f4SDimitry Andric MDC.Instance.getASTReader()->visitInputFiles( 219480093f4SDimitry Andric *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { 220*fe6060f1SDimitry Andric // __inferred_module.map is the result of the way in which an implicit 221*fe6060f1SDimitry Andric // module build handles inferred modules. It adds an overlay VFS with 222*fe6060f1SDimitry Andric // this file in the proper directory and relies on the rest of Clang to 223*fe6060f1SDimitry Andric // handle it like normal. With explicitly built modules we don't need 224*fe6060f1SDimitry Andric // to play VFS tricks, so replace it with the correct module map. 225*fe6060f1SDimitry Andric if (IF.getFile()->getName().endswith("__inferred_module.map")) { 226*fe6060f1SDimitry Andric MD.FileDeps.insert(ModuleMap->getName()); 227*fe6060f1SDimitry Andric return; 228*fe6060f1SDimitry Andric } 229480093f4SDimitry Andric MD.FileDeps.insert(IF.getFile()->getName()); 230480093f4SDimitry Andric }); 231480093f4SDimitry Andric 232*fe6060f1SDimitry Andric // Add direct prebuilt module dependencies now, so that we can use them when 233*fe6060f1SDimitry Andric // creating a CompilerInvocation and computing context hash for this 234*fe6060f1SDimitry Andric // ModuleDeps instance. 235*fe6060f1SDimitry Andric addDirectPrebuiltModuleDeps(M, MD); 236*fe6060f1SDimitry Andric 237*fe6060f1SDimitry Andric MD.Invocation = MDC.makeInvocationForModuleBuildWithoutPaths(MD); 238*fe6060f1SDimitry Andric MD.ID.ContextHash = MD.Invocation.getModuleHash(); 239*fe6060f1SDimitry Andric 2405ffd83dbSDimitry Andric llvm::DenseSet<const Module *> AddedModules; 2415ffd83dbSDimitry Andric addAllSubmoduleDeps(M, MD, AddedModules); 242*fe6060f1SDimitry Andric 243*fe6060f1SDimitry Andric return MD.ID; 244*fe6060f1SDimitry Andric } 245*fe6060f1SDimitry Andric 246*fe6060f1SDimitry Andric void ModuleDepCollectorPP::addDirectPrebuiltModuleDeps(const Module *M, 247*fe6060f1SDimitry Andric ModuleDeps &MD) { 248*fe6060f1SDimitry Andric for (const Module *Import : M->Imports) 249*fe6060f1SDimitry Andric if (Import->getTopLevelModule() != M->getTopLevelModule()) 250*fe6060f1SDimitry Andric if (MDC.isPrebuiltModule(Import)) 251*fe6060f1SDimitry Andric MD.PrebuiltModuleDeps.emplace_back(Import); 252480093f4SDimitry Andric } 253480093f4SDimitry Andric 2545ffd83dbSDimitry Andric void ModuleDepCollectorPP::addAllSubmoduleDeps( 2555ffd83dbSDimitry Andric const Module *M, ModuleDeps &MD, 2565ffd83dbSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 2575ffd83dbSDimitry Andric addModuleDep(M, MD, AddedModules); 258480093f4SDimitry Andric 259480093f4SDimitry Andric for (const Module *SubM : M->submodules()) 2605ffd83dbSDimitry Andric addAllSubmoduleDeps(SubM, MD, AddedModules); 261480093f4SDimitry Andric } 262480093f4SDimitry Andric 2635ffd83dbSDimitry Andric void ModuleDepCollectorPP::addModuleDep( 2645ffd83dbSDimitry Andric const Module *M, ModuleDeps &MD, 2655ffd83dbSDimitry Andric llvm::DenseSet<const Module *> &AddedModules) { 266480093f4SDimitry Andric for (const Module *Import : M->Imports) { 267*fe6060f1SDimitry Andric if (Import->getTopLevelModule() != M->getTopLevelModule() && 268*fe6060f1SDimitry Andric !MDC.isPrebuiltModule(Import)) { 269*fe6060f1SDimitry Andric ModuleID ImportID = handleTopLevelModule(Import->getTopLevelModule()); 2705ffd83dbSDimitry Andric if (AddedModules.insert(Import->getTopLevelModule()).second) 271*fe6060f1SDimitry Andric MD.ClangModuleDeps.push_back(ImportID); 272480093f4SDimitry Andric } 273480093f4SDimitry Andric } 274480093f4SDimitry Andric } 275480093f4SDimitry Andric 2765ffd83dbSDimitry Andric ModuleDepCollector::ModuleDepCollector( 2775ffd83dbSDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I, 278*fe6060f1SDimitry Andric DependencyConsumer &C, CompilerInvocation &&OriginalCI) 279*fe6060f1SDimitry Andric : Instance(I), Consumer(C), Opts(std::move(Opts)), 280*fe6060f1SDimitry Andric OriginalInvocation(std::move(OriginalCI)) {} 281480093f4SDimitry Andric 282480093f4SDimitry Andric void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { 283480093f4SDimitry Andric PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this)); 284480093f4SDimitry Andric } 285480093f4SDimitry Andric 286480093f4SDimitry Andric void ModuleDepCollector::attachToASTReader(ASTReader &R) {} 287*fe6060f1SDimitry Andric 288*fe6060f1SDimitry Andric bool ModuleDepCollector::isPrebuiltModule(const Module *M) { 289*fe6060f1SDimitry Andric std::string Name(M->getTopLevelModuleName()); 290*fe6060f1SDimitry Andric const auto &PrebuiltModuleFiles = 291*fe6060f1SDimitry Andric Instance.getHeaderSearchOpts().PrebuiltModuleFiles; 292*fe6060f1SDimitry Andric auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); 293*fe6060f1SDimitry Andric if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) 294*fe6060f1SDimitry Andric return false; 295*fe6060f1SDimitry Andric assert("Prebuilt module came from the expected AST file" && 296*fe6060f1SDimitry Andric PrebuiltModuleFileIt->second == M->getASTFile()->getName()); 297*fe6060f1SDimitry Andric return true; 298*fe6060f1SDimitry Andric } 299