1 //===- ModuleDepCollector.h - 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 #ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H 11 #define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H 12 13 #include "clang/Basic/LLVM.h" 14 #include "clang/Basic/SourceManager.h" 15 #include "clang/Frontend/CompilerInvocation.h" 16 #include "clang/Frontend/Utils.h" 17 #include "clang/Lex/HeaderSearch.h" 18 #include "clang/Lex/PPCallbacks.h" 19 #include "clang/Serialization/ASTReader.h" 20 #include "llvm/ADT/DenseMap.h" 21 #include "llvm/ADT/StringSet.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <string> 24 #include <unordered_map> 25 26 namespace clang { 27 namespace tooling { 28 namespace dependencies { 29 30 class DependencyConsumer; 31 32 /// This is used to identify a specific module. 33 struct ModuleID { 34 /// The name of the module. This may include `:` for C++20 module partitions, 35 /// or a header-name for C++20 header units. 36 std::string ModuleName; 37 38 /// The context hash of a module represents the set of compiler options that 39 /// may make one version of a module incompatible with another. This includes 40 /// things like language mode, predefined macros, header search paths, etc... 41 /// 42 /// Modules with the same name but a different \c ContextHash should be 43 /// treated as separate modules for the purpose of a build. 44 std::string ContextHash; 45 }; 46 47 struct ModuleDeps { 48 /// The identifier of the module. 49 ModuleID ID; 50 51 /// Whether this is a "system" module. 52 bool IsSystem; 53 54 /// The path to the modulemap file which defines this module. 55 /// 56 /// This can be used to explicitly build this module. This file will 57 /// additionally appear in \c FileDeps as a dependency. 58 std::string ClangModuleMapFile; 59 60 /// The path to where an implicit build would put the PCM for this module. 61 std::string ImplicitModulePCMPath; 62 63 /// A collection of absolute paths to files that this module directly depends 64 /// on, not including transitive dependencies. 65 llvm::StringSet<> FileDeps; 66 67 /// A list of module identifiers this module directly depends on, not 68 /// including transitive dependencies. 69 /// 70 /// This may include modules with a different context hash when it can be 71 /// determined that the differences are benign for this compilation. 72 std::vector<ModuleID> ClangModuleDeps; 73 74 // Used to track which modules that were discovered were directly imported by 75 // the primary TU. 76 bool ImportedByMainFile = false; 77 78 /// Compiler invocation that can be used to build this module (without paths). 79 CompilerInvocation Invocation; 80 81 /// Gets the canonical command line suitable for passing to clang. 82 /// 83 /// \param LookupPCMPath This function is called to fill in "-fmodule-file=" 84 /// arguments and the "-o" argument. It needs to return 85 /// a path for where the PCM for the given module is to 86 /// be located. 87 /// \param LookupModuleDeps This function is called to collect the full 88 /// transitive set of dependencies for this 89 /// compilation and fill in "-fmodule-map-file=" 90 /// arguments. 91 std::vector<std::string> getCanonicalCommandLine( 92 std::function<StringRef(ModuleID)> LookupPCMPath, 93 std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const; 94 95 /// Gets the canonical command line suitable for passing to clang, excluding 96 /// arguments containing modules-related paths: "-fmodule-file=", "-o", 97 /// "-fmodule-map-file=". 98 std::vector<std::string> getCanonicalCommandLineWithoutModulePaths() const; 99 }; 100 101 namespace detail { 102 /// Collect the paths of PCM and module map files for the modules in \c Modules 103 /// transitively. 104 void collectPCMAndModuleMapPaths( 105 llvm::ArrayRef<ModuleID> Modules, 106 std::function<StringRef(ModuleID)> LookupPCMPath, 107 std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps, 108 std::vector<std::string> &PCMPaths, std::vector<std::string> &ModMapPaths); 109 } // namespace detail 110 111 class ModuleDepCollector; 112 113 /// Callback that records textual includes and direct modular includes/imports 114 /// during preprocessing. At the end of the main file, it also collects 115 /// transitive modular dependencies and passes everything to the 116 /// \c DependencyConsumer of the parent \c ModuleDepCollector. 117 class ModuleDepCollectorPP final : public PPCallbacks { 118 public: ModuleDepCollectorPP(CompilerInstance & I,ModuleDepCollector & MDC)119 ModuleDepCollectorPP(CompilerInstance &I, ModuleDepCollector &MDC) 120 : Instance(I), MDC(MDC) {} 121 122 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 123 SrcMgr::CharacteristicKind FileType, 124 FileID PrevFID) override; 125 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 126 StringRef FileName, bool IsAngled, 127 CharSourceRange FilenameRange, const FileEntry *File, 128 StringRef SearchPath, StringRef RelativePath, 129 const Module *Imported, 130 SrcMgr::CharacteristicKind FileType) override; 131 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, 132 const Module *Imported) override; 133 134 void EndOfMainFile() override; 135 136 private: 137 /// The compiler instance for the current translation unit. 138 CompilerInstance &Instance; 139 /// The parent dependency collector. 140 ModuleDepCollector &MDC; 141 /// Working set of direct modular dependencies. 142 llvm::DenseSet<const Module *> DirectModularDeps; 143 144 void handleImport(const Module *Imported); 145 146 /// Traverses the previously collected direct modular dependencies to discover 147 /// transitive modular dependencies and fills the parent \c ModuleDepCollector 148 /// with both. 149 ModuleID handleTopLevelModule(const Module *M); 150 void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD, 151 llvm::DenseSet<const Module *> &AddedModules); 152 void addModuleDep(const Module *M, ModuleDeps &MD, 153 llvm::DenseSet<const Module *> &AddedModules); 154 }; 155 156 /// Collects modular and non-modular dependencies of the main file by attaching 157 /// \c ModuleDepCollectorPP to the preprocessor. 158 class ModuleDepCollector final : public DependencyCollector { 159 public: 160 ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts, 161 CompilerInstance &I, DependencyConsumer &C); 162 163 void attachToPreprocessor(Preprocessor &PP) override; 164 void attachToASTReader(ASTReader &R) override; 165 166 private: 167 friend ModuleDepCollectorPP; 168 169 /// The compiler instance for the current translation unit. 170 CompilerInstance &Instance; 171 /// The consumer of collected dependency information. 172 DependencyConsumer &Consumer; 173 /// Path to the main source file. 174 std::string MainFile; 175 /// Hash identifying the compilation conditions of the current TU. 176 std::string ContextHash; 177 /// Non-modular file dependencies. This includes the main source file and 178 /// textually included header files. 179 std::vector<std::string> FileDeps; 180 /// Direct and transitive modular dependencies of the main source file. 181 std::unordered_map<const Module *, ModuleDeps> ModularDeps; 182 /// Options that control the dependency output generation. 183 std::unique_ptr<DependencyOutputOptions> Opts; 184 }; 185 186 } // end namespace dependencies 187 } // end namespace tooling 188 } // end namespace clang 189 190 #endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H 191