jansvoboda11 created this revision.
jansvoboda11 added reviewers: Bigcheese, dexonsmith.
jansvoboda11 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

To reduce the number of explicit builds of a single module, we can try to 
squash multiple occurances of the module with different command-lines (and 
context hashes) by removing benign command-line options. The greatest 
contributors to benign differences between command-lines are the header search 
paths.

In this patch, the lookup cache in `HeaderSearch` is used to determine which 
paths were actually used when implicitly building the module during scanning. 
This information is serialized into the unhashed control block of the 
implicitly-built PCM. The dependency scanner then loads this and may use it to 
prune the header search paths before computing the context hash of the module 
and generating the command-line.

We could also prune the header search paths when serializing 
`HeaderSearchOptions` into the PCM. That way, we could do it only once instead 
of every load of the PCM file by dependency scanner. However, that would result 
in a PCM file whose contents don't produce the same context hash, which is 
probably highly surprising.

There is an alternative approach to storing extra information into the PCM: 
wire up preprocessor callbacks to capture the used header search paths 
on-the-fly during preprocessing of modularized headers (similar to what we 
currently do for the main source file and textual headers). Right now, that's 
not compatible with the fact that we do an actual implicit build producing PCM 
files during dependency scanning. The second run of dependency scanner loads 
the PCM from the first run, skipping the preprocessing altogether, which would 
result in different results between runs. We can revisit this approach when we


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D102488

Files:
  clang/include/clang/Lex/HeaderSearch.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/include/clang/Serialization/ModuleFile.h
  clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
  clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
  clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
  clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
  clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
  clang/test/ClangScanDeps/Inputs/header-search-pruning/a/a.h
  clang/test/ClangScanDeps/Inputs/header-search-pruning/b/b.h
  clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json
  clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h
  clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap
  clang/test/ClangScanDeps/header-search-pruning.cpp
  clang/test/ClangScanDeps/modules-full.cpp
  clang/tools/clang-scan-deps/ClangScanDeps.cpp

Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp
===================================================================
--- clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -163,6 +163,11 @@
         "'-fmodule-file=', '-o', '-fmodule-map-file='."),
     llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
 
