https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/136178
>From 51449e05b19f3b0f237305159ae150bc92588fd9 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Fri, 11 Apr 2025 14:11:36 -0700 Subject: [PATCH 1/3] [clang][deps] Make dependency directives getter thread-safe --- .../include/clang/Frontend/CompilerInstance.h | 8 +++ .../clang/Lex/DependencyDirectivesScanner.h | 6 ++ clang/include/clang/Lex/Preprocessor.h | 10 +++ clang/include/clang/Lex/PreprocessorOptions.h | 13 ---- .../DependencyScanningFilesystem.h | 10 +++ clang/lib/Frontend/CompilerInstance.cpp | 5 ++ clang/lib/Lex/PPLexerChange.cpp | 14 ++--- .../DependencyScanningWorker.cpp | 61 ++++++++++++++++--- .../Lex/PPDependencyDirectivesTest.cpp | 12 ++-- 9 files changed, 100 insertions(+), 39 deletions(-) diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 41dc7f1fef461..ecd1f5cabc79e 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -16,6 +16,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Frontend/Utils.h" +#include "clang/Lex/DependencyDirectivesScanner.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "llvm/ADT/ArrayRef.h" @@ -99,6 +100,9 @@ class CompilerInstance : public ModuleLoader { /// The cache of PCM files. IntrusiveRefCntPtr<ModuleCache> ModCache; + /// Function for getting the dependency preprocessor directives of a file. + GetDependencyDirectivesFn GetDependencyDirectives; + /// The preprocessor. std::shared_ptr<Preprocessor> PP; @@ -697,6 +701,10 @@ class CompilerInstance : public ModuleLoader { /// and replace any existing one with it. void createPreprocessor(TranslationUnitKind TUKind); + void setDependencyDirectivesGetter(GetDependencyDirectivesFn Fn) { + GetDependencyDirectives = Fn; + } + std::string getSpecificModuleCachePath(StringRef ModuleHash); std::string getSpecificModuleCachePath() { return getSpecificModuleCachePath(getInvocation().getModuleHash()); diff --git a/clang/include/clang/Lex/DependencyDirectivesScanner.h b/clang/include/clang/Lex/DependencyDirectivesScanner.h index 0e115906fbfe5..c975311f8bf33 100644 --- a/clang/include/clang/Lex/DependencyDirectivesScanner.h +++ b/clang/include/clang/Lex/DependencyDirectivesScanner.h @@ -21,6 +21,7 @@ #include "llvm/ADT/ArrayRef.h" namespace clang { +class FileManager; namespace tok { enum TokenKind : unsigned short; @@ -135,6 +136,11 @@ void printDependencyDirectivesAsSource( ArrayRef<dependency_directives_scan::Directive> Directives, llvm::raw_ostream &OS); +// FIXME: Allow returning an error. +using GetDependencyDirectivesFn = std::function< + std::optional<ArrayRef<dependency_directives_scan::Directive>>( + FileManager &, FileEntryRef)>; + } // end namespace clang #endif // LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 24bb524783e93..8554068b19607 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -140,6 +140,12 @@ class Preprocessor { friend class VariadicMacroScopeGuard; llvm::unique_function<void(const clang::Token &)> OnToken; + /// Function for getting the dependency preprocessor directives of a file. + /// + /// These are directives derived from a special form of lexing where the + /// source input is scanned for the preprocessor directives that might have an + /// effect on the dependencies for a compilation unit. + GetDependencyDirectivesFn GetDependencyDirectives; const PreprocessorOptions &PPOpts; DiagnosticsEngine *Diags; const LangOptions &LangOpts; @@ -1326,6 +1332,10 @@ class Preprocessor { OnToken = std::move(F); } + void setDependencyDirectivesGetter(GetDependencyDirectivesFn Fn) { + GetDependencyDirectives = Fn; + } + void setPreprocessToken(bool Preprocess) { PreprocessToken = Preprocess; } bool isMacroDefined(StringRef Id) { diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index c2e3d68333024..d4c4e1ccbf2c4 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -189,19 +189,6 @@ class PreprocessorOptions { /// with support for lifetime-qualified pointers. ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib; - /// Function for getting the dependency preprocessor directives of a file. - /// - /// These are directives derived from a special form of lexing where the - /// source input is scanned for the preprocessor directives that might have an - /// effect on the dependencies for a compilation unit. - /// - /// Enables a client to cache the directives for a file and provide them - /// across multiple compiler invocations. - /// FIXME: Allow returning an error. - std::function<std::optional<ArrayRef<dependency_directives_scan::Directive>>( - FileEntryRef)> - DependencyDirectivesForFile; - /// Set up preprocessor for RunAnalysis action. bool SetUpStaticAnalyzer = false; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h index d12814e7c9253..f07bd5e820dab 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -371,6 +371,16 @@ class DependencyScanningWorkerFilesystem /// false if not (i.e. this entry is not a file or its scan fails). bool ensureDirectiveTokensArePopulated(EntryRef Entry); + /// \returns The scanned preprocessor directive tokens of the file that are + /// used to speed up preprocessing, if available. + std::optional<ArrayRef<dependency_directives_scan::Directive>> + getDirectiveTokens(const Twine &Path) { + if (llvm::ErrorOr<EntryRef> Entry = getOrCreateFileSystemEntry(Path.str())) + if (ensureDirectiveTokensArePopulated(*Entry)) + return Entry->getDirectiveTokens(); + return std::nullopt; + } + /// Check whether \p Path exists. By default checks cached result of \c /// status(), and falls back on FS if unable to do so. bool exists(const Twine &Path) override; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 243e0a3c15b05..0efe0ada4873f 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -535,6 +535,9 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { /*ShowAllHeaders=*/true, /*OutputPath=*/"", /*ShowDepth=*/true, /*MSStyle=*/true); } + + if (GetDependencyDirectives) + PP->setDependencyDirectivesGetter(GetDependencyDirectives); } std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) { @@ -1237,6 +1240,8 @@ std::unique_ptr<CompilerInstance> CompilerInstance::cloneForModuleCompileImpl( // Make a copy for the new instance. Instance.FailedModules = FailedModules; + Instance.GetDependencyDirectives = GetDependencyDirectives; + // If we're collecting module dependencies, we need to share a collector // between all of the module CompilerInstances. Other than that, we don't // want to produce any dependency output from the module build. diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index a373a52506a24..09ef921f67202 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -92,16 +92,10 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir, } Lexer *TheLexer = new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile); - if (getPreprocessorOpts().DependencyDirectivesForFile && - FID != PredefinesFileID) { - if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) { - if (std::optional<ArrayRef<dependency_directives_scan::Directive>> - DepDirectives = - getPreprocessorOpts().DependencyDirectivesForFile(*File)) { - TheLexer->DepDirectives = *DepDirectives; - } - } - } + if (GetDependencyDirectives && FID != PredefinesFileID) + if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) + if (auto MaybeDepDirectives = GetDependencyDirectives(FileMgr, *File)) + TheLexer->DepDirectives = *MaybeDepDirectives; EnterSourceFileWithLexer(TheLexer, CurDir); return false; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 6595f8ff5dc55..a9e35e0484ac9 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -357,6 +357,57 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) { std::swap(PPOpts.Macros, NewMacros); } +static GetDependencyDirectivesFn makeDepDirectivesGetter() { + /// This is a functor that conforms to \c GetDependencyDirectivesFn. + /// It ensures it's always invoked with the same \c FileManager and caches the + /// extraction of the scanning VFS for better performance. + struct DepDirectivesGetter { + DepDirectivesGetter() : DepFS(nullptr), FM(nullptr) {} + + /// It's important copies do not carry over the cached members. The copies + /// are likely to be used from distinct \c CompilerInstance objects with + /// distinct \c FileManager \c llvm::vfs::FileSystem. + DepDirectivesGetter(const DepDirectivesGetter &) + : DepFS(nullptr), FM(nullptr) {} + DepDirectivesGetter &operator=(const DepDirectivesGetter &) { + DepFS = nullptr; + FM = nullptr; + return *this; + } + + auto operator()(FileManager &FileMgr, FileEntryRef File) { + ensureConsistentFileManager(FileMgr); + ensurePopulatedFileSystem(FileMgr); + return DepFS->getDirectiveTokens(File.getName()); + } + + private: + DependencyScanningWorkerFilesystem *DepFS; + FileManager *FM; + + void ensureConsistentFileManager(FileManager &FileMgr) { + if (!FM) + FM = &FileMgr; + assert(&FileMgr == FM); + } + + void ensurePopulatedFileSystem(FileManager &FM) { + if (DepFS) + return; + FM.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) { + auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS); + if (DFS) { + assert(!DepFS && "Found multiple scanning VFSs"); + DepFS = DFS; + } + }); + assert(DepFS && "Did not find scanning VFS"); + } + }; + + return DepDirectivesGetter{}; +} + /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. class DependencyScanningAction : public tooling::ToolAction { @@ -433,15 +484,7 @@ class DependencyScanningAction : public tooling::ToolAction { if (!ModulesCachePath.empty()) DepFS->setBypassedPathPrefix(ModulesCachePath); - ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile = - [LocalDepFS = DepFS](FileEntryRef File) - -> std::optional<ArrayRef<dependency_directives_scan::Directive>> { - if (llvm::ErrorOr<EntryRef> Entry = - LocalDepFS->getOrCreateFileSystemEntry(File.getName())) - if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry)) - return Entry->getDirectiveTokens(); - return std::nullopt; - }; + ScanInstance.setDependencyDirectivesGetter(makeDepDirectivesGetter()); } // Create a new FileManager to match the invocation's FileSystemOptions. diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp index 03f1432d990cb..c52d5091eabfb 100644 --- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp +++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp @@ -105,8 +105,7 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { }; SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects; - auto getDependencyDirectives = [&](FileEntryRef File) - -> std::optional<ArrayRef<dependency_directives_scan::Directive>> { + auto GetDependencyDirectives = [&](FileManager &FileMgr, FileEntryRef File) { DepDirectivesObjects.push_back(std::make_unique<DepDirectives>()); StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer(); bool Err = scanSourceForDependencyDirectives( @@ -117,11 +116,6 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { }; PreprocessorOptions PPOpts; - PPOpts.DependencyDirectivesForFile = [&](FileEntryRef File) - -> std::optional<ArrayRef<dependency_directives_scan::Directive>> { - return getDependencyDirectives(File); - }; - HeaderSearchOptions HSOpts; TrivialModuleLoader ModLoader; HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get()); @@ -130,6 +124,10 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { /*OwnsHeaderSearch =*/false); PP.Initialize(*Target); + PP.setDependencyDirectivesGetter([&](FileManager &FM, FileEntryRef File) { + return GetDependencyDirectives(FM, File); + }); + SmallVector<StringRef> IncludedFiles; PP.addPPCallbacks(std::make_unique<IncludeCollector>(PP, IncludedFiles)); PP.EnterMainSourceFile(); >From 00099ccf341ba443e356b514a4f81dae2b01e0bd Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Thu, 17 Apr 2025 11:44:01 -0700 Subject: [PATCH 2/3] Simplify test --- clang/unittests/Lex/PPDependencyDirectivesTest.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp index c52d5091eabfb..5f4c2706a519d 100644 --- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp +++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp @@ -124,9 +124,7 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { /*OwnsHeaderSearch =*/false); PP.Initialize(*Target); - PP.setDependencyDirectivesGetter([&](FileManager &FM, FileEntryRef File) { - return GetDependencyDirectives(FM, File); - }); + PP.setDependencyDirectivesGetter(GetDependencyDirectives); SmallVector<StringRef> IncludedFiles; PP.addPPCallbacks(std::make_unique<IncludeCollector>(PP, IncludedFiles)); >From 105e148b597907b9ef21c492f401c10725cf49e2 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Tue, 22 Apr 2025 13:21:28 -0700 Subject: [PATCH 3/3] Interface with explicit `cloneFor(FileManager&)` API --- .../include/clang/Frontend/CompilerInstance.h | 9 ++- .../clang/Lex/DependencyDirectivesScanner.h | 18 +++-- clang/include/clang/Lex/Preprocessor.h | 8 +- clang/lib/Frontend/CompilerInstance.cpp | 6 +- clang/lib/Lex/PPLexerChange.cpp | 2 +- .../DependencyScanningWorker.cpp | 77 +++++++------------ .../Lex/PPDependencyDirectivesTest.cpp | 34 +++++--- 7 files changed, 78 insertions(+), 76 deletions(-) diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index ecd1f5cabc79e..078044ed2d039 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -100,8 +100,8 @@ class CompilerInstance : public ModuleLoader { /// The cache of PCM files. IntrusiveRefCntPtr<ModuleCache> ModCache; - /// Function for getting the dependency preprocessor directives of a file. - GetDependencyDirectivesFn GetDependencyDirectives; + /// Functor for getting the dependency preprocessor directives of a file. + std::unique_ptr<DependencyDirectivesGetter> GetDependencyDirectives; /// The preprocessor. std::shared_ptr<Preprocessor> PP; @@ -701,8 +701,9 @@ class CompilerInstance : public ModuleLoader { /// and replace any existing one with it. void createPreprocessor(TranslationUnitKind TUKind); - void setDependencyDirectivesGetter(GetDependencyDirectivesFn Fn) { - GetDependencyDirectives = Fn; + void setDependencyDirectivesGetter( + std::unique_ptr<DependencyDirectivesGetter> Getter) { + GetDependencyDirectives = std::move(Getter); } std::string getSpecificModuleCachePath(StringRef ModuleHash); diff --git a/clang/include/clang/Lex/DependencyDirectivesScanner.h b/clang/include/clang/Lex/DependencyDirectivesScanner.h index c975311f8bf33..acdc9e2bf9aa4 100644 --- a/clang/include/clang/Lex/DependencyDirectivesScanner.h +++ b/clang/include/clang/Lex/DependencyDirectivesScanner.h @@ -136,11 +136,19 @@ void printDependencyDirectivesAsSource( ArrayRef<dependency_directives_scan::Directive> Directives, llvm::raw_ostream &OS); -// FIXME: Allow returning an error. -using GetDependencyDirectivesFn = std::function< - std::optional<ArrayRef<dependency_directives_scan::Directive>>( - FileManager &, FileEntryRef)>; - +/// Functor that returns the dependency directives for a given file. +class DependencyDirectivesGetter { +public: + /// Clone the getter for a new \c FileManager instance. + virtual std::unique_ptr<DependencyDirectivesGetter> + cloneFor(FileManager &FileMgr) = 0; + + /// Get the dependency directives for the given file. + virtual std::optional<ArrayRef<dependency_directives_scan::Directive>> + operator()(FileEntryRef File) = 0; + + virtual ~DependencyDirectivesGetter() = default; +}; } // end namespace clang #endif // LLVM_CLANG_LEX_DEPENDENCYDIRECTIVESSCANNER_H diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 8554068b19607..3ec02a754138f 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -140,12 +140,12 @@ class Preprocessor { friend class VariadicMacroScopeGuard; llvm::unique_function<void(const clang::Token &)> OnToken; - /// Function for getting the dependency preprocessor directives of a file. + /// Functor for getting the dependency preprocessor directives of a file. /// /// These are directives derived from a special form of lexing where the /// source input is scanned for the preprocessor directives that might have an /// effect on the dependencies for a compilation unit. - GetDependencyDirectivesFn GetDependencyDirectives; + DependencyDirectivesGetter *GetDependencyDirectives = nullptr; const PreprocessorOptions &PPOpts; DiagnosticsEngine *Diags; const LangOptions &LangOpts; @@ -1332,8 +1332,8 @@ class Preprocessor { OnToken = std::move(F); } - void setDependencyDirectivesGetter(GetDependencyDirectivesFn Fn) { - GetDependencyDirectives = Fn; + void setDependencyDirectivesGetter(DependencyDirectivesGetter &Get) { + GetDependencyDirectives = &Get; } void setPreprocessToken(bool Preprocess) { PreprocessToken = Preprocess; } diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 0efe0ada4873f..9f27224ddd6f0 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -537,7 +537,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { } if (GetDependencyDirectives) - PP->setDependencyDirectivesGetter(GetDependencyDirectives); + PP->setDependencyDirectivesGetter(*GetDependencyDirectives); } std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) { @@ -1240,7 +1240,9 @@ std::unique_ptr<CompilerInstance> CompilerInstance::cloneForModuleCompileImpl( // Make a copy for the new instance. Instance.FailedModules = FailedModules; - Instance.GetDependencyDirectives = GetDependencyDirectives; + if (GetDependencyDirectives) + Instance.GetDependencyDirectives = + GetDependencyDirectives->cloneFor(Instance.getFileManager()); // If we're collecting module dependencies, we need to share a collector // between all of the module CompilerInstances. Other than that, we don't diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index 09ef921f67202..f95e38317a872 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -94,7 +94,7 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir, Lexer *TheLexer = new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile); if (GetDependencyDirectives && FID != PredefinesFileID) if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) - if (auto MaybeDepDirectives = GetDependencyDirectives(FileMgr, *File)) + if (auto MaybeDepDirectives = (*GetDependencyDirectives)(*File)) TheLexer->DepDirectives = *MaybeDepDirectives; EnterSourceFileWithLexer(TheLexer, CurDir); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index a9e35e0484ac9..ef38c7c9defee 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -357,56 +357,31 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) { std::swap(PPOpts.Macros, NewMacros); } -static GetDependencyDirectivesFn makeDepDirectivesGetter() { - /// This is a functor that conforms to \c GetDependencyDirectivesFn. - /// It ensures it's always invoked with the same \c FileManager and caches the - /// extraction of the scanning VFS for better performance. - struct DepDirectivesGetter { - DepDirectivesGetter() : DepFS(nullptr), FM(nullptr) {} - - /// It's important copies do not carry over the cached members. The copies - /// are likely to be used from distinct \c CompilerInstance objects with - /// distinct \c FileManager \c llvm::vfs::FileSystem. - DepDirectivesGetter(const DepDirectivesGetter &) - : DepFS(nullptr), FM(nullptr) {} - DepDirectivesGetter &operator=(const DepDirectivesGetter &) { - DepFS = nullptr; - FM = nullptr; - return *this; - } - - auto operator()(FileManager &FileMgr, FileEntryRef File) { - ensureConsistentFileManager(FileMgr); - ensurePopulatedFileSystem(FileMgr); - return DepFS->getDirectiveTokens(File.getName()); - } +class ActualDependencyDirectivesGetter : public DependencyDirectivesGetter { + DependencyScanningWorkerFilesystem *DepFS; - private: - DependencyScanningWorkerFilesystem *DepFS; - FileManager *FM; - - void ensureConsistentFileManager(FileManager &FileMgr) { - if (!FM) - FM = &FileMgr; - assert(&FileMgr == FM); - } +public: + ActualDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) { + FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) { + auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS); + if (DFS) { + assert(!DepFS && "Found multiple scanning VFSs"); + DepFS = DFS; + } + }); + assert(DepFS && "Did not find scanning VFS"); + } - void ensurePopulatedFileSystem(FileManager &FM) { - if (DepFS) - return; - FM.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) { - auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS); - if (DFS) { - assert(!DepFS && "Found multiple scanning VFSs"); - DepFS = DFS; - } - }); - assert(DepFS && "Did not find scanning VFS"); - } - }; + std::unique_ptr<DependencyDirectivesGetter> + cloneFor(FileManager &FileMgr) override { + return std::make_unique<ActualDependencyDirectivesGetter>(FileMgr); + } - return DepDirectivesGetter{}; -} + std::optional<ArrayRef<dependency_directives_scan::Directive>> + operator()(FileEntryRef File) override { + return DepFS->getDirectiveTokens(File.getName()); + } +}; /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. @@ -475,6 +450,9 @@ class DependencyScanningAction : public tooling::ToolAction { ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), DriverFileMgr->getVirtualFileSystemPtr()); + // Create a new FileManager to match the invocation's FileSystemOptions. + auto *FileMgr = ScanInstance.createFileManager(FS); + // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { StringRef ModulesCachePath = @@ -484,11 +462,10 @@ class DependencyScanningAction : public tooling::ToolAction { if (!ModulesCachePath.empty()) DepFS->setBypassedPathPrefix(ModulesCachePath); - ScanInstance.setDependencyDirectivesGetter(makeDepDirectivesGetter()); + ScanInstance.setDependencyDirectivesGetter( + std::make_unique<ActualDependencyDirectivesGetter>(*FileMgr)); } - // Create a new FileManager to match the invocation's FileSystemOptions. - auto *FileMgr = ScanInstance.createFileManager(FS); ScanInstance.createSourceManager(*FileMgr); // Store a mapping of prebuilt module files and their properties like header diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp index 5f4c2706a519d..6ab80ba01677e 100644 --- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp +++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp @@ -103,17 +103,31 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { SmallVector<dependency_directives_scan::Token> Tokens; SmallVector<dependency_directives_scan::Directive> Directives; }; - SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects; - - auto GetDependencyDirectives = [&](FileManager &FileMgr, FileEntryRef File) { - DepDirectivesObjects.push_back(std::make_unique<DepDirectives>()); - StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer(); - bool Err = scanSourceForDependencyDirectives( - Input, DepDirectivesObjects.back()->Tokens, - DepDirectivesObjects.back()->Directives); - EXPECT_FALSE(Err); - return llvm::ArrayRef(DepDirectivesObjects.back()->Directives); + + class TestDependencyDirectivesGetter : public DependencyDirectivesGetter { + FileManager &FileMgr; + SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects; + + public: + TestDependencyDirectivesGetter(FileManager &FileMgr) : FileMgr(FileMgr) {} + + std::unique_ptr<DependencyDirectivesGetter> + cloneFor(FileManager &FileMgr) override { + return std::make_unique<TestDependencyDirectivesGetter>(FileMgr); + } + + std::optional<ArrayRef<dependency_directives_scan::Directive>> + operator()(FileEntryRef File) override { + DepDirectivesObjects.push_back(std::make_unique<DepDirectives>()); + StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer(); + bool Err = scanSourceForDependencyDirectives( + Input, DepDirectivesObjects.back()->Tokens, + DepDirectivesObjects.back()->Directives); + EXPECT_FALSE(Err); + return DepDirectivesObjects.back()->Directives; + } }; + TestDependencyDirectivesGetter GetDependencyDirectives(FileMgr); PreprocessorOptions PPOpts; HeaderSearchOptions HSOpts; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits