diff options
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h')
-rw-r--r-- | contrib/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h | 251 |
1 files changed, 172 insertions, 79 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/contrib/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h index a9f2b4d0c6fc..051363b075de 100644 --- a/contrib/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/contrib/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -1,14 +1,13 @@ //===- ModuleDepCollector.h - Callbacks to collect deps ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H -#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H +#ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H +#define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" @@ -17,16 +16,21 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/raw_ostream.h" +#include <optional> #include <string> #include <unordered_map> +#include <variant> namespace clang { namespace tooling { namespace dependencies { +class DependencyActionController; class DependencyConsumer; /// Modular dependency that has already been built prior to the dependency scan. @@ -47,25 +51,61 @@ struct ModuleID { /// or a header-name for C++20 header units. std::string ModuleName; - /// The context hash of a module represents the set of compiler options that - /// may make one version of a module incompatible with another. This includes - /// things like language mode, predefined macros, header search paths, etc... + /// The context hash of a module represents the compiler options that affect + /// the resulting command-line invocation. + /// + /// Modules with the same name and ContextHash but different invocations could + /// cause non-deterministic build results. /// /// Modules with the same name but a different \c ContextHash should be /// treated as separate modules for the purpose of a build. std::string ContextHash; bool operator==(const ModuleID &Other) const { - return ModuleName == Other.ModuleName && ContextHash == Other.ContextHash; + return std::tie(ModuleName, ContextHash) == + std::tie(Other.ModuleName, Other.ContextHash); } -}; -struct ModuleIDHasher { - std::size_t operator()(const ModuleID &MID) const { - return llvm::hash_combine(MID.ModuleName, MID.ContextHash); + bool operator<(const ModuleID& Other) const { + return std::tie(ModuleName, ContextHash) < + std::tie(Other.ModuleName, Other.ContextHash); } }; +/// P1689ModuleInfo - Represents the needed information of standard C++20 +/// modules for P1689 format. +struct P1689ModuleInfo { + /// The name of the module. This may include `:` for partitions. + std::string ModuleName; + + /// Optional. The source path to the module. + std::string SourcePath; + + /// If this module is a standard c++ interface unit. + bool IsStdCXXModuleInterface = true; + + enum class ModuleType { + NamedCXXModule + // To be supported + // AngleHeaderUnit, + // QuoteHeaderUnit + }; + ModuleType Type = ModuleType::NamedCXXModule; +}; + +/// An output from a module compilation, such as the path of the module file. +enum class ModuleOutputKind { + /// The module file (.pcm). Required. + ModuleFile, + /// The path of the dependency file (.d), if any. + DependencyFile, + /// The null-separated list of names to use as the targets in the dependency + /// file, if any. Defaults to the value of \c ModuleFile, as in the driver. + DependencyTargets, + /// The path of the serialized diagnostic file (.dia), if any. + DiagnosticSerializationFile, +}; + struct ModuleDeps { /// The identifier of the module. ModuleID ID; @@ -79,13 +119,14 @@ struct ModuleDeps { /// additionally appear in \c FileDeps as a dependency. std::string ClangModuleMapFile; - /// The path to where an implicit build would put the PCM for this module. - std::string ImplicitModulePCMPath; - /// A collection of absolute paths to files that this module directly depends /// on, not including transitive dependencies. llvm::StringSet<> FileDeps; + /// A collection of absolute paths to module map files that this module needs + /// to know about. The ordering is significant. + std::vector<std::string> ModuleMapFileDeps; + /// A collection of prebuilt modular dependencies this module directly depends /// on, not including transitive dependencies. std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; @@ -97,43 +138,17 @@ struct ModuleDeps { /// determined that the differences are benign for this compilation. std::vector<ModuleID> ClangModuleDeps; - // Used to track which modules that were discovered were directly imported by - // the primary TU. - bool ImportedByMainFile = false; + /// Get (or compute) the compiler invocation that can be used to build this + /// module. Does not include argv[0]. + const std::vector<std::string> &getBuildArguments(); - /// Compiler invocation that can be used to build this module (without paths). - CompilerInvocation Invocation; +private: + friend class ModuleDepCollectorPP; - /// Gets the canonical command line suitable for passing to clang. - /// - /// \param LookupPCMPath This function is called to fill in "-fmodule-file=" - /// arguments and the "-o" argument. It needs to return - /// a path for where the PCM for the given module is to - /// be located. - /// \param LookupModuleDeps This function is called to collect the full - /// transitive set of dependencies for this - /// compilation and fill in "-fmodule-map-file=" - /// arguments. - std::vector<std::string> getCanonicalCommandLine( - std::function<StringRef(ModuleID)> LookupPCMPath, - std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const; - - /// Gets the canonical command line suitable for passing to clang, excluding - /// arguments containing modules-related paths: "-fmodule-file=", "-o", - /// "-fmodule-map-file=". - std::vector<std::string> getCanonicalCommandLineWithoutModulePaths() const; + std::variant<std::monostate, CowCompilerInvocation, std::vector<std::string>> + BuildInfo; }; -namespace detail { -/// Collect the paths of PCM and module map files for the modules in \c Modules -/// transitively. -void collectPCMAndModuleMapPaths( - llvm::ArrayRef<ModuleID> Modules, - std::function<StringRef(ModuleID)> LookupPCMPath, - std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps, - std::vector<std::string> &PCMPaths, std::vector<std::string> &ModMapPaths); -} // namespace detail - class ModuleDepCollector; /// Callback that records textual includes and direct modular includes/imports @@ -142,17 +157,16 @@ class ModuleDepCollector; /// \c DependencyConsumer of the parent \c ModuleDepCollector. class ModuleDepCollectorPP final : public PPCallbacks { public: - ModuleDepCollectorPP(CompilerInstance &I, ModuleDepCollector &MDC) - : Instance(I), MDC(MDC) {} + ModuleDepCollectorPP(ModuleDepCollector &MDC) : MDC(MDC) {} - void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType, - FileID PrevFID) override; + void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, FileID PrevFID, + SourceLocation Loc) override; void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange, const FileEntry *File, - StringRef SearchPath, StringRef RelativePath, - const Module *Imported, + CharSourceRange FilenameRange, + OptionalFileEntryRef File, StringRef SearchPath, + StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) override; void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported) override; @@ -160,29 +174,35 @@ public: void EndOfMainFile() override; private: - /// The compiler instance for the current translation unit. - CompilerInstance &Instance; /// The parent dependency collector. ModuleDepCollector &MDC; - /// Working set of direct modular dependencies. - llvm::DenseSet<const Module *> DirectModularDeps; - /// Working set of direct modular dependencies that have already been built. - llvm::DenseSet<const Module *> DirectPrebuiltModularDeps; void handleImport(const Module *Imported); /// Adds direct modular dependencies that have already been built to the /// ModuleDeps instance. - void addDirectPrebuiltModuleDeps(const Module *M, ModuleDeps &MD); + void + addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD, + llvm::DenseSet<const Module *> &SeenSubmodules); + void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD, + llvm::DenseSet<const Module *> &SeenSubmodules); /// Traverses the previously collected direct modular dependencies to discover /// transitive modular dependencies and fills the parent \c ModuleDepCollector /// with both. - ModuleID handleTopLevelModule(const Module *M); + /// Returns the ID or nothing if the dependency is spurious and is ignored. + std::optional<ModuleID> handleTopLevelModule(const Module *M); void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD, llvm::DenseSet<const Module *> &AddedModules); void addModuleDep(const Module *M, ModuleDeps &MD, llvm::DenseSet<const Module *> &AddedModules); + + /// Traverses the affecting modules and updates \c MD with references to the + /// parent \c ModuleDepCollector info. + void addAllAffectingClangModules(const Module *M, ModuleDeps &MD, + llvm::DenseSet<const Module *> &AddedModules); + void addAffectingClangModule(const Module *M, ModuleDeps &MD, + llvm::DenseSet<const Module *> &AddedModules); }; /// Collects modular and non-modular dependencies of the main file by attaching @@ -190,19 +210,28 @@ private: class ModuleDepCollector final : public DependencyCollector { public: ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts, - CompilerInstance &I, DependencyConsumer &C, - CompilerInvocation &&OriginalCI); + CompilerInstance &ScanInstance, DependencyConsumer &C, + DependencyActionController &Controller, + CompilerInvocation OriginalCI, + ScanningOptimizations OptimizeArgs, bool EagerLoadModules, + bool IsStdModuleP1689Format); void attachToPreprocessor(Preprocessor &PP) override; void attachToASTReader(ASTReader &R) override; + /// Apply any changes implied by the discovered dependencies to the given + /// invocation, (e.g. disable implicit modules, add explicit module paths). + void applyDiscoveredDependencies(CompilerInvocation &CI); + private: friend ModuleDepCollectorPP; - /// The compiler instance for the current translation unit. - CompilerInstance &Instance; + /// The compiler instance for scanning the current translation unit. + CompilerInstance &ScanInstance; /// The consumer of collected dependency information. DependencyConsumer &Consumer; + /// Callbacks for computing dependency information. + DependencyActionController &Controller; /// Path to the main source file. std::string MainFile; /// Hash identifying the compilation conditions of the current TU. @@ -211,24 +240,88 @@ private: /// textually included header files. std::vector<std::string> FileDeps; /// Direct and transitive modular dependencies of the main source file. - std::unordered_map<const Module *, ModuleDeps> ModularDeps; + llvm::MapVector<const Module *, std::unique_ptr<ModuleDeps>> ModularDeps; + /// Secondary mapping for \c ModularDeps allowing lookup by ModuleID without + /// a preprocessor. Storage owned by \c ModularDeps. + llvm::DenseMap<ModuleID, ModuleDeps *> ModuleDepsByID; + /// Direct modular dependencies that have already been built. + llvm::MapVector<const Module *, PrebuiltModuleDep> DirectPrebuiltModularDeps; + /// Working set of direct modular dependencies. + llvm::SetVector<const Module *> DirectModularDeps; /// Options that control the dependency output generation. std::unique_ptr<DependencyOutputOptions> Opts; - /// The original Clang invocation passed to dependency scanner. - CompilerInvocation OriginalInvocation; + /// A Clang invocation that's based on the original TU invocation and that has + /// been partially transformed into one that can perform explicit build of + /// a discovered modular dependency. Note that this still needs to be adjusted + /// for each individual module. + CowCompilerInvocation CommonInvocation; + /// Whether to optimize the modules' command-line arguments. + ScanningOptimizations OptimizeArgs; + /// Whether to set up command-lines to load PCM files eagerly. + bool EagerLoadModules; + /// If we're generating dependency output in P1689 format + /// for standard C++ modules. + bool IsStdModuleP1689Format; + + std::optional<P1689ModuleInfo> ProvidedStdCXXModule; + std::vector<P1689ModuleInfo> RequiredStdCXXModules; /// Checks whether the module is known as being prebuilt. bool isPrebuiltModule(const Module *M); - /// Constructs a CompilerInvocation that can be used to build the given - /// module, excluding paths to discovered modular dependencies that are yet to - /// be built. - CompilerInvocation - makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps) const; + /// Adds \p Path to \c FileDeps, making it absolute if necessary. + void addFileDep(StringRef Path); + /// Adds \p Path to \c MD.FileDeps, making it absolute if necessary. + void addFileDep(ModuleDeps &MD, StringRef Path); + + /// Get a Clang invocation adjusted to build the given modular dependency. + /// This excludes paths that are yet-to-be-provided by the build system. + CowCompilerInvocation getInvocationAdjustedForModuleBuildWithoutOutputs( + const ModuleDeps &Deps, + llvm::function_ref<void(CowCompilerInvocation &)> Optimize) const; + + /// Collect module map files for given modules. + llvm::DenseSet<const FileEntry *> + collectModuleMapFiles(ArrayRef<ModuleID> ClangModuleDeps) const; + + /// Add module map files to the invocation, if needed. + void addModuleMapFiles(CompilerInvocation &CI, + ArrayRef<ModuleID> ClangModuleDeps) const; + /// Add module files (pcm) to the invocation, if needed. + void addModuleFiles(CompilerInvocation &CI, + ArrayRef<ModuleID> ClangModuleDeps) const; + void addModuleFiles(CowCompilerInvocation &CI, + ArrayRef<ModuleID> ClangModuleDeps) const; + + /// Add paths that require looking up outputs to the given dependencies. + void addOutputPaths(CowCompilerInvocation &CI, ModuleDeps &Deps); + + /// Compute the context hash for \p Deps, and create the mapping + /// \c ModuleDepsByID[Deps.ID] = &Deps. + void associateWithContextHash(const CowCompilerInvocation &CI, + ModuleDeps &Deps); }; } // end namespace dependencies } // end namespace tooling } // end namespace clang -#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H +namespace llvm { +inline hash_code hash_value(const clang::tooling::dependencies::ModuleID &ID) { + return hash_combine(ID.ModuleName, ID.ContextHash); +} + +template <> struct DenseMapInfo<clang::tooling::dependencies::ModuleID> { + using ModuleID = clang::tooling::dependencies::ModuleID; + static inline ModuleID getEmptyKey() { return ModuleID{"", ""}; } + static inline ModuleID getTombstoneKey() { + return ModuleID{"~", "~"}; // ~ is not a valid module name or context hash + } + static unsigned getHashValue(const ModuleID &ID) { return hash_value(ID); } + static bool isEqual(const ModuleID &LHS, const ModuleID &RHS) { + return LHS == RHS; + } +}; +} // namespace llvm + +#endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H |