xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
1480093f4SDimitry Andric //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
9a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
10a7dea167SDimitry Andric #include "clang/Frontend/Utils.h"
11a7dea167SDimitry Andric 
12753f127fSDimitry Andric using namespace clang;
13753f127fSDimitry Andric using namespace tooling;
14753f127fSDimitry Andric using namespace dependencies;
15a7dea167SDimitry Andric 
1681ad6265SDimitry Andric std::vector<std::string> FullDependencies::getCommandLine(
17753f127fSDimitry Andric     llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
18753f127fSDimitry Andric         LookupModuleOutput) const {
1981ad6265SDimitry Andric   std::vector<std::string> Ret = getCommandLineWithoutModulePaths();
205ffd83dbSDimitry Andric 
21753f127fSDimitry Andric   for (ModuleID MID : ClangModuleDeps) {
22753f127fSDimitry Andric     auto PCM = LookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
23753f127fSDimitry Andric     Ret.push_back("-fmodule-file=" + PCM);
24753f127fSDimitry Andric   }
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric   return Ret;
275ffd83dbSDimitry Andric }
285ffd83dbSDimitry Andric 
29fe6060f1SDimitry Andric std::vector<std::string>
3081ad6265SDimitry Andric FullDependencies::getCommandLineWithoutModulePaths() const {
3181ad6265SDimitry Andric   std::vector<std::string> Args = OriginalCommandLine;
32fe6060f1SDimitry Andric 
3381ad6265SDimitry Andric   Args.push_back("-fno-implicit-modules");
3481ad6265SDimitry Andric   Args.push_back("-fno-implicit-module-maps");
35349cc55cSDimitry Andric   for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
36349cc55cSDimitry Andric     Args.push_back("-fmodule-file=" + PMD.PCMFile);
37fe6060f1SDimitry Andric 
3881ad6265SDimitry Andric   // These arguments are unused in explicit compiles.
3981ad6265SDimitry Andric   llvm::erase_if(Args, [](StringRef Arg) {
4081ad6265SDimitry Andric     if (Arg.consume_front("-fmodules-")) {
4181ad6265SDimitry Andric       return Arg.startswith("cache-path=") ||
4281ad6265SDimitry Andric              Arg.startswith("prune-interval=") ||
4381ad6265SDimitry Andric              Arg.startswith("prune-after=") ||
4481ad6265SDimitry Andric              Arg == "validate-once-per-build-session";
4581ad6265SDimitry Andric     }
4681ad6265SDimitry Andric     return Arg.startswith("-fbuild-session-file=");
4781ad6265SDimitry Andric   });
4881ad6265SDimitry Andric 
49fe6060f1SDimitry Andric   return Args;
50fe6060f1SDimitry Andric }
51fe6060f1SDimitry Andric 
52480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool(
53*fcaf7f86SDimitry Andric     DependencyScanningService &Service,
54*fcaf7f86SDimitry Andric     llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
55*fcaf7f86SDimitry Andric     : Worker(Service, std::move(FS)) {}
56a7dea167SDimitry Andric 
57480093f4SDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
58349cc55cSDimitry Andric     const std::vector<std::string> &CommandLine, StringRef CWD,
59349cc55cSDimitry Andric     llvm::Optional<StringRef> ModuleName) {
60a7dea167SDimitry Andric   /// Prints out all of the gathered dependencies into a string.
61480093f4SDimitry Andric   class MakeDependencyPrinterConsumer : public DependencyConsumer {
62a7dea167SDimitry Andric   public:
63fe6060f1SDimitry Andric     void
64fe6060f1SDimitry Andric     handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
65a7dea167SDimitry Andric       this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
66fe6060f1SDimitry Andric     }
67fe6060f1SDimitry Andric 
68fe6060f1SDimitry Andric     void handleFileDependency(StringRef File) override {
695ffd83dbSDimitry Andric       Dependencies.push_back(std::string(File));
70a7dea167SDimitry Andric     }
71a7dea167SDimitry Andric 
72fe6060f1SDimitry Andric     void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
73fe6060f1SDimitry Andric       // Same as `handleModuleDependency`.
74fe6060f1SDimitry Andric     }
75fe6060f1SDimitry Andric 
76480093f4SDimitry Andric     void handleModuleDependency(ModuleDeps MD) override {
77480093f4SDimitry Andric       // These are ignored for the make format as it can't support the full
78480093f4SDimitry Andric       // set of deps, and handleFileDependency handles enough for implicitly
79480093f4SDimitry Andric       // built modules to work.
80480093f4SDimitry Andric     }
81480093f4SDimitry Andric 
82480093f4SDimitry Andric     void handleContextHash(std::string Hash) override {}
83480093f4SDimitry Andric 
84a7dea167SDimitry Andric     void printDependencies(std::string &S) {
85fe6060f1SDimitry Andric       assert(Opts && "Handled dependency output options.");
86a7dea167SDimitry Andric 
87a7dea167SDimitry Andric       class DependencyPrinter : public DependencyFileGenerator {
88a7dea167SDimitry Andric       public:
89a7dea167SDimitry Andric         DependencyPrinter(DependencyOutputOptions &Opts,
90a7dea167SDimitry Andric                           ArrayRef<std::string> Dependencies)
91a7dea167SDimitry Andric             : DependencyFileGenerator(Opts) {
92a7dea167SDimitry Andric           for (const auto &Dep : Dependencies)
93a7dea167SDimitry Andric             addDependency(Dep);
94a7dea167SDimitry Andric         }
95a7dea167SDimitry Andric 
96a7dea167SDimitry Andric         void printDependencies(std::string &S) {
97a7dea167SDimitry Andric           llvm::raw_string_ostream OS(S);
98a7dea167SDimitry Andric           outputDependencyFile(OS);
99a7dea167SDimitry Andric         }
100a7dea167SDimitry Andric       };
101a7dea167SDimitry Andric 
102a7dea167SDimitry Andric       DependencyPrinter Generator(*Opts, Dependencies);
103a7dea167SDimitry Andric       Generator.printDependencies(S);
104a7dea167SDimitry Andric     }
105a7dea167SDimitry Andric 
106a7dea167SDimitry Andric   private:
107a7dea167SDimitry Andric     std::unique_ptr<DependencyOutputOptions> Opts;
108a7dea167SDimitry Andric     std::vector<std::string> Dependencies;
109a7dea167SDimitry Andric   };
110a7dea167SDimitry Andric 
1115ffd83dbSDimitry Andric   MakeDependencyPrinterConsumer Consumer;
112349cc55cSDimitry Andric   auto Result =
113349cc55cSDimitry Andric       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
1145ffd83dbSDimitry Andric   if (Result)
1155ffd83dbSDimitry Andric     return std::move(Result);
1165ffd83dbSDimitry Andric   std::string Output;
1175ffd83dbSDimitry Andric   Consumer.printDependencies(Output);
1185ffd83dbSDimitry Andric   return Output;
1195ffd83dbSDimitry Andric }
1205ffd83dbSDimitry Andric 
1215ffd83dbSDimitry Andric llvm::Expected<FullDependenciesResult>
1225ffd83dbSDimitry Andric DependencyScanningTool::getFullDependencies(
123349cc55cSDimitry Andric     const std::vector<std::string> &CommandLine, StringRef CWD,
124349cc55cSDimitry Andric     const llvm::StringSet<> &AlreadySeen,
125349cc55cSDimitry Andric     llvm::Optional<StringRef> ModuleName) {
126480093f4SDimitry Andric   class FullDependencyPrinterConsumer : public DependencyConsumer {
127480093f4SDimitry Andric   public:
1285ffd83dbSDimitry Andric     FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen)
1295ffd83dbSDimitry Andric         : AlreadySeen(AlreadySeen) {}
1305ffd83dbSDimitry Andric 
131fe6060f1SDimitry Andric     void
132fe6060f1SDimitry Andric     handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {}
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric     void handleFileDependency(StringRef File) override {
1355ffd83dbSDimitry Andric       Dependencies.push_back(std::string(File));
136480093f4SDimitry Andric     }
137480093f4SDimitry Andric 
138fe6060f1SDimitry Andric     void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
139fe6060f1SDimitry Andric       PrebuiltModuleDeps.emplace_back(std::move(PMD));
140fe6060f1SDimitry Andric     }
141fe6060f1SDimitry Andric 
142480093f4SDimitry Andric     void handleModuleDependency(ModuleDeps MD) override {
143fe6060f1SDimitry Andric       ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD);
144480093f4SDimitry Andric     }
145480093f4SDimitry Andric 
146480093f4SDimitry Andric     void handleContextHash(std::string Hash) override {
147480093f4SDimitry Andric       ContextHash = std::move(Hash);
148480093f4SDimitry Andric     }
149480093f4SDimitry Andric 
15081ad6265SDimitry Andric     FullDependenciesResult getFullDependencies(
15181ad6265SDimitry Andric         const std::vector<std::string> &OriginalCommandLine) const {
1525ffd83dbSDimitry Andric       FullDependencies FD;
153480093f4SDimitry Andric 
15481ad6265SDimitry Andric       FD.OriginalCommandLine =
15581ad6265SDimitry Andric           ArrayRef<std::string>(OriginalCommandLine).slice(1);
15681ad6265SDimitry Andric 
157fe6060f1SDimitry Andric       FD.ID.ContextHash = std::move(ContextHash);
158480093f4SDimitry Andric 
1595ffd83dbSDimitry Andric       FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
160480093f4SDimitry Andric 
1615ffd83dbSDimitry Andric       for (auto &&M : ClangModuleDeps) {
1625ffd83dbSDimitry Andric         auto &MD = M.second;
163480093f4SDimitry Andric         if (MD.ImportedByMainFile)
164fe6060f1SDimitry Andric           FD.ClangModuleDeps.push_back(MD.ID);
165480093f4SDimitry Andric       }
166480093f4SDimitry Andric 
167fe6060f1SDimitry Andric       FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
168fe6060f1SDimitry Andric 
1695ffd83dbSDimitry Andric       FullDependenciesResult FDR;
1705ffd83dbSDimitry Andric 
1715ffd83dbSDimitry Andric       for (auto &&M : ClangModuleDeps) {
1725ffd83dbSDimitry Andric         // TODO: Avoid handleModuleDependency even being called for modules
1735ffd83dbSDimitry Andric         //   we've already seen.
1745ffd83dbSDimitry Andric         if (AlreadySeen.count(M.first))
1755ffd83dbSDimitry Andric           continue;
1765ffd83dbSDimitry Andric         FDR.DiscoveredModules.push_back(std::move(M.second));
177480093f4SDimitry Andric       }
178480093f4SDimitry Andric 
1795ffd83dbSDimitry Andric       FDR.FullDeps = std::move(FD);
1805ffd83dbSDimitry Andric       return FDR;
181480093f4SDimitry Andric     }
182480093f4SDimitry Andric 
183480093f4SDimitry Andric   private:
184480093f4SDimitry Andric     std::vector<std::string> Dependencies;
185fe6060f1SDimitry Andric     std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
18681ad6265SDimitry Andric     llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> ClangModuleDeps;
187480093f4SDimitry Andric     std::string ContextHash;
1885ffd83dbSDimitry Andric     std::vector<std::string> OutputPaths;
1895ffd83dbSDimitry Andric     const llvm::StringSet<> &AlreadySeen;
190480093f4SDimitry Andric   };
191480093f4SDimitry Andric 
1925ffd83dbSDimitry Andric   FullDependencyPrinterConsumer Consumer(AlreadySeen);
1935ffd83dbSDimitry Andric   llvm::Error Result =
194349cc55cSDimitry Andric       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
195a7dea167SDimitry Andric   if (Result)
196a7dea167SDimitry Andric     return std::move(Result);
19781ad6265SDimitry Andric   return Consumer.getFullDependencies(CommandLine);
198a7dea167SDimitry Andric }
199