+static llvm::cl::opt<bool> OptimizeArgs(
+    "optimize-args",
+    llvm::cl::desc("Whether to optimize command-line arguments of modules."),
+    llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
+
 llvm::cl::opt<unsigned>
     NumThreads("j", llvm::cl::Optional,
                llvm::cl::desc("Number of worker threads to use (default: use "
@@ -357,7 +362,26 @@
 
 private:
   StringRef lookupPCMPath(ModuleID MID) {
-    return Modules[IndexedModuleID{MID, 0}].ImplicitModulePCMPath;
+    auto PCMPath = PCMPaths.insert({IndexedModuleID{MID, 0}, ""});
+    if (PCMPath.second)
+      PCMPath.first->second = constructPCMPath(lookupModuleDeps(MID));
+    return PCMPath.first->second;
+  }
+
+  /// Construct a path where to put the explicitly built PCM - essentially the
+  /// path to implicitly built PCM with the context hash replaced by the final
+  /// (potentially modified) context hash.
+  std::string constructPCMPath(const ModuleDeps &MD) const {
+    const std::string &ImplicitPCMPath = MD.ImplicitModulePCMPath;
+    StringRef Filename = llvm::sys::path::filename(ImplicitPCMPath);
+    StringRef ImplicitContextHashPath =
+        llvm::sys::path::parent_path(ImplicitPCMPath);
+    StringRef ModuleCachePath =
+        llvm::sys::path::parent_path(ImplicitContextHashPath);
+
+    SmallString<64> ExplicitPCMPath = ModuleCachePath;
+    llvm::sys::path::append(ExplicitPCMPath, MD.ID.ContextHash, Filename);
+    return std::string(ExplicitPCMPath);
   }
 
   const ModuleDeps &lookupModuleDeps(ModuleID MID) {
@@ -395,6 +419,8 @@
   std::mutex Lock;
   std::unordered_map<IndexedModuleID, ModuleDeps, IndexedModuleIDHasher>
       Modules;
+  std::unordered_map<IndexedModuleID, std::string, IndexedModuleIDHasher>
+      PCMPaths;
   std::vector<InputDeps> Inputs;
 };
 
@@ -554,7 +580,7 @@
   SharedStream DependencyOS(llvm::outs());
 
   DependencyScanningService Service(ScanMode, Format, ReuseFileManager,
-                                    SkipExcludedPPRanges);
+                                    SkipExcludedPPRanges, OptimizeArgs);
   llvm::ThreadPool Pool(llvm::hardware_concurrency(NumThreads));
   std::vector<std::unique_ptr<DependencyScanningTool>> WorkerTools;
   for (unsigned I = 0; I < Pool.getThreadCount(); ++I)
Index: clang/test/ClangScanDeps/modules-full.cpp
===================================================================
--- clang/test/ClangScanDeps/modules-full.cpp
+++ clang/test/ClangScanDeps/modules-full.cpp
@@ -96,7 +96,7 @@
 // CHECK-NEXT:   ],
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
-// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H2]]",
+// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H3:[A-Z0-9]+]]",
 // CHECK-NEXT:       "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[CONTEXT_HASH_H2]]",
@@ -117,7 +117,7 @@
 // CHECK-NEXT:       "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
 // CHECK-NEXT:     },
 // CHECK-NEXT:     {
-// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H2]]",
+// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H3]]",
 // CHECK-NEXT:       "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[CONTEXT_HASH_H2]]",
@@ -138,7 +138,7 @@
 // CHECK-NEXT:       "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
 // CHECK-NEXT:     },
 // CHECK-NEXT:     {
-// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H2]]",
+// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H3]]",
 // CHECK-NEXT:       "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[CONTEXT_HASH_H2]]",
@@ -159,7 +159,7 @@
 // CHECK-NEXT:       "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
 // CHECK-NEXT:     },
 // CHECK-NEXT:     {
-// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H1]]",
+// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H4:[A-Z0-9]+]]",
 // CHECK-NEXT:       "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[CONTEXT_HASH_H1]]",
Index: clang/test/ClangScanDeps/header-search-pruning.cpp
===================================================================
--- /dev/null
+++ clang/test/ClangScanDeps/header-search-pruning.cpp
@@ -0,0 +1,87 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: cp -r %S/Inputs/header-search-pruning/* %t
+// RUN: cp %S/header-search-pruning.cpp %t/header-search-pruning.cpp
+// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_A|g"             %S/Inputs/header-search-pruning/cdb.json > %t/cdb_a.json
+// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_B|g"             %S/Inputs/header-search-pruning/cdb.json > %t/cdb_b.json
+// RUN: sed -e "s|DIR|%t|g" -e "s|DEFINES|-DINCLUDE_A -DINCLUDE_B|g" %S/Inputs/header-search-pruning/cdb.json > %t/cdb_ab.json
+//
+// RUN: clang-scan-deps -compilation-database %t/cdb_a.json -format experimental-full -optimize-args >> %t/result_a.json
+// RUN: cat %t/result_a.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_A %s
+//
+// RUN: clang-scan-deps -compilation-database %t/cdb_b.json -format experimental-full -optimize-args >> %t/result_b.json
+// RUN: cat %t/result_b.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_B %s
+//
+// RUN: clang-scan-deps -compilation-database %t/cdb_ab.json -format experimental-full -optimize-args >> %t/result_ab.json
+// RUN: cat %t/result_ab.json | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK_AB %s
+
+#include "mod.h"
+
+// CHECK_A:        {
+// CHECK_A-NEXT:     "modules": [
+// CHECK_A-NEXT:       {
+// CHECK_A-NEXT:         "clang-module-deps": [],
+// CHECK_A-NEXT:         "clang-modulemap-file": "{{.*}}",
+// CHECK_A-NEXT:         "command-line": [
+// CHECK_A-NEXT:           "-cc1"
+// CHECK_A:                "-I"
+// CHECK_A:                "a"
+// CHECK_A-NOT:            "-I"
+// CHECK_A-NOT:            "b"
+// CHECK_A:              ],
+// CHECK_A-NEXT:         "context-hash": "[[HASH:.*]]",
+// CHECK_A-NEXT:         "file-deps": [
+// CHECK_A-NEXT:           "[[PREFIX:.*]]/a/a.h",
+// CHECK_A-NEXT:           "[[PREFIX]]/mod.h",
+// CHECK_A-NEXT:           "[[PREFIX]]/module.modulemap"
+// CHECK_A-NEXT:         ],
+// CHECK_A-NEXT:         "name": "mod"
+// CHECK_A-NEXT:       }
+// CHECK_A-NEXT:     ]
+// CHECK_A:        }
+
+// CHECK_B:        {
+// CHECK_B-NEXT:     "modules": [
+// CHECK_B-NEXT:       {
+// CHECK_B-NEXT:         "clang-module-deps": [],
+// CHECK_B-NEXT:         "clang-modulemap-file": "{{.*}}",
+// CHECK_B-NEXT:         "command-line": [
+// CHECK_B-NEXT:           "-cc1"
+// CHECK_B-NOT:            "-I"
+// CHECK_B-NOT:            "a"
+// CHECK_B:                "-I"
+// CHECK_B:                "b"
+// CHECK_B:              ],
+// CHECK_B-NEXT:         "context-hash": "[[HASH:.*]]",
+// CHECK_B-NEXT:         "file-deps": [
+// CHECK_B-NEXT:           "[[PREFIX:.*]]/b/b.h",
+// CHECK_B-NEXT:           "[[PREFIX]]/mod.h",
+// CHECK_B-NEXT:           "[[PREFIX]]/module.modulemap"
+// CHECK_B-NEXT:         ],
+// CHECK_B-NEXT:         "name": "mod"
+// CHECK_B-NEXT:       }
+// CHECK_B-NEXT:     ]
+// CHECK_B:        }
+
+// CHECK_AB:       {
+// CHECK_AB-NEXT:    "modules": [
+// CHECK_AB-NEXT:      {
+// CHECK_AB-NEXT:        "clang-module-deps": [],
+// CHECK_AB-NEXT:        "clang-modulemap-file": "{{.*}}",
+// CHECK_AB-NEXT:        "command-line": [
+// CHECK_AB-NEXT:          "-cc1"
+// CHECK_AB:               "-I"
+// CHECK_AB:               "a"
+// CHECK_AB:               "-I"
+// CHECK_AB:               "b"
+// CHECK_AB:             ],
+// CHECK_AB-NEXT:        "context-hash": "[[HASH:.*]]",
+// CHECK_AB-NEXT:        "file-deps": [
+// CHECK_AB-NEXT:          "[[PREFIX:.*]]/a/a.h",
+// CHECK_AB-NEXT:          "[[PREFIX:.*]]/b/b.h",
+// CHECK_AB-NEXT:          "[[PREFIX]]/mod.h",
+// CHECK_AB-NEXT:          "[[PREFIX]]/module.modulemap"
+// CHECK_AB-NEXT:        ],
+// CHECK_AB-NEXT:        "name": "mod"
+// CHECK_AB-NEXT:      }
+// CHECK_AB-NEXT:    ]
+// CHECK_AB:       }
Index: clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/ClangScanDeps/Inputs/header-search-pruning/module.modulemap
@@ -0,0 +1,4 @@
+module mod {
+    header "mod.h"
+    export *
+}
Index: clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h
===================================================================
--- /dev/null
+++ clang/test/ClangScanDeps/Inputs/header-search-pruning/mod.h
@@ -0,0 +1,7 @@
+#ifdef INCLUDE_A
+#include "a.h"
+#endif
+
+#ifdef INCLUDE_B
+#include "b.h"
+#endif
Index: clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json
===================================================================
--- /dev/null
+++ clang/test/ClangScanDeps/Inputs/header-search-pruning/cdb.json
@@ -0,0 +1,7 @@
+[
+  {
+    "directory": "DIR",
+    "command": "clang -E DIR/header-search-pruning.cpp -Ia -Ib DEFINES -fmodules -fcxx-modules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fmodule-map-file=DIR/module.modulemap",
+    "file": "DIR/header-search-pruning.cpp"
+  }
+]
Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -18,9 +18,19 @@
 using namespace tooling;
 using namespace dependencies;
 
-static CompilerInvocation
-makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps,
-                                         const CompilerInvocation &Invocation) {
+static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts,
+                                     const std::set<unsigned> &UsedEntryIdxs) {
+  std::vector<HeaderSearchOptions::Entry> &Entries = Opts.UserEntries;
+  std::vector<HeaderSearchOptions::Entry> OrigEntries(Entries);
+
+  Entries.clear();
+  for (unsigned Idx : UsedEntryIdxs)
+    Entries.push_back(OrigEntries[Idx]);
+}
+
+static CompilerInvocation makeInvocationForModuleBuildWithoutPaths(
+    const ModuleDeps &Deps, const CompilerInvocation &Invocation,
+    llvm::function_ref<void(CompilerInvocation &)> Optimize) {
   // Make a deep copy of the invocation.
   CompilerInvocation CI(Invocation);
 
@@ -35,6 +45,8 @@
   CI.getLangOpts()->ImplicitModules = false;
   CI.getHeaderSearchOpts().ImplicitModuleMaps = false;
 
+  Optimize(CI);
+
   return CI;
 }
 
@@ -189,8 +201,12 @@
         MD.FileDeps.insert(IF.getFile()->getName());
       });
 
-  MD.Invocation =
-      makeInvocationForModuleBuildWithoutPaths(MD, Instance.getInvocation());
+  MD.Invocation = makeInvocationForModuleBuildWithoutPaths(
+      MD, Instance.getInvocation(), [&](CompilerInvocation &CI) {
+        if (MDC.OptimizeArgs)
+          optimizeHeaderSearchOpts(CI.getHeaderSearchOpts(),
+                                   MF->UsedHeaderSearchPathIdxs);
+      });
   MD.ID.ContextHash = MD.Invocation.getModuleHash();
 
   llvm::DenseSet<const Module *> AddedModules;
@@ -222,8 +238,9 @@
 
 ModuleDepCollector::ModuleDepCollector(
     std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I,
-    DependencyConsumer &C)
-    : Instance(I), Consumer(C), Opts(std::move(Opts)) {}
+    DependencyConsumer &C, bool OptimizeArgs)
+    : Instance(I), Consumer(C), OptimizeArgs(OptimizeArgs),
+      Opts(std::move(Opts)) {}
 
 void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
   PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this));
Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -52,10 +52,10 @@
       StringRef WorkingDirectory, DependencyConsumer &Consumer,
       llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
       ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings,
-      ScanningOutputFormat Format)
+      ScanningOutputFormat Format, bool OptimizeArgs)
       : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
-        DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings),
-        Format(Format) {}
+        DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), Format(Format),
+        OptimizeArgs(OptimizeArgs) {}
 
   bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
                      FileManager *FileMgr,
@@ -121,7 +121,7 @@
       break;
     case ScanningOutputFormat::Full:
       Compiler.addDependencyCollector(std::make_shared<ModuleDepCollector>(
-          std::move(Opts), Compiler, Consumer));
+          std::move(Opts), Compiler, Consumer, OptimizeArgs));
       break;
     }
 
@@ -145,13 +145,14 @@
   llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
   ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
   ScanningOutputFormat Format;
+  bool OptimizeArgs;
 };
 
 } // end anonymous namespace
 
 DependencyScanningWorker::DependencyScanningWorker(
     DependencyScanningService &Service)
-    : Format(Service.getFormat()) {
+    : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) {
   DiagOpts = new DiagnosticOptions();
   PCHContainerOps = std::make_shared<PCHContainerOperations>();
   RealFS = llvm::vfs::createPhysicalFileSystem();
@@ -194,7 +195,7 @@
     Tool.setPrintErrorMessage(false);
     Tool.setDiagnosticConsumer(&DC);
     DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
-                                    PPSkipMappings.get(), Format);
+                                    PPSkipMappings.get(), Format, OptimizeArgs);
     return !Tool.run(&Action);
   });
 }
Index: clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
+++ clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -14,6 +14,6 @@
 
 DependencyScanningService::DependencyScanningService(
     ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager,
-    bool SkipExcludedPPRanges)
+    bool SkipExcludedPPRanges, bool OptimizeArgs)
     : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager),
-      SkipExcludedPPRanges(SkipExcludedPPRanges) {}
+      SkipExcludedPPRanges(SkipExcludedPPRanges), OptimizeArgs(OptimizeArgs) {}
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -1097,6 +1097,16 @@
   // Write out the diagnostic/pragma mappings.
   WritePragmaDiagnosticMappings(Diags, /* isModule = */ WritingModule);
 
+  Record.clear();
+
+  // Used search path indices.
+  auto UsedSearchPathIdxs = PP.getHeaderSearchInfo().GetUsedSearchPathIdxs();
+  Record.push_back(UsedSearchPathIdxs.size());
+  for (unsigned Idx : UsedSearchPathIdxs)
+    Record.push_back(Idx);
+
+  Stream.EmitRecord(USED_HEADER_SEARCH_PATHS, Record);
+
   // Leave the options block.
   Stream.ExitBlock();
   return Signature;
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -4795,6 +4795,14 @@
         F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(),
                                      Record.begin(), Record.end());
       break;
