brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.4 KiB · 3132959 Raw
680 lines · cpp
1//===--------------- PrerequisiteModulesTests.cpp -------------------*- C++2//-*-===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10/// FIXME: Skip testing on windows temporarily due to the different escaping11/// code mode.12#ifndef _WIN3213 14#include "Annotations.h"15#include "CodeComplete.h"16#include "Compiler.h"17#include "ModulesBuilder.h"18#include "ScanningProjectModules.h"19#include "TestTU.h"20#include "support/ThreadsafeFS.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/Support/FileSystem.h"23#include "llvm/Support/raw_ostream.h"24#include "gmock/gmock.h"25#include "gtest/gtest.h"26 27namespace clang::clangd {28namespace {29 30class GlobalScanningCounterProjectModules : public ProjectModules {31public:32  GlobalScanningCounterProjectModules(33      std::unique_ptr<ProjectModules> Underlying, std::atomic<unsigned> &Count)34      : Underlying(std::move(Underlying)), Count(Count) {}35 36  std::vector<std::string> getRequiredModules(PathRef File) override {37    return Underlying->getRequiredModules(File);38  }39 40  std::string getModuleNameForSource(PathRef File) override {41    return Underlying->getModuleNameForSource(File);42  }43 44  void setCommandMangler(CommandMangler Mangler) override {45    Underlying->setCommandMangler(std::move(Mangler));46  }47 48  std::string getSourceForModuleName(llvm::StringRef ModuleName,49                                     PathRef RequiredSrcFile) override {50    Count++;51    return Underlying->getSourceForModuleName(ModuleName, RequiredSrcFile);52  }53 54private:55  std::unique_ptr<ProjectModules> Underlying;56  std::atomic<unsigned> &Count;57};58 59class MockDirectoryCompilationDatabase : public MockCompilationDatabase {60public:61  MockDirectoryCompilationDatabase(StringRef TestDir, const ThreadsafeFS &TFS)62      : MockCompilationDatabase(TestDir),63        MockedCDBPtr(std::make_shared<MockClangCompilationDatabase>(*this)),64        TFS(TFS), GlobalScanningCount(0) {65    this->ExtraClangFlags.push_back("-std=c++20");66    this->ExtraClangFlags.push_back("-c");67  }68 69  void addFile(llvm::StringRef Path, llvm::StringRef Contents);70 71  std::unique_ptr<ProjectModules> getProjectModules(PathRef) const override {72    return std::make_unique<GlobalScanningCounterProjectModules>(73        scanningProjectModules(MockedCDBPtr, TFS), GlobalScanningCount);74  }75 76  unsigned getGlobalScanningCount() const { return GlobalScanningCount; }77 78private:79  class MockClangCompilationDatabase : public tooling::CompilationDatabase {80  public:81    MockClangCompilationDatabase(MockDirectoryCompilationDatabase &MCDB)82        : MCDB(MCDB) {}83 84    std::vector<tooling::CompileCommand>85    getCompileCommands(StringRef FilePath) const override {86      std::optional<tooling::CompileCommand> Cmd =87          MCDB.getCompileCommand(FilePath);88      EXPECT_TRUE(Cmd);89      return {*Cmd};90    }91 92    std::vector<std::string> getAllFiles() const override { return Files; }93 94    void AddFile(StringRef File) { Files.push_back(File.str()); }95 96  private:97    MockDirectoryCompilationDatabase &MCDB;98    std::vector<std::string> Files;99  };100 101  std::shared_ptr<MockClangCompilationDatabase> MockedCDBPtr;102  const ThreadsafeFS &TFS;103 104  mutable std::atomic<unsigned> GlobalScanningCount;105};106 107// Add files to the working testing directory and the compilation database.108void MockDirectoryCompilationDatabase::addFile(llvm::StringRef Path,109                                               llvm::StringRef Contents) {110  ASSERT_FALSE(llvm::sys::path::is_absolute(Path));111 112  SmallString<256> AbsPath(Directory);113  llvm::sys::path::append(AbsPath, Path);114 115  ASSERT_FALSE(116      llvm::sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));117 118  std::error_code EC;119  llvm::raw_fd_ostream OS(AbsPath, EC);120  ASSERT_FALSE(EC);121  OS << Contents;122 123  MockedCDBPtr->AddFile(Path);124}125 126class PrerequisiteModulesTests : public ::testing::Test {127protected:128  void SetUp() override {129    ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("modules-test", TestDir));130  }131 132  void TearDown() override {133    ASSERT_FALSE(llvm::sys::fs::remove_directories(TestDir));134  }135 136public:137  // Get the absolute path for file specified by Path under testing working138  // directory.139  std::string getFullPath(llvm::StringRef Path) {140    SmallString<128> Result(TestDir);141    llvm::sys::path::append(Result, Path);142    EXPECT_TRUE(llvm::sys::fs::exists(Result.str()));143    return Result.str().str();144  }145 146  ParseInputs getInputs(llvm::StringRef FileName,147                        const GlobalCompilationDatabase &CDB) {148    std::string FullPathName = getFullPath(FileName);149 150    ParseInputs Inputs;151    std::optional<tooling::CompileCommand> Cmd =152        CDB.getCompileCommand(FullPathName);153    EXPECT_TRUE(Cmd);154    Inputs.CompileCommand = std::move(*Cmd);155    Inputs.TFS = &FS;156 157    if (auto Contents = FS.view(TestDir)->getBufferForFile(FullPathName))158      Inputs.Contents = Contents->get()->getBuffer().str();159 160    return Inputs;161  }162 163  SmallString<256> TestDir;164  // FIXME: It will be better to use the MockFS if the scanning process and165  // build module process doesn't depend on reading real IO.166  RealThreadsafeFS FS;167 168  DiagnosticConsumer DiagConsumer;169};170 171TEST_F(PrerequisiteModulesTests, NonModularTest) {172  MockDirectoryCompilationDatabase CDB(TestDir, FS);173 174  CDB.addFile("foo.h", R"cpp(175inline void foo() {}176  )cpp");177 178  CDB.addFile("NonModular.cpp", R"cpp(179#include "foo.h"180void use() {181  foo();182}183  )cpp");184 185  ModulesBuilder Builder(CDB);186 187  // NonModular.cpp is not related to modules. So nothing should be built.188  auto NonModularInfo =189      Builder.buildPrerequisiteModulesFor(getFullPath("NonModular.cpp"), FS);190  EXPECT_TRUE(NonModularInfo);191 192  HeaderSearchOptions HSOpts;193  NonModularInfo->adjustHeaderSearchOptions(HSOpts);194  EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.empty());195 196  auto Invocation =197      buildCompilerInvocation(getInputs("NonModular.cpp", CDB), DiagConsumer);198  EXPECT_TRUE(NonModularInfo->canReuse(*Invocation, FS.view(TestDir)));199}200 201TEST_F(PrerequisiteModulesTests, ModuleWithoutDepTest) {202  MockDirectoryCompilationDatabase CDB(TestDir, FS);203 204  CDB.addFile("foo.h", R"cpp(205inline void foo() {}206  )cpp");207 208  CDB.addFile("M.cppm", R"cpp(209module;210#include "foo.h"211export module M;212  )cpp");213 214  ModulesBuilder Builder(CDB);215 216  auto MInfo = Builder.buildPrerequisiteModulesFor(getFullPath("M.cppm"), FS);217  EXPECT_TRUE(MInfo);218 219  // Nothing should be built since M doesn't dependent on anything.220  HeaderSearchOptions HSOpts;221  MInfo->adjustHeaderSearchOptions(HSOpts);222  EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.empty());223 224  auto Invocation =225      buildCompilerInvocation(getInputs("M.cppm", CDB), DiagConsumer);226  EXPECT_TRUE(MInfo->canReuse(*Invocation, FS.view(TestDir)));227}228 229TEST_F(PrerequisiteModulesTests, ModuleWithArgumentPatch) {230  MockDirectoryCompilationDatabase CDB(TestDir, FS);231 232  CDB.ExtraClangFlags.push_back("-invalid-unknown-flag");233 234  CDB.addFile("Dep.cppm", R"cpp(235export module Dep;236  )cpp");237 238  CDB.addFile("M.cppm", R"cpp(239export module M;240import Dep;241  )cpp");242 243  // An invalid flag will break the module compilation and the244  // getRequiredModules would return an empty array245  auto ProjectModules = CDB.getProjectModules(getFullPath("M.cppm"));246  EXPECT_TRUE(247      ProjectModules->getRequiredModules(getFullPath("M.cppm")).empty());248 249  // Set the mangler to filter out the invalid flag250  ProjectModules->setCommandMangler([](tooling::CompileCommand &Command,251                                       PathRef) {252    auto const It = llvm::find(Command.CommandLine, "-invalid-unknown-flag");253    Command.CommandLine.erase(It);254  });255 256  // And now it returns a non-empty list of required modules since the257  // compilation succeeded258  EXPECT_FALSE(259      ProjectModules->getRequiredModules(getFullPath("M.cppm")).empty());260}261 262TEST_F(PrerequisiteModulesTests, ModuleWithDepTest) {263  MockDirectoryCompilationDatabase CDB(TestDir, FS);264 265  CDB.addFile("foo.h", R"cpp(266inline void foo() {}267  )cpp");268 269  CDB.addFile("M.cppm", R"cpp(270module;271#include "foo.h"272export module M;273  )cpp");274 275  CDB.addFile("N.cppm", R"cpp(276export module N;277import :Part;278import M;279  )cpp");280 281  CDB.addFile("N-part.cppm", R"cpp(282// Different module name with filename intentionally.283export module N:Part;284  )cpp");285 286  ModulesBuilder Builder(CDB);287 288  auto NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);289  EXPECT_TRUE(NInfo);290 291  ParseInputs NInput = getInputs("N.cppm", CDB);292  std::unique_ptr<CompilerInvocation> Invocation =293      buildCompilerInvocation(NInput, DiagConsumer);294  // Test that `PrerequisiteModules::canReuse` works basically.295  EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));296 297  {298    // Check that299    // `PrerequisiteModules::adjustHeaderSearchOptions(HeaderSearchOptions&)`300    // can appending HeaderSearchOptions correctly.301    HeaderSearchOptions HSOpts;302    NInfo->adjustHeaderSearchOptions(HSOpts);303 304    EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count("M"));305    EXPECT_TRUE(HSOpts.PrebuiltModuleFiles.count("N:Part"));306  }307 308  {309    // Check that310    // `PrerequisiteModules::adjustHeaderSearchOptions(HeaderSearchOptions&)`311    // can replace HeaderSearchOptions correctly.312    HeaderSearchOptions HSOpts;313    HSOpts.PrebuiltModuleFiles["M"] = "incorrect_path";314    HSOpts.PrebuiltModuleFiles["N:Part"] = "incorrect_path";315    NInfo->adjustHeaderSearchOptions(HSOpts);316 317    EXPECT_TRUE(StringRef(HSOpts.PrebuiltModuleFiles["M"]).ends_with(".pcm"));318    EXPECT_TRUE(319        StringRef(HSOpts.PrebuiltModuleFiles["N:Part"]).ends_with(".pcm"));320  }321}322 323TEST_F(PrerequisiteModulesTests, ReusabilityTest) {324  MockDirectoryCompilationDatabase CDB(TestDir, FS);325 326  CDB.addFile("foo.h", R"cpp(327inline void foo() {}328  )cpp");329 330  CDB.addFile("M.cppm", R"cpp(331module;332#include "foo.h"333export module M;334  )cpp");335 336  CDB.addFile("N.cppm", R"cpp(337export module N;338import :Part;339import M;340  )cpp");341 342  CDB.addFile("N-part.cppm", R"cpp(343// Different module name with filename intentionally.344export module N:Part;345  )cpp");346 347  ModulesBuilder Builder(CDB);348 349  auto NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);350  EXPECT_TRUE(NInfo);351  EXPECT_TRUE(NInfo);352 353  ParseInputs NInput = getInputs("N.cppm", CDB);354  std::unique_ptr<CompilerInvocation> Invocation =355      buildCompilerInvocation(NInput, DiagConsumer);356  EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));357 358  // Test that we can still reuse the NInfo after we touch a unrelated file.359  {360    CDB.addFile("L.cppm", R"cpp(361module;362#include "foo.h"363export module L;364export int ll = 43;365  )cpp");366    EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));367 368    CDB.addFile("bar.h", R"cpp(369inline void bar() {}370inline void bar(int) {}371  )cpp");372    EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));373  }374 375  // Test that we can't reuse the NInfo after we touch a related file.376  {377    CDB.addFile("M.cppm", R"cpp(378module;379#include "foo.h"380export module M;381export int mm = 44;382  )cpp");383    EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));384 385    NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);386    EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));387 388    CDB.addFile("foo.h", R"cpp(389inline void foo() {}390inline void foo(int) {}391  )cpp");392    EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));393 394    NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);395    EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));396  }397 398  CDB.addFile("N-part.cppm", R"cpp(399export module N:Part;400// Intentioned to make it uncompilable.401export int NPart = 4LIdjwldijaw402  )cpp");403  EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));404  NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);405  EXPECT_TRUE(NInfo);406  EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));407 408  CDB.addFile("N-part.cppm", R"cpp(409export module N:Part;410export int NPart = 43;411  )cpp");412  EXPECT_TRUE(NInfo);413  EXPECT_FALSE(NInfo->canReuse(*Invocation, FS.view(TestDir)));414  NInfo = Builder.buildPrerequisiteModulesFor(getFullPath("N.cppm"), FS);415  EXPECT_TRUE(NInfo);416  EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));417 418  // Test that if we changed the modification time of the file, the module files419  // info is still reusable if its content doesn't change.420  CDB.addFile("N-part.cppm", R"cpp(421export module N:Part;422export int NPart = 43;423  )cpp");424  EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));425 426  CDB.addFile("N.cppm", R"cpp(427export module N;428import :Part;429import M;430 431export int nn = 43;432  )cpp");433  // NInfo should be reusable after we change its content.434  EXPECT_TRUE(NInfo->canReuse(*Invocation, FS.view(TestDir)));435}436 437// An End-to-End test for modules.438TEST_F(PrerequisiteModulesTests, ParsedASTTest) {439  MockDirectoryCompilationDatabase CDB(TestDir, FS);440 441  CDB.addFile("A.cppm", R"cpp(442export module A;443export void printA();444  )cpp");445 446  CDB.addFile("Use.cpp", R"cpp(447import A;448)cpp");449 450  ModulesBuilder Builder(CDB);451 452  ParseInputs Use = getInputs("Use.cpp", CDB);453  Use.ModulesManager = &Builder;454 455  std::unique_ptr<CompilerInvocation> CI =456      buildCompilerInvocation(Use, DiagConsumer);457  EXPECT_TRUE(CI);458 459  auto Preamble =460      buildPreamble(getFullPath("Use.cpp"), *CI, Use, /*InMemory=*/true,461                    /*Callback=*/nullptr);462  EXPECT_TRUE(Preamble);463  EXPECT_TRUE(Preamble->RequiredModules);464 465  auto AST = ParsedAST::build(getFullPath("Use.cpp"), Use, std::move(CI), {},466                              Preamble);467  EXPECT_TRUE(AST);468 469  const NamedDecl &D = findDecl(*AST, "printA");470  EXPECT_TRUE(D.isFromASTFile());471}472 473// An end to end test for code complete in modules474TEST_F(PrerequisiteModulesTests, CodeCompleteTest) {475  MockDirectoryCompilationDatabase CDB(TestDir, FS);476 477  CDB.addFile("A.cppm", R"cpp(478export module A;479export void printA();480  )cpp");481 482  llvm::StringLiteral UserContents = R"cpp(483import A;484void func() {485  print^486}487)cpp";488 489  CDB.addFile("Use.cpp", UserContents);490  Annotations Test(UserContents);491 492  ModulesBuilder Builder(CDB);493 494  ParseInputs Use = getInputs("Use.cpp", CDB);495  Use.ModulesManager = &Builder;496 497  std::unique_ptr<CompilerInvocation> CI =498      buildCompilerInvocation(Use, DiagConsumer);499  EXPECT_TRUE(CI);500 501  auto Preamble =502      buildPreamble(getFullPath("Use.cpp"), *CI, Use, /*InMemory=*/true,503                    /*Callback=*/nullptr);504  EXPECT_TRUE(Preamble);505  EXPECT_TRUE(Preamble->RequiredModules);506 507  auto Result = codeComplete(getFullPath("Use.cpp"), Test.point(),508                             Preamble.get(), Use, {});509  EXPECT_FALSE(Result.Completions.empty());510  EXPECT_EQ(Result.Completions[0].Name, "printA");511}512 513TEST_F(PrerequisiteModulesTests, SignatureHelpTest) {514  MockDirectoryCompilationDatabase CDB(TestDir, FS);515 516  CDB.addFile("A.cppm", R"cpp(517export module A;518export void printA(int a);519  )cpp");520 521  llvm::StringLiteral UserContents = R"cpp(522import A;523void func() {524  printA(^);525}526)cpp";527 528  CDB.addFile("Use.cpp", UserContents);529  Annotations Test(UserContents);530 531  ModulesBuilder Builder(CDB);532 533  ParseInputs Use = getInputs("Use.cpp", CDB);534  Use.ModulesManager = &Builder;535 536  std::unique_ptr<CompilerInvocation> CI =537      buildCompilerInvocation(Use, DiagConsumer);538  EXPECT_TRUE(CI);539 540  auto Preamble =541      buildPreamble(getFullPath("Use.cpp"), *CI, Use, /*InMemory=*/true,542                    /*Callback=*/nullptr);543  EXPECT_TRUE(Preamble);544  EXPECT_TRUE(Preamble->RequiredModules);545 546  auto Result = signatureHelp(getFullPath("Use.cpp"), Test.point(), *Preamble,547                              Use, MarkupKind::PlainText);548  EXPECT_FALSE(Result.signatures.empty());549  EXPECT_EQ(Result.signatures[0].label, "printA(int a) -> void");550  EXPECT_EQ(Result.signatures[0].parameters[0].labelString, "int a");551}552 553TEST_F(PrerequisiteModulesTests, ReusablePrerequisiteModulesTest) {554  MockDirectoryCompilationDatabase CDB(TestDir, FS);555 556  CDB.addFile("M.cppm", R"cpp(557export module M;558export int M = 43;559  )cpp");560  CDB.addFile("A.cppm", R"cpp(561export module A;562import M;563export int A = 43 + M;564  )cpp");565  CDB.addFile("B.cppm", R"cpp(566export module B;567import M;568export int B = 44 + M;569  )cpp");570 571  ModulesBuilder Builder(CDB);572 573  auto AInfo = Builder.buildPrerequisiteModulesFor(getFullPath("A.cppm"), FS);574  EXPECT_TRUE(AInfo);575  auto BInfo = Builder.buildPrerequisiteModulesFor(getFullPath("B.cppm"), FS);576  EXPECT_TRUE(BInfo);577  HeaderSearchOptions HSOptsA(TestDir);578  HeaderSearchOptions HSOptsB(TestDir);579  AInfo->adjustHeaderSearchOptions(HSOptsA);580  BInfo->adjustHeaderSearchOptions(HSOptsB);581 582  EXPECT_FALSE(HSOptsA.PrebuiltModuleFiles.empty());583  EXPECT_FALSE(HSOptsB.PrebuiltModuleFiles.empty());584 585  // Check that we're reusing the module files.586  EXPECT_EQ(HSOptsA.PrebuiltModuleFiles, HSOptsB.PrebuiltModuleFiles);587 588  // Update M.cppm to check if the modules builder can update correctly.589  CDB.addFile("M.cppm", R"cpp(590export module M;591export constexpr int M = 43;592  )cpp");593 594  ParseInputs AUse = getInputs("A.cppm", CDB);595  AUse.ModulesManager = &Builder;596  std::unique_ptr<CompilerInvocation> AInvocation =597      buildCompilerInvocation(AUse, DiagConsumer);598  EXPECT_FALSE(AInfo->canReuse(*AInvocation, FS.view(TestDir)));599 600  ParseInputs BUse = getInputs("B.cppm", CDB);601  AUse.ModulesManager = &Builder;602  std::unique_ptr<CompilerInvocation> BInvocation =603      buildCompilerInvocation(BUse, DiagConsumer);604  EXPECT_FALSE(BInfo->canReuse(*BInvocation, FS.view(TestDir)));605 606  auto NewAInfo =607      Builder.buildPrerequisiteModulesFor(getFullPath("A.cppm"), FS);608  auto NewBInfo =609      Builder.buildPrerequisiteModulesFor(getFullPath("B.cppm"), FS);610  EXPECT_TRUE(NewAInfo);611  EXPECT_TRUE(NewBInfo);612  HeaderSearchOptions NewHSOptsA(TestDir);613  HeaderSearchOptions NewHSOptsB(TestDir);614  NewAInfo->adjustHeaderSearchOptions(NewHSOptsA);615  NewBInfo->adjustHeaderSearchOptions(NewHSOptsB);616 617  EXPECT_FALSE(NewHSOptsA.PrebuiltModuleFiles.empty());618  EXPECT_FALSE(NewHSOptsB.PrebuiltModuleFiles.empty());619 620  EXPECT_EQ(NewHSOptsA.PrebuiltModuleFiles, NewHSOptsB.PrebuiltModuleFiles);621  // Check that we didn't reuse the old and stale module files.622  EXPECT_NE(NewHSOptsA.PrebuiltModuleFiles, HSOptsA.PrebuiltModuleFiles);623}624 625TEST_F(PrerequisiteModulesTests, ScanningCacheTest) {626  MockDirectoryCompilationDatabase CDB(TestDir, FS);627 628  CDB.addFile("M.cppm", R"cpp(629export module M;630  )cpp");631  CDB.addFile("A.cppm", R"cpp(632export module A;633import M;634  )cpp");635  CDB.addFile("B.cppm", R"cpp(636export module B;637import M;638  )cpp");639 640  ModulesBuilder Builder(CDB);641 642  Builder.buildPrerequisiteModulesFor(getFullPath("A.cppm"), FS);643  Builder.buildPrerequisiteModulesFor(getFullPath("B.cppm"), FS);644  EXPECT_EQ(CDB.getGlobalScanningCount(), 1u);645}646 647TEST_F(PrerequisiteModulesTests, PrebuiltModuleFileTest) {648  MockDirectoryCompilationDatabase CDB(TestDir, FS);649 650  CDB.addFile("M.cppm", R"cpp(651export module M;652  )cpp");653 654  CDB.addFile("U.cpp", R"cpp(655import M;656  )cpp");657 658  // Use ModulesBuilder to produce the prebuilt module file.659  ModulesBuilder Builder(CDB);660  auto ModuleInfo =661      Builder.buildPrerequisiteModulesFor(getFullPath("U.cpp"), FS);662  HeaderSearchOptions HS(TestDir);663  ModuleInfo->adjustHeaderSearchOptions(HS);664 665  CDB.ExtraClangFlags.push_back("-fmodule-file=M=" +666                                HS.PrebuiltModuleFiles["M"]);667  ModulesBuilder Builder2(CDB);668  auto ModuleInfo2 =669      Builder2.buildPrerequisiteModulesFor(getFullPath("U.cpp"), FS);670  HeaderSearchOptions HS2(TestDir);671  ModuleInfo2->adjustHeaderSearchOptions(HS2);672 673  EXPECT_EQ(HS.PrebuiltModuleFiles, HS2.PrebuiltModuleFiles);674}675 676} // namespace677} // namespace clang::clangd678 679#endif680