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/Utils.h" 16 #include "clang/Lex/HeaderSearch.h" 17 #include "clang/Lex/PPCallbacks.h" 18 #include "clang/Serialization/ASTReader.h" 19 #include "llvm/ADT/DenseMap.h" 20 #include "llvm/ADT/StringSet.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <string> 23 #include <unordered_map> 24 25 namespace clang { 26 namespace tooling { 27 namespace dependencies { 28 29 class DependencyConsumer; 30 31 /// This is used to refer to a specific module. 32 /// 33 /// See \c ModuleDeps for details about what these members mean. 34 struct ClangModuleDep { 35 std::string ModuleName; 36 std::string ContextHash; 37 }; 38 39 struct ModuleDeps { 40 /// The name of the module. This may include `:` for C++20 module partitons, 41 /// or a header-name for C++20 header units. 42 std::string ModuleName; 43 44 /// The context hash of a module represents the set of compiler options that 45 /// may make one version of a module incompatible with another. This includes 46 /// things like language mode, predefined macros, header search paths, etc... 47 /// 48 /// Modules with the same name but a different \c ContextHash should be 49 /// treated as separate modules for the purpose of a build. 50 std::string ContextHash; 51 52 /// The path to the modulemap file which defines this module. 53 /// 54 /// This can be used to explicitly build this module. This file will 55 /// additionally appear in \c FileDeps as a dependency. 56 std::string ClangModuleMapFile; 57 58 /// The path to where an implicit build would put the PCM for this module. 59 std::string ImplicitModulePCMPath; 60 61 /// A collection of absolute paths to files that this module directly depends 62 /// on, not including transitive dependencies. 63 llvm::StringSet<> FileDeps; 64 65 /// A list of modules this module directly depends on, not including 66 /// transitive dependencies. 67 /// 68 /// This may include modules with a different context hash when it can be 69 /// determined that the differences are benign for this compilation. 70 std::vector<ClangModuleDep> ClangModuleDeps; 71 72 /// A partial command line that can be used to build this module. 73 /// 74 /// Call \c getFullCommandLine() to get a command line suitable for passing to 75 /// clang. 76 std::vector<std::string> NonPathCommandLine; 77 78 // Used to track which modules that were discovered were directly imported by 79 // the primary TU. 80 bool ImportedByMainFile = false; 81 82 /// Gets the full command line suitable for passing to clang. 83 /// 84 /// \param LookupPCMPath this function is called to fill in `-fmodule-file=` 85 /// flags and for the `-o` flag. It needs to return a 86 /// path for where the PCM for the given module is to 87 /// be located. 88 /// \param LookupModuleDeps this fucntion is called to collect the full 89 /// transitive set of dependencies for this 90 /// compilation. 91 std::vector<std::string> getFullCommandLine( 92 std::function<StringRef(ClangModuleDep)> LookupPCMPath, 93 std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps) const; 94 }; 95 96 namespace detail { 97 /// Append the `-fmodule-file=` and `-fmodule-map-file=` arguments for the 98 /// modules in \c Modules transitively, along with other needed arguments to 99 /// use explicitly built modules. 100 void appendCommonModuleArguments( 101 llvm::ArrayRef<ClangModuleDep> Modules, 102 std::function<StringRef(ClangModuleDep)> LookupPCMPath, 103 std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps, 104 std::vector<std::string> &Result); 105 } // namespace detail 106 107 class ModuleDepCollector; 108 109 class ModuleDepCollectorPP final : public PPCallbacks { 110 public: ModuleDepCollectorPP(CompilerInstance & I,ModuleDepCollector & MDC)111 ModuleDepCollectorPP(CompilerInstance &I, ModuleDepCollector &MDC) 112 : Instance(I), MDC(MDC) {} 113 114 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 115 SrcMgr::CharacteristicKind FileType, 116 FileID PrevFID) override; 117 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 118 StringRef FileName, bool IsAngled, 119 CharSourceRange FilenameRange, const FileEntry *File, 120 StringRef SearchPath, StringRef RelativePath, 121 const Module *Imported, 122 SrcMgr::CharacteristicKind FileType) override; 123 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, 124 const Module *Imported) override; 125 126 void EndOfMainFile() override; 127 128 private: 129 CompilerInstance &Instance; 130 ModuleDepCollector &MDC; 131 llvm::DenseSet<const Module *> DirectDeps; 132 133 void handleImport(const Module *Imported); 134 void handleTopLevelModule(const Module *M); 135 void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD, 136 llvm::DenseSet<const Module *> &AddedModules); 137 void addModuleDep(const Module *M, ModuleDeps &MD, 138 llvm::DenseSet<const Module *> &AddedModules); 139 }; 140 141 class ModuleDepCollector final : public DependencyCollector { 142 public: 143 ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts, 144 CompilerInstance &I, DependencyConsumer &C); 145 146 void attachToPreprocessor(Preprocessor &PP) override; 147 void attachToASTReader(ASTReader &R) override; 148 149 private: 150 friend ModuleDepCollectorPP; 151 152 CompilerInstance &Instance; 153 DependencyConsumer &Consumer; 154 std::string MainFile; 155 std::string ContextHash; 156 std::vector<std::string> MainDeps; 157 std::unordered_map<std::string, ModuleDeps> Deps; 158 std::unique_ptr<DependencyOutputOptions> Opts; 159 }; 160 161 } // end namespace dependencies 162 } // end namespace tooling 163 } // end namespace clang 164 165 #endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H 166