+    case USED_HEADER_SEARCH_PATHS:
+      if (F) {
+        unsigned Idx = 0;
+        unsigned Count = Record[Idx++];
+        for (unsigned I = 0; I < Count; ++I)
+          F->UsedHeaderSearchPathIdxs.insert(Record[Idx++]);
+      }
+      break;
     }
   }
 }
Index: clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
===================================================================
--- clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -20,6 +20,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/raw_ostream.h"
+#include <set>
 #include <string>
 #include <unordered_map>
 
@@ -158,7 +159,8 @@
 class ModuleDepCollector final : public DependencyCollector {
 public:
   ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
-                     CompilerInstance &I, DependencyConsumer &C);
+                     CompilerInstance &I, DependencyConsumer &C,
+                     bool OptimizeArgs);
 
   void attachToPreprocessor(Preprocessor &PP) override;
   void attachToASTReader(ASTReader &R) override;
@@ -170,6 +172,8 @@
   CompilerInstance &Instance;
   /// The consumer of collected dependency information.
   DependencyConsumer &Consumer;
+  /// Whether to optimize the modules' command-line arguments.
+  bool OptimizeArgs;
   /// Path to the main source file.
   std::string MainFile;
   /// Hash identifying the compilation conditions of the current TU.
Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
===================================================================
--- clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -77,6 +77,7 @@
   /// worker. If null, the file manager will not be reused.
   llvm::IntrusiveRefCntPtr<FileManager> Files;
   ScanningOutputFormat Format;
