forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			174 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
 | |
| //
 | |
| // 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
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
 | |
| #include "clang/Frontend/Utils.h"
 | |
| 
 | |
| namespace clang{
 | |
| namespace tooling{
 | |
| namespace dependencies{
 | |
| 
 | |
| std::vector<std::string> FullDependencies::getAdditionalCommandLine(
 | |
|     std::function<StringRef(ClangModuleDep)> LookupPCMPath,
 | |
|     std::function<const ModuleDeps &(ClangModuleDep)> LookupModuleDeps) const {
 | |
|   std::vector<std::string> Ret = AdditionalNonPathCommandLine;
 | |
| 
 | |
|   dependencies::detail::appendCommonModuleArguments(
 | |
|       ClangModuleDeps, LookupPCMPath, LookupModuleDeps, Ret);
 | |
| 
 | |
|   return Ret;
 | |
| }
 | |
| 
 | |
| DependencyScanningTool::DependencyScanningTool(
 | |
|     DependencyScanningService &Service)
 | |
|     : Worker(Service) {}
 | |
| 
 | |
| llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
 | |
|     const tooling::CompilationDatabase &Compilations, StringRef CWD) {
 | |
|   /// Prints out all of the gathered dependencies into a string.
 | |
|   class MakeDependencyPrinterConsumer : public DependencyConsumer {
 | |
|   public:
 | |
|     void handleFileDependency(const DependencyOutputOptions &Opts,
 | |
|                               StringRef File) override {
 | |
|       if (!this->Opts)
 | |
|         this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
 | |
|       Dependencies.push_back(std::string(File));
 | |
|     }
 | |
| 
 | |
|     void handleModuleDependency(ModuleDeps MD) override {
 | |
|       // These are ignored for the make format as it can't support the full
 | |
|       // set of deps, and handleFileDependency handles enough for implicitly
 | |
|       // built modules to work.
 | |
|     }
 | |
| 
 | |
|     void handleContextHash(std::string Hash) override {}
 | |
| 
 | |
|     void printDependencies(std::string &S) {
 | |
|       if (!Opts)
 | |
|         return;
 | |
| 
 | |
|       class DependencyPrinter : public DependencyFileGenerator {
 | |
|       public:
 | |
|         DependencyPrinter(DependencyOutputOptions &Opts,
 | |
|                           ArrayRef<std::string> Dependencies)
 | |
|             : DependencyFileGenerator(Opts) {
 | |
|           for (const auto &Dep : Dependencies)
 | |
|             addDependency(Dep);
 | |
|         }
 | |
| 
 | |
|         void printDependencies(std::string &S) {
 | |
|           llvm::raw_string_ostream OS(S);
 | |
|           outputDependencyFile(OS);
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       DependencyPrinter Generator(*Opts, Dependencies);
 | |
|       Generator.printDependencies(S);
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     std::unique_ptr<DependencyOutputOptions> Opts;
 | |
|     std::vector<std::string> Dependencies;
 | |
|   };
 | |
| 
 | |
|   // We expect a single command here because if a source file occurs multiple
 | |
|   // times in the original CDB, then `computeDependencies` would run the
 | |
|   // `DependencyScanningAction` once for every time the input occured in the
 | |
|   // CDB. Instead we split up the CDB into single command chunks to avoid this
 | |
|   // behavior.
 | |
|   assert(Compilations.getAllCompileCommands().size() == 1 &&
 | |
|          "Expected a compilation database with a single command!");
 | |
|   std::string Input = Compilations.getAllCompileCommands().front().Filename;
 | |
| 
 | |
|   MakeDependencyPrinterConsumer Consumer;
 | |
|   auto Result = Worker.computeDependencies(Input, CWD, Compilations, Consumer);
 | |
|   if (Result)
 | |
|     return std::move(Result);
 | |
|   std::string Output;
 | |
|   Consumer.printDependencies(Output);
 | |
|   return Output;
 | |
| }
 | |
| 
 | |
| llvm::Expected<FullDependenciesResult>
 | |
| DependencyScanningTool::getFullDependencies(
 | |
|     const tooling::CompilationDatabase &Compilations, StringRef CWD,
 | |
|     const llvm::StringSet<> &AlreadySeen) {
 | |
|   class FullDependencyPrinterConsumer : public DependencyConsumer {
 | |
|   public:
 | |
|     FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen)
 | |
|         : AlreadySeen(AlreadySeen) {}
 | |
| 
 | |
|     void handleFileDependency(const DependencyOutputOptions &Opts,
 | |
|                               StringRef File) override {
 | |
|       Dependencies.push_back(std::string(File));
 | |
|     }
 | |
| 
 | |
|     void handleModuleDependency(ModuleDeps MD) override {
 | |
|       ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD);
 | |
|     }
 | |
| 
 | |
|     void handleContextHash(std::string Hash) override {
 | |
|       ContextHash = std::move(Hash);
 | |
|     }
 | |
| 
 | |
|     FullDependenciesResult getFullDependencies() const {
 | |
|       FullDependencies FD;
 | |
| 
 | |
|       FD.ContextHash = std::move(ContextHash);
 | |
| 
 | |
|       FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
 | |
| 
 | |
|       for (auto &&M : ClangModuleDeps) {
 | |
|         auto &MD = M.second;
 | |
|         if (MD.ImportedByMainFile)
 | |
|           FD.ClangModuleDeps.push_back({MD.ModuleName, ContextHash});
 | |
|       }
 | |
| 
 | |
|       FullDependenciesResult FDR;
 | |
| 
 | |
|       for (auto &&M : ClangModuleDeps) {
 | |
|         // TODO: Avoid handleModuleDependency even being called for modules
 | |
|         //   we've already seen.
 | |
|         if (AlreadySeen.count(M.first))
 | |
|           continue;
 | |
|         FDR.DiscoveredModules.push_back(std::move(M.second));
 | |
|       }
 | |
| 
 | |
|       FDR.FullDeps = std::move(FD);
 | |
|       return FDR;
 | |
|     }
 | |
| 
 | |
|   private:
 | |
|     std::vector<std::string> Dependencies;
 | |
|     std::unordered_map<std::string, ModuleDeps> ClangModuleDeps;
 | |
|     std::string ContextHash;
 | |
|     std::vector<std::string> OutputPaths;
 | |
|     const llvm::StringSet<> &AlreadySeen;
 | |
|   };
 | |
| 
 | |
|   // We expect a single command here because if a source file occurs multiple
 | |
|   // times in the original CDB, then `computeDependencies` would run the
 | |
|   // `DependencyScanningAction` once for every time the input occured in the
 | |
|   // CDB. Instead we split up the CDB into single command chunks to avoid this
 | |
|   // behavior.
 | |
|   assert(Compilations.getAllCompileCommands().size() == 1 &&
 | |
|          "Expected a compilation database with a single command!");
 | |
|   std::string Input = Compilations.getAllCompileCommands().front().Filename;
 | |
| 
 | |
|   FullDependencyPrinterConsumer Consumer(AlreadySeen);
 | |
|   llvm::Error Result =
 | |
|       Worker.computeDependencies(Input, CWD, Compilations, Consumer);
 | |
|   if (Result)
 | |
|     return std::move(Result);
 | |
|   return Consumer.getFullDependencies();
 | |
| }
 | |
| 
 | |
| } // end namespace dependencies
 | |
| } // end namespace tooling
 | |
| } // end namespace clang
 |