15#include "llvm/ADT/STLExtras.h"
16#include "llvm/Support/BLAKE3.h"
17#include "llvm/Support/StringSaver.h"
21using namespace tooling;
22using namespace dependencies;
25 assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
26 "Using uninitialized ModuleDeps");
27 if (
const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
28 BuildInfo = CI->getCC1CommandLine();
29 return std::get<std::vector<std::string>>(BuildInfo);
39 std::vector<HeaderSearchOptions::Entry> Entries;
42 llvm::BitVector SearchPathUsage(Entries.size());
43 llvm::DenseSet<const serialization::ModuleFile *>
Visited;
54 if (SearchPathUsage.size() != Entries.size())
55 llvm::report_fatal_error(
56 "Inconsistent search path options between modules detected");
58 for (
auto Idx : SearchPathUsage.set_bits())
59 Opts.
UserEntries.push_back(std::move(Entries[Idx]));
62 std::vector<std::string> VFSOverlayFiles;
65 llvm::BitVector VFSUsage(VFSOverlayFiles.size());
66 llvm::DenseSet<const serialization::ModuleFile *>
Visited;
80 auto VFSMap = PrebuiltModuleVFSMap.find(MF->
FileName);
81 if (VFSMap == PrebuiltModuleVFSMap.end())
83 for (std::size_t I = 0,
E = VFSOverlayFiles.size(); I !=
E; ++I) {
84 if (VFSMap->second.contains(VFSOverlayFiles[I]))
91 if (VFSUsage.size() != VFSOverlayFiles.size())
92 llvm::report_fatal_error(
93 "Inconsistent -ivfsoverlay options between modules detected");
95 for (
auto Idx : VFSUsage.set_bits())
101 bool IsSystemModule) {
106 bool Wsystem_headers =
false;
107 for (StringRef Opt : Opts.
Warnings) {
108 bool isPositive = !Opt.consume_front(
"no-");
109 if (Opt ==
"system-headers")
110 Wsystem_headers = isPositive;
122static std::vector<std::string>
splitString(std::string S,
char Separator) {
124 StringRef(S).split(Segments, Separator, -1,
false);
125 std::vector<std::string>
Result;
126 Result.reserve(Segments.size());
127 for (StringRef Segment : Segments)
128 Result.push_back(Segment.str());
216 [&CI](
const std::pair<std::string, bool> &Def) {
217 StringRef MacroDef = Def.first;
218 return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
219 llvm::CachedHashString(MacroDef.split(
'=').first));
229ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
243 auto CurrentModuleMapEntry =
245 assert(CurrentModuleMapEntry &&
"module map file entry not found");
255 assert(ModuleMapEntry &&
"module map file entry not found");
262 if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
267 if (*ModuleMapEntry == *CurrentModuleMapEntry &&
268 !DepModuleMapFiles.contains(*ModuleMapEntry))
295llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
297 llvm::DenseSet<const FileEntry *> ModuleMapFiles;
298 for (
const ModuleID &MID : ClangModuleDeps) {
300 assert(MD &&
"Inconsistent dependency info");
303 assert(FE &&
"Missing module map file that was previously found");
304 ModuleMapFiles.insert(*FE);
306 return ModuleMapFiles;
309void ModuleDepCollector::addModuleMapFiles(
311 if (EagerLoadModules)
314 for (
const ModuleID &MID : ClangModuleDeps) {
316 assert(MD &&
"Inconsistent dependency info");
321void ModuleDepCollector::addModuleFiles(
323 for (
const ModuleID &MID : ClangModuleDeps) {
324 std::string PCMPath =
326 if (EagerLoadModules)
330 {MID.ModuleName, std::move(PCMPath)});
334void ModuleDepCollector::addModuleFiles(
336 for (
const ModuleID &MID : ClangModuleDeps) {
337 std::string PCMPath =
339 if (EagerLoadModules)
343 {MID.ModuleName, std::move(PCMPath)});
371 CurrentModuleMap->getNameAsRequested());
374 for (
const auto &KV : ModularDeps)
375 if (DirectModularDeps.contains(KV.first))
376 DirectDeps.push_back(KV.second->ID);
379 addModuleMapFiles(CI, DirectDeps);
381 addModuleFiles(CI, DirectDeps);
383 for (
const auto &KV : DirectPrebuiltModularDeps)
390 bool EagerLoadModules,
391 llvm::vfs::FileSystem &
VFS) {
392 llvm::HashBuilder<llvm::TruncatedBLAKE3<16>, llvm::endianness::native>
400 llvm::ErrorOr<std::string> CWD =
VFS.getCurrentWorkingDirectory();
402 HashBuilder.add(*CWD);
406 ArgVec.reserve(4096);
408 Arg.toVector(ArgVec);
409 ArgVec.push_back(
'\0');
411 HashBuilder.add(ArgVec);
419 HashBuilder.add(ID.ModuleName);
420 HashBuilder.add(ID.ContextHash);
423 HashBuilder.add(EagerLoadModules);
425 llvm::BLAKE3Result<16> Hash = HashBuilder.final();
426 std::array<uint64_t, 2> Words;
427 static_assert(
sizeof(Hash) ==
sizeof(Words),
"Hash must match Words");
428 std::memcpy(Words.data(), Hash.data(),
sizeof(Hash));
429 return toString(llvm::APInt(
sizeof(Words) * 8, Words), 36,
false);
432void ModuleDepCollector::associateWithContextHash(
436 bool Inserted = ModuleDepsByID.insert({Deps.
ID, &Deps}).second;
438 assert(Inserted &&
"duplicate module mapping");
451 if (MDC.ContextHash.empty()) {
461 if (std::optional<StringRef>
Filename =
SM.getNonBuiltinFilenameForID(FID))
462 MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*
Filename));
468 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
470 if (!
File && !ModuleImported) {
475 handleImport(SuggestedModule);
485 MDC.RequiredStdCXXModules.push_back(RequiredModule);
489 handleImport(Imported);
492void ModuleDepCollectorPP::handleImport(
const Module *Imported) {
498 if (MDC.isPrebuiltModule(TopLevelModule))
499 MDC.DirectPrebuiltModularDeps.insert(
502 MDC.DirectModularDeps.insert(TopLevelModule);
512 if (PP.isInNamedModule()) {
514 ProvidedModule.
ModuleName = PP.getNamedModuleName();
520 if (PP.isInImplementationUnit())
521 MDC.RequiredStdCXXModules.push_back(ProvidedModule);
523 MDC.ProvidedStdCXXModule = ProvidedModule;
531 if (!MDC.isPrebuiltModule(M))
532 MDC.DirectModularDeps.insert(M);
534 for (
const Module *M : MDC.DirectModularDeps)
535 handleTopLevelModule(M);
539 if (MDC.IsStdModuleP1689Format)
541 MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
543 for (
auto &&I : MDC.ModularDeps)
546 for (
const Module *M : MDC.DirectModularDeps) {
547 auto It = MDC.ModularDeps.find(M);
549 if (It != MDC.ModularDeps.end())
553 for (
auto &&I : MDC.FileDeps)
556 for (
auto &&I : MDC.DirectPrebuiltModularDeps)
560std::optional<ModuleID>
561ModuleDepCollectorPP::handleTopLevelModule(
const Module *M) {
572 auto ModI = MDC.ModularDeps.insert({M,
nullptr});
574 return ModI.first->second->ID;
576 ModI.first->second = std::make_unique<ModuleDeps>();
598 MDC.ScanInstance.
getASTReader()->getModuleManager().lookup(
608 if (StringRef(IFI.
Filename).ends_with(
"__inferred_module.map")) {
609 MDC.addFileDep(MD, ModuleMap->getName());
615 llvm::DenseSet<const Module *> SeenDeps;
616 addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
617 addAllSubmoduleDeps(M, MD, SeenDeps);
618 addAllAffectingClangModules(M, MD, SeenDeps);
626 .ends_with(
"__inferred_module.map"))
632 MDC.getInvocationAdjustedForModuleBuildWithoutOutputs(
638 MDC.PrebuiltModuleVFSMap,
646 MDC.associateWithContextHash(CI, MD);
649 MDC.addOutputPaths(CI, MD);
651 MD.BuildInfo = std::move(CI);
657 llvm::function_ref<
void(
const Module *)> F) {
662 llvm::stable_sort(Submodules, [](
const Module *A,
const Module *B) {
665 for (
const Module *SubM : Submodules)
669void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps(
671 llvm::DenseSet<const Module *> &SeenSubmodules) {
672 addModulePrebuiltDeps(M, MD, SeenSubmodules);
675 addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules);
679void ModuleDepCollectorPP::addModulePrebuiltDeps(
681 llvm::DenseSet<const Module *> &SeenSubmodules) {
684 if (MDC.isPrebuiltModule(
Import->getTopLevelModule()))
685 if (SeenSubmodules.insert(
Import->getTopLevelModule()).second)
689void ModuleDepCollectorPP::addAllSubmoduleDeps(
691 llvm::DenseSet<const Module *> &AddedModules) {
692 addModuleDep(M, MD, AddedModules);
695 addAllSubmoduleDeps(SubM, MD, AddedModules);
699void ModuleDepCollectorPP::addModuleDep(
701 llvm::DenseSet<const Module *> &AddedModules) {
704 !MDC.isPrebuiltModule(
Import)) {
705 if (
auto ImportID = handleTopLevelModule(
Import->getTopLevelModule()))
706 if (AddedModules.insert(
Import->getTopLevelModule()).second)
712void ModuleDepCollectorPP::addAllAffectingClangModules(
714 llvm::DenseSet<const Module *> &AddedModules) {
715 addAffectingClangModule(M, MD, AddedModules);
718 addAllAffectingClangModules(SubM, MD, AddedModules);
721void ModuleDepCollectorPP::addAffectingClangModule(
723 llvm::DenseSet<const Module *> &AddedModules) {
726 "Not quite import not top-level module");
728 !MDC.isPrebuiltModule(Affecting)) {
729 if (
auto ImportID = handleTopLevelModule(Affecting))
730 if (AddedModules.insert(Affecting).second)
737 std::unique_ptr<DependencyOutputOptions> Opts,
742 bool IsStdModuleP1689Format)
743 : ScanInstance(ScanInstance), Consumer(
C), Controller(Controller),
744 PrebuiltModuleVFSMap(
std::move(PrebuiltModuleVFSMap)),
745 Opts(
std::move(Opts)),
748 OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
749 IsStdModuleP1689Format(IsStdModuleP1689Format) {}
757bool ModuleDepCollector::isPrebuiltModule(
const Module *M) {
759 const auto &PrebuiltModuleFiles =
761 auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name);
762 if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end())
764 assert(
"Prebuilt module came from the expected AST file" &&
771 if (llvm::sys::path::is_absolute(
Path) &&
772 !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
774 Storage.assign(
Path.begin(),
Path.end());
776 llvm::sys::path::make_preferred(Storage);
777 return StringRef(Storage.data(), Storage.size());
780void ModuleDepCollector::addFileDep(StringRef
Path) {
781 if (IsStdModuleP1689Format) {
784 FileDeps.push_back(std::string(
Path));
790 FileDeps.push_back(std::string(
Path));
793void ModuleDepCollector::addFileDep(
ModuleDeps &MD, StringRef
Path) {
794 if (IsStdModuleP1689Format) {
llvm::DenseSet< const void * > Visited
llvm::MachO::FileType FileType
llvm::MachO::Target Target
static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, ASTReader &Reader, const serialization::ModuleFile &MF, const PrebuiltModuleVFSMapT &PrebuiltModuleVFSMap, ScanningOptimizations OptimizeArgs)
static std::vector< std::string > splitString(std::string S, char Separator)
static std::string getModuleContextHash(const ModuleDeps &MD, const CowCompilerInvocation &CI, bool EagerLoadModules, llvm::vfs::FileSystem &VFS)
static void optimizeDiagnosticOpts(DiagnosticOptions &Opts, bool IsSystemModule)
static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path, SmallVectorImpl< char > &Storage)
static CowCompilerInvocation makeCommonInvocationForModuleBuild(CompilerInvocation CI)
static void forEachSubmoduleSorted(const Module *M, llvm::function_ref< void(const Module *)> F)
static bool needsModules(FrontendInputFile FIF)
Defines the clang::Preprocessor interface.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Reads an AST files chain containing the contents of a translation unit.
Represents a character-granular source range.
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
std::string CoverageNotesFile
The filename with path we use for coverage notes files.
std::string ProfileInstrumentUsePath
Name of the profile file to use as input for -fprofile-instr-use.
std::string SampleProfileFile
Name of the profile file to use with -fprofile-sample-use.
std::string CoverageDataFile
The filename with path we use for coverage data files.
std::string DebugCompilationDir
The string to embed in debug information as the current working directory.
std::string MainFileName
The user provided name for the "main file", if non-empty.
std::string CoverageCompilationDir
The string to embed in coverage mapping as the current working directory.
std::string ProfileRemappingFile
Name of the profile remapping file to apply to the profile data supplied by -fprofile-sample-use or -...
std::string DwarfDebugFlags
The string to embed in the debug information for the compile unit, if non-empty.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileManager & getFileManager() const
Return the current file manager to the caller.
IntrusiveRefCntPtr< ASTReader > getASTReader() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
HeaderSearchOptions & getHeaderSearchOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
llvm::vfs::FileSystem & getVirtualFileSystem() const
SourceManager & getSourceManager() const
Return the current source manager.
const FrontendOptions & getFrontendOpts() const
void generateCC1CommandLine(llvm::SmallVectorImpl< const char * > &Args, StringAllocator SA) const
Generate cc1-compatible command line arguments from this instance.
const DependencyOutputOptions & getDependencyOutputOpts() const
const DiagnosticOptions & getDiagnosticOpts() const
Helper class for holding the data necessary to invoke the compiler.
PreprocessorOptions & getPreprocessorOpts()
void clearImplicitModuleBuildOptions()
Disable implicit modules and canonicalize options that are only used by implicit modules.
LangOptions & getLangOpts()
Mutable getters.
DependencyOutputOptions & getDependencyOutputOpts()
void resetNonModularOptions()
Reset all of the options that are not considered when building a module.
FrontendOptions & getFrontendOpts()
std::string getModuleHash() const
Retrieve a module hash string that is suitable for uniquely identifying the conditions under which th...
CodeGenOptions & getCodeGenOpts()
HeaderSearchOptions & getHeaderSearchOpts()
DiagnosticOptions & getDiagnosticOpts()
Same as CompilerInvocation, but with copy-on-write optimization.
FrontendOptions & getMutFrontendOpts()
LangOptions & getMutLangOpts()
Mutable getters.
HeaderSearchOptions & getMutHeaderSearchOpts()
DiagnosticOptions & getMutDiagnosticOpts()
DependencyOutputOptions & getMutDependencyOutputOpts()
std::string OutputFile
The file to write dependency output to.
std::vector< std::string > Targets
A list of names to use as the targets in the dependency file; this list must contain at least one ent...
Options for controlling the compiler diagnostics engine.
std::vector< std::string > Remarks
The list of -R... options used to alter the diagnostic mappings, with the prefixes removed.
std::vector< std::string > Warnings
The list of -W... options used to alter the diagnostic mappings, with the prefixes removed.
std::vector< std::string > UndefPrefixes
The list of prefixes from -Wundef-prefix=... used to generate warnings for undefined macros.
std::vector< std::string > SystemHeaderWarningsModules
The list of -Wsystem-headers-in-module=... options used to override whether -Wsystem-headers is enabl...
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
StringRef getName() const
The name of this FileEntry.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option.
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
InputKind DashX
The input kind, either specified via -x argument or deduced from the input file name.
std::vector< std::string > ModuleFiles
The list of additional prebuilt module files to load before processing the input.
unsigned IsSystemModule
When using -emit-module, treat the modulemap as a system module.
std::vector< std::string > LLVMArgs
A list of arguments to forward to LLVM's option processing; this should only be used for debugging an...
std::string OutputFile
The output file, if any.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
frontend::ActionKind ProgramAction
The frontend action to perform.
enum clang::FrontendOptions::@199 ARCMTAction
std::vector< std::string > ModuleMapFiles
The list of module map files to load before processing the input.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::string ModuleName
The module currently being compiled as specified by -fmodule-name.
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
std::error_code canonicalizeModuleMapPath(SmallVectorImpl< char > &Path)
Canonicalize Path in a manner suitable for a module map file.
Describes a module or submodule.
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
llvm::SmallSetVector< Module *, 2 > Imports
The set of modules imported by this module, and on which this module depends.
unsigned IsSystem
Whether this is a "system" module (which assumes that all headers in it are system headers).
std::string Name
The name of this module.
llvm::iterator_range< submodule_iterator > submodules()
llvm::SmallVector< LinkLibrary, 2 > LinkLibraries
The set of libraries or frameworks to link against when an entity from this module is used.
llvm::SmallSetVector< Module *, 2 > AffectingClangModules
The set of top-level modules that affected the compilation of this module, but were not imported.
std::string getFullModuleName(bool AllowStringLiterals=false) const
Retrieve the full name of this module, including the path from its top-level module.
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
OptionalFileEntryRef getASTFile() const
The serialized AST file for this module, if one was created.
bool UseExportAsModuleLinkName
Autolinking uses the framework name for linking purposes when this is false and the export_as name ot...
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
std::vector< std::pair< std::string, bool > > Macros
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool isInImportingCXXNamedModules() const
If we're importing a standard C++20 Named Modules.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Module * getCurrentModuleImplementation()
Retrieves the module whose implementation we're current compiling, if any.
HeaderSearch & getHeaderSearchInfo() const
const llvm::SmallSetVector< Module *, 2 > & getAffectingClangModules() const
Get the set of top-level clang modules that affected preprocessing, but were not imported.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
FileID getMainFileID() const
Returns the FileID of the main source file.
Token - This structure provides full information about a lexed token.
Information about a module that has been loaded by the ASTReader.
std::string FileName
The file name of the module file.
llvm::SetVector< ModuleFile * > Imports
List of modules which this module directly imported.
llvm::BitVector SearchPathUsage
The bit vector denoting usage of each header search entry (true = used).
llvm::BitVector VFSUsage
The bit vector denoting usage of each VFS entry (true = used).
ModuleKind Kind
The type of this module.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
@ GeneratePCH
Generate pre-compiled header.
@ GenerateModule
Generate pre-compiled module from a module map.
const unsigned VERSION_MINOR
AST file minor version number supported by this version of Clang.
const unsigned VERSION_MAJOR
AST file major version number supported by this version of Clang.
@ MK_ImplicitModule
File is an implicitly-loaded module.
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void quoteMakeTarget(StringRef Target, SmallVectorImpl< char > &Res)
Quote target names for inclusion in GNU Make dependency files.
@ Asm
Assembly: we accept this only so that we can preprocess it.
@ Result
The result type of a method or function.
std::string getClangFullRepositoryVersion()
Retrieves the full repository version that is an amalgamation of the information in getClangRepositor...
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.