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:
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