+  bool OptimizeArgs;
 };
 
 } // end namespace dependencies
Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
===================================================================
--- clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
+++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
@@ -48,7 +48,8 @@
 public:
   DependencyScanningService(ScanningMode Mode, ScanningOutputFormat Format,
                             bool ReuseFileManager = true,
-                            bool SkipExcludedPPRanges = true);
+                            bool SkipExcludedPPRanges = true,
+                            bool OptimizeArgs = false);
 
   ScanningMode getMode() const { return Mode; }
 
@@ -58,6 +59,8 @@
 
   bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; }
 
+  bool canOptimizeArgs() const { return OptimizeArgs; }
+
   DependencyScanningFilesystemSharedCache &getSharedCache() {
     return SharedCache;
   }
@@ -70,6 +73,7 @@
   /// ranges by bumping the buffer pointer in the lexer instead of lexing the
   /// tokens in the range until reaching the corresponding directive.
   const bool SkipExcludedPPRanges;
+  const bool OptimizeArgs;
   /// The global file system cache.
   DependencyScanningFilesystemSharedCache SharedCache;
 };
Index: clang/include/clang/Serialization/ModuleFile.h
===================================================================
--- clang/include/clang/Serialization/ModuleFile.h
+++ clang/include/clang/Serialization/ModuleFile.h
@@ -30,6 +30,7 @@
 #include <cassert>
 #include <cstdint>
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -173,6 +174,10 @@
   /// unique module files based on AST contents.
   ASTFileSignature ASTBlockHash;
 
