From a37ebd2602e5236c986831e7a74d860d7b1a5dc4 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 11 Nov 2025 10:22:48 -0800 Subject: [PATCH] [clang][cas] Use the new `CompilerInvocation::visitPaths()` API --- .../clang/Frontend/CompilerInvocation.h | 8 ++ clang/lib/Frontend/CompilerInvocation.cpp | 12 +++ .../IncludeTreeActionController.cpp | 2 + .../DependencyScanning/ScanAndUpdateArgs.cpp | 96 ++----------------- 4 files changed, 32 insertions(+), 86 deletions(-) diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index b043a7db94ca4..a548d70c846b2 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -313,6 +313,14 @@ class CompilerInvocation : public CompilerInvocationBase { } /// @} + /// Visitation. + /// @{ + /// Visits paths stored in the invocation. The callback may return true to + /// short-circuit the visitation, or return false to continue visiting. This + /// is allowed to mutate the visited paths. + void visitPaths(llvm::function_ref Callback); + /// @} + /// Create a compiler invocation from a list of input options. /// \returns true on success. /// diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index f8f3f9749b443..6a755a81b9d05 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -5804,6 +5804,9 @@ void CompilerInvocationBase::visitPathsImpl( for (auto &Entry : HeaderSearchOpts.UserEntries) if (Entry.IgnoreSysRoot) RETURN_IF(Entry.Path); + // TODO: Consider upstreaming this. + for (auto &Prefix : HeaderSearchOpts.SystemHeaderPrefixes) + RETURN_IF(Prefix.Prefix); RETURN_IF(HeaderSearchOpts.ResourceDir); RETURN_IF(HeaderSearchOpts.ModuleCachePath); RETURN_IF(HeaderSearchOpts.ModuleUserBuildPath); @@ -5837,6 +5840,7 @@ void CompilerInvocationBase::visitPathsImpl( // Filesystem options. auto &FileSystemOpts = *this->FSOpts; RETURN_IF(FileSystemOpts.WorkingDir); + RETURN_IF(FileSystemOpts.CASFileSystemWorkingDirectory); // Codegen options. auto &CodeGenOpts = *this->CodeGenOpts; @@ -5864,6 +5868,14 @@ void CompilerInvocationBase::visitPaths( [&Callback](std::string &Path) { return Callback(StringRef(Path)); }); } +void CompilerInvocation::visitPaths( + llvm::function_ref Callback) { + // Unlike the copy-on-write variant (and therefore potentially also the base + // class), regular CompilerInvocation does not share the option objects with + // anyone else. This makes the potential mutation in the callback safe. + visitPathsImpl(Callback); +} + void CompilerInvocationBase::generateCC1CommandLine( ArgumentConsumer Consumer) const { llvm::Triple T(getTargetOpts().Triple); diff --git a/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp b/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp index 06ddb3dec8492..1378ee22f2598 100644 --- a/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp +++ b/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp @@ -312,6 +312,8 @@ Error IncludeTreeActionController::initialize( addReversePrefixMappingFileSystem(PrefixMapper, ScanInstance); + // TODO: Confirm why it's not enough to do this in + // DepscanPrefixMapping::remapInvocationPaths. // These are written in the predefines buffer, so we need to remap them. for (std::string &Include : PPOpts.Includes) PrefixMapper.mapInPlace(Include); diff --git a/clang/lib/Tooling/DependencyScanning/ScanAndUpdateArgs.cpp b/clang/lib/Tooling/DependencyScanning/ScanAndUpdateArgs.cpp index 12f9d46c308cd..45c04babc8019 100644 --- a/clang/lib/Tooling/DependencyScanning/ScanAndUpdateArgs.cpp +++ b/clang/lib/Tooling/DependencyScanning/ScanAndUpdateArgs.cpp @@ -145,94 +145,18 @@ void DepscanPrefixMapping::remapInvocationPaths(CompilerInvocation &Invocation, FrontendOpts.PathPrefixMappings.emplace_back(Map.Old, Map.New); } - auto mapInPlaceAll = [&](std::vector &Vector) { - for (auto &Path : Vector) - Mapper.mapInPlace(Path); - }; - - auto &FileSystemOpts = Invocation.getFileSystemOpts(); - Mapper.mapInPlace(FileSystemOpts.CASFileSystemWorkingDirectory); - - // Remap header search. - auto &HeaderSearchOpts = Invocation.getHeaderSearchOpts(); - Mapper.mapInPlace(HeaderSearchOpts.Sysroot); - for (auto &Entry : HeaderSearchOpts.UserEntries) - if (Entry.IgnoreSysRoot) - Mapper.mapInPlace(Entry.Path); - - for (auto &Prefix : HeaderSearchOpts.SystemHeaderPrefixes) - Mapper.mapInPlace(Prefix.Prefix); - Mapper.mapInPlace(HeaderSearchOpts.ResourceDir); - Mapper.mapInPlace(HeaderSearchOpts.ModuleCachePath); - Mapper.mapInPlace(HeaderSearchOpts.ModuleUserBuildPath); - for (auto I = HeaderSearchOpts.PrebuiltModuleFiles.begin(), - E = HeaderSearchOpts.PrebuiltModuleFiles.end(); - I != E;) { - auto Current = I++; - Mapper.mapInPlace(Current->second); - } - mapInPlaceAll(HeaderSearchOpts.PrebuiltModulePaths); - mapInPlaceAll(HeaderSearchOpts.VFSOverlayFiles); - - // Preprocessor options. - auto &PPOpts = Invocation.getPreprocessorOpts(); - mapInPlaceAll(PPOpts.MacroIncludes); - mapInPlaceAll(PPOpts.Includes); - Mapper.mapInPlace(PPOpts.ImplicitPCHInclude); - - // Frontend options. - for (FrontendInputFile &Input : FrontendOpts.Inputs) { - if (Input.isBuffer()) - continue; // FIXME: Can this happen when parsing command-line? - - SmallString<256> RemappedFile; - Mapper.map(Input.getFile(), RemappedFile); - if (RemappedFile != Input.getFile()) - Input = - FrontendInputFile(RemappedFile, Input.getKind(), Input.isSystem()); - } - - // Skip the output file. That's not the input CAS filesystem. - // Mapper.mapInPlace(OutputFile); <-- this doesn't make sense. - - Mapper.mapInPlace(FrontendOpts.CodeCompletionAt.FileName); - - // Don't remap plugins (for now), since we don't know how to remap their - // arguments. Maybe they should be loaded outside of the CAS filesystem? + // Note: We don't remap plugins for now, since we don't know how to remap + // their arguments. Maybe they should be loaded outside of the CAS filesystem? // Maybe we should error? // - // Mapper.mapInPlaceOrFilterOut(FrontendOpts.Plugins); - - mapInPlaceAll(FrontendOpts.ModuleMapFiles); - mapInPlaceAll(FrontendOpts.ModuleFiles); - mapInPlaceAll(FrontendOpts.ModulesEmbedFiles); - mapInPlaceAll(FrontendOpts.ASTMergeFiles); - Mapper.mapInPlace(FrontendOpts.OverrideRecordLayoutsFile); - Mapper.mapInPlace(FrontendOpts.StatsFile); - - // Filesystem options. - Mapper.mapInPlace(FileSystemOpts.WorkingDir); - - // Code generation options. - auto &CodeGenOpts = Invocation.getCodeGenOpts(); - Mapper.mapInPlace(CodeGenOpts.DebugCompilationDir); - Mapper.mapInPlace(CodeGenOpts.CoverageCompilationDir); - - // Sanitizer options. - mapInPlaceAll(Invocation.getLangOpts().NoSanitizeFiles); - - // Handle coverage mappings. - Mapper.mapInPlace(CodeGenOpts.ProfileInstrumentUsePath); - Mapper.mapInPlace(CodeGenOpts.SampleProfileFile); - Mapper.mapInPlace(CodeGenOpts.ProfileRemappingFile); - - // Dependency output options. - // Note: these are not in the cache key, but they are in the module context - // hash, which indirectly impacts the cache key when importing a module. - // In the future we may change how -fmodule-file-cache-key works when - // remapping to avoid needing this. - for (auto &ExtraDep : Invocation.getDependencyOutputOpts().ExtraDeps) - Mapper.mapInPlace(ExtraDep.first); + // Note: DependencyOutputOptions::ExtraDeps are not in the cache key, but they + // are in the module context hash, which indirectly impacts the cache key when + // importing a module. In the future we may change how -fmodule-file-cache-key + // works when remapping to avoid needing this. + Invocation.visitPaths([&Mapper](std::string &Path) { + Mapper.mapInPlace(Path); + return false; + }); } void DepscanPrefixMapping::configurePrefixMapper(const CompilerInvocation &CI,