aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Wu <stevenwu@apple.com>2025-09-17 15:57:51 -0700
committerSteven Wu <stevenwu@apple.com>2025-09-17 15:57:51 -0700
commit3aabd45122935506f7b1d73b919afa117d75f911 (patch)
tree2d47628aeaa5ca1718612868484403bcce2feadc
parentf0090bacc14db0e262c276670ff0afeadbf4d309 (diff)
downloadllvm-users/cachemeifyoucan/spr/clangscandeps-improve-gettranslationunitdependencies.zip
llvm-users/cachemeifyoucan/spr/clangscandeps-improve-gettranslationunitdependencies.tar.gz
llvm-users/cachemeifyoucan/spr/clangscandeps-improve-gettranslationunitdependencies.tar.bz2
Created using spr 1.3.6
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h8
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h11
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp6
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp41
-rw-r--r--clang/test/ClangScanDeps/tu-vfs.c (renamed from clang/test/ClangScanDeps/tu-buffer.c)63
-rw-r--r--clang/tools/clang-scan-deps/ClangScanDeps.cpp29
-rw-r--r--clang/tools/clang-scan-deps/Opts.td2
7 files changed, 97 insertions, 63 deletions
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index c3601a4..2974e67 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -139,9 +139,9 @@ public:
/// \param LookupModuleOutput This function is called to fill in
/// "-fmodule-file=", "-o" and other output
/// arguments for dependencies.
- /// \param TUBuffer Optional memory buffer for translation unit input. If
- /// TUBuffer is nullopt, the input should be included in the
- /// Commandline already.
+ /// \param OverlayFS An optional VFS that overlays on top of WorkerFS to
+ /// provide additional virtual files to the scanning of the
+ /// translation unit.
///
/// \returns a \c StringError with the diagnostic output if clang errors
/// occurred, \c TranslationUnitDeps otherwise.
@@ -149,7 +149,7 @@ public:
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::DenseSet<ModuleID> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
- std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
/// Given a compilation context specified via the Clang driver command-line,
/// gather modular dependencies of module with the given name, and return the
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 6060e4b..8ef81e5 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -90,10 +90,9 @@ public:
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
/// Run the dependency scanning tool for a given clang driver command-line,
- /// and report the discovered dependencies to the provided consumer. If
- /// TUBuffer is not nullopt, it is used as TU input for the dependency
- /// scanning. Otherwise, the input should be included as part of the
- /// command-line.
+ /// and report the discovered dependencies to the provided consumer. An
+ /// additional OverlayFS can be provided to add additional virtual files to
+ /// the dependency scanning.
///
/// \returns false if clang errors occurred (with diagnostics reported to
/// \c DiagConsumer), true otherwise.
@@ -101,7 +100,7 @@ public:
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &DepConsumer, DependencyActionController &Controller,
DiagnosticConsumer &DiagConsumer,
- std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
/// Run the dependency scanning tool for a given clang driver command-line
/// for a specific module.
@@ -123,7 +122,7 @@ public:
llvm::Error computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
- std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
/// Run the dependency scanning tool for a given clang driver command-line
/// for a specific module.
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 27734ff..bd66ad6 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -144,11 +144,11 @@ DependencyScanningTool::getTranslationUnitDependencies(
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::DenseSet<ModuleID> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
- std::optional<llvm::MemoryBufferRef> TUBuffer) {
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
FullDependencyConsumer Consumer(AlreadySeen);
CallbackActionController Controller(LookupModuleOutput);
- llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,
- Controller, TUBuffer);
+ llvm::Error Result = Worker.computeDependencies(
+ CWD, CommandLine, Consumer, Controller, std::move(OverlayFS));
if (Result)
return std::move(Result);
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 0a12c47..7aed691 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -627,7 +627,7 @@ createDiagOptions(const std::vector<std::string> &CommandLine) {
llvm::Error DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
- std::optional<llvm::MemoryBufferRef> TUBuffer) {
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
// Capture the emitted diagnostics and report them to the client
// in the case of a failure.
std::string DiagnosticOutput;
@@ -636,7 +636,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
- DiagPrinter, TUBuffer))
+ DiagPrinter, std::move(OverlayFS)))
return llvm::Error::success();
return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
llvm::inconvertibleErrorCode());
@@ -788,41 +788,26 @@ bool DependencyScanningWorker::scanDependencies(
bool DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
- DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
+ DiagnosticConsumer &DC,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
// Reset what might have been modified in the previous worker invocation.
BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
- std::optional<std::vector<std::string>> ModifiedCommandLine;
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
-
- // If we're scanning based on a module name alone, we don't expect the client
- // to provide us with an input file. However, the driver really wants to have
- // one. Let's just make it up to make the driver happy.
- if (TUBuffer) {
- auto OverlayFS =
+ // If an OverlayFS is provided, create a new FS that has the overlay on the
+ // top layer.
+ if (OverlayFS) {
+ auto NewFS =
llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
- auto InMemoryFS =
- llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
- InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
- auto InputPath = TUBuffer->getBufferIdentifier();
- InMemoryFS->addFile(
- InputPath, 0,
- llvm::MemoryBuffer::getMemBufferCopy(TUBuffer->getBuffer()));
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay =
- InMemoryFS;
-
- OverlayFS->pushOverlay(InMemoryOverlay);
- ModifiedFS = OverlayFS;
- ModifiedCommandLine = CommandLine;
- ModifiedCommandLine->emplace_back(InputPath);
+ NewFS->pushOverlay(std::move(OverlayFS));
+ NewFS->setCurrentWorkingDirectory(WorkingDirectory);
+ ModifiedFS = NewFS;
}
- const std::vector<std::string> &FinalCommandLine =
- ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
- return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,
- Controller, DC, FinalFS, /*ModuleName=*/std::nullopt);
+ return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
+ DC, FinalFS, /*ModuleName=*/std::nullopt);
}
bool DependencyScanningWorker::computeDependencies(
diff --git a/clang/test/ClangScanDeps/tu-buffer.c b/clang/test/ClangScanDeps/tu-vfs.c
index b450b13..5082293 100644
--- a/clang/test/ClangScanDeps/tu-buffer.c
+++ b/clang/test/ClangScanDeps/tu-vfs.c
@@ -19,26 +19,72 @@ module addition { header "addition.h" }
//--- addition.h
// empty
-//--- tu.c
+//--- hidden/tu.c
#include "root.h"
+//--- hidden/additional.h
+#include "addition.h"
+
//--- root/textual.h
// This is here to verify that the "root" directory doesn't clash with name of
// the "root" module.
//--- cdb.json.template
[{
- "file": "",
+ "file": "DIR/test.c",
"directory": "DIR",
- "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c -c"
+ "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c DIR/test.c -c"
}]
+//--- cdb2.json.template
+[{
+ "file": "DIR/test.c",
+ "directory": "DIR",
+ "command": "clang -fmodules -fmodules-cache-path=DIR/cache -include DIR/pre.h -I DIR -x c DIR/test.c -c"
+}]
+
+//--- vfs.yaml.template
+{
+ 'version': 0,
+ 'roots': [
+ { 'name': 'DIR', 'type': 'directory',
+ 'contents': [
+ { 'name': 'test.c', 'type': 'file',
+ 'use-external-name': false,
+ 'external-contents': 'DIR/hidden/tu.c'
+ },
+ { 'name': 'pre.h', 'type': 'file',
+ 'use-external-name': false,
+ 'external-contents': 'DIR/hidden/additional.h'
+ },
+ ]
+ }
+ ]
+}
+
// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
-// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -tu-buffer-path %t/tu.c > %t/result.json
+// RUN: sed "s|DIR|%/t|g" %t/vfs.yaml.template > %t/vfs.yaml
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -vfs-overlay-path %t/vfs.yaml > %t/result.json
// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s --check-prefix=CHECK
+// RUN: sed "s|DIR|%/t|g" %t/cdb2.json.template > %t/cdb2.json
+// RUN: clang-scan-deps -compilation-database %t/cdb2.json -format experimental-full -vfs-overlay-path %t/vfs.yaml > %t/result2.json
+// RUN: cat %t/result2.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s --check-prefix=CHECK --check-prefix=ADDITION
+
// CHECK: {
// CHECK-NEXT: "modules": [
+// ADDITION-NEXT: {
+// ADDITION-NEXT: "clang-module-deps": [],
+// ADDITION-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// ADDITION-NEXT: "command-line": [
+// ADDITION: ],
+// ADDITION-NEXT: "context-hash": "{{.*}}",
+// ADDITION-NEXT: "file-deps": [
+// ADDITION-NEXT: "[[PREFIX]]/module.modulemap"
+// ADDITION-NEXT: "[[PREFIX]]/addition.h"
+// ADDITION-NEXT: ],
+// ADDITION: "name": "addition"
+// ADDITION-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
@@ -93,6 +139,10 @@ module addition { header "addition.h" }
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
+// ADDITION-NEXT: {
+// ADDITION-NEXT: "context-hash": "{{.*}}",
+// ADDITION-NEXT: "module-name": "addition"
+// ADDITION-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "module-name": "root"
@@ -101,9 +151,10 @@ module addition { header "addition.h" }
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK: "file-deps": [
-// CHECK-NEXT: [[PREFIX]]/tu.c
+// CHECK-NEXT: [[PREFIX]]/test.c
+// ADDITION-NEXT: [[PREFIX]]/pre.h
// CHECK-NEXT: ],
-// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
+// CHECK-NEXT: "input-file": "[[PREFIX]]/test.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 0e2758d..63990f1 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -89,7 +89,7 @@ static unsigned NumThreads = 0;
static std::string CompilationDB;
static std::optional<std::string> ModuleName;
static std::vector<std::string> ModuleDepTargets;
-static std::string TranslationUnitFile;
+static std::string VFSOverlayFile;
static bool DeprecatedDriverCommand;
static ResourceDirRecipeKind ResourceDirRecipe;
static bool Verbose;
@@ -210,8 +210,8 @@ static void ParseArgs(int argc, char **argv) {
for (const llvm::opt::Arg *A : Args.filtered(OPT_dependency_target_EQ))
ModuleDepTargets.emplace_back(A->getValue());
- if (const llvm::opt::Arg *A = Args.getLastArg(OPT_tu_buffer_path_EQ))
- TranslationUnitFile = A->getValue();
+ if (const llvm::opt::Arg *A = Args.getLastArg(OPT_vfs_overlay_path_EQ))
+ VFSOverlayFile = A->getValue();
DeprecatedDriverCommand = Args.hasArg(OPT_deprecated_driver_command);
@@ -1082,24 +1082,23 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
LocalIndex, DependencyOS, Errs))
HadErrors = true;
} else {
- std::unique_ptr<llvm::MemoryBuffer> TU;
- std::optional<llvm::MemoryBufferRef> TUBuffer;
- if (!TranslationUnitFile.empty()) {
- auto MaybeTU =
- llvm::MemoryBuffer::getFile(TranslationUnitFile, /*IsText=*/true);
- if (!MaybeTU) {
- llvm::errs() << "cannot open input translation unit: "
- << MaybeTU.getError().message() << "\n";
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS;
+ if (!VFSOverlayFile.empty()) {
+ auto YAMLFile =
+ llvm::MemoryBuffer::getFile(VFSOverlayFile, /*IsText=*/true);
+ if (!YAMLFile) {
+ llvm::errs() << "cannot open vfs overlay yaml: "
+ << YAMLFile.getError().message() << "\n";
HadErrors = true;
continue;
}
- TU = std::move(*MaybeTU);
- TUBuffer = TU->getMemBufferRef();
- Filename = TU->getBufferIdentifier();
+ OverlayFS = llvm::vfs::RedirectingFileSystem::create(
+ std::move(*YAMLFile), nullptr, "", nullptr,
+ llvm::vfs::getRealFileSystem());
}
auto MaybeTUDeps = WorkerTool.getTranslationUnitDependencies(
Input->CommandLine, CWD, AlreadySeenModules, LookupOutput,
- TUBuffer);
+ OverlayFS);
if (handleTranslationUnitResult(Filename, MaybeTUDeps, *FD, LocalIndex,
DependencyOS, Errs))
HadErrors = true;
diff --git a/clang/tools/clang-scan-deps/Opts.td b/clang/tools/clang-scan-deps/Opts.td
index 03011f9..909e311 100644
--- a/clang/tools/clang-scan-deps/Opts.td
+++ b/clang/tools/clang-scan-deps/Opts.td
@@ -29,7 +29,7 @@ defm compilation_database : Eq<"compilation-database", "Compilation database">;
defm module_name : Eq<"module-name", "the module of which the dependencies are to be computed">;
defm dependency_target : Eq<"dependency-target", "The names of dependency targets for the dependency file">;
-defm tu_buffer_path: Eq<"tu-buffer-path", "The path to the translation unit for depscan. Not compatible with -module-name">;
+defm vfs_overlay_path: Eq<"vfs-overlay-path", "The path to a VFS overlay file that is used to scan the translation unit. Not compatible with -module-name">;
def deprecated_driver_command : F<"deprecated-driver-command", "use a single driver command to build the tu (deprecated)">;