+  /// The indices of header search paths that were actually used when building
+  /// the module file.
+  std::set<unsigned> UsedHeaderSearchPathIdxs;
+
   /// Whether this module has been directly imported by the
   /// user.
   bool DirectlyImported = false;
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -402,6 +402,10 @@
 
   /// Record code for \#pragma diagnostic mappings.
   DIAG_PRAGMA_MAPPINGS,
+
+  /// Record code for indices of header search paths that were actually used
+  /// when building the module.
+  USED_HEADER_SEARCH_PATHS,
 };
 
 /// Record code for extension blocks.
Index: clang/include/clang/Lex/HeaderSearch.h
===================================================================
--- clang/include/clang/Lex/HeaderSearch.h
+++ clang/include/clang/Lex/HeaderSearch.h
@@ -21,12 +21,13 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Allocator.h"
 #include <cassert>
 #include <cstddef>
 #include <memory>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -290,6 +291,15 @@
     SystemDirIdx++;
   }
 
+  /// Return indices of used search paths.
+  std::set<unsigned> GetUsedSearchPathIdxs() const {
+    std::set<unsigned> UsedSearchPathIdxs;
+    for (const auto &Entry : LookupFileCache)
+      if (Entry.second.HitIdx < SearchDirs.size())
+        UsedSearchPathIdxs.insert(Entry.second.HitIdx);
+    return UsedSearchPathIdxs;
+  }
+
   /// Set the list of system header prefixes.
   void SetSystemHeaderPrefixes(ArrayRef<std::pair<std::string, bool>> P) {
     SystemHeaderPrefixes.assign(P.begin(), P.end());
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to