1 //===- unittests/Serialization/PreambleInNamedModulesTest.cpp -------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "clang/Frontend/CompilerInstance.h"
10 #include "clang/Frontend/CompilerInvocation.h"
11 #include "clang/Frontend/FrontendActions.h"
12 #include "clang/Frontend/PrecompiledPreamble.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/raw_ostream.h"
17 #include "gtest/gtest.h"
20 using namespace clang
;
24 class PreambleInNamedModulesTest
: public ::testing::Test
{
25 void SetUp() override
{
26 ASSERT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir
));
29 void TearDown() override
{ sys::fs::remove_directories(TestDir
); }
32 using PathType
= SmallString
<256>;
36 void addFile(StringRef Path
, StringRef Contents
, PathType
&AbsPath
) {
37 ASSERT_FALSE(sys::path::is_absolute(Path
));
40 sys::path::append(AbsPath
, Path
);
43 sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath
)));
46 llvm::raw_fd_ostream
OS(AbsPath
, EC
);
51 void addFile(StringRef Path
, StringRef Contents
) {
52 PathType UnusedAbsPath
;
53 addFile(Path
, Contents
, UnusedAbsPath
);
57 // Testing that the use of Preamble in named modules can work basically.
58 // See https://github.com/llvm/llvm-project/issues/80570
59 TEST_F(PreambleInNamedModulesTest
, BasicTest
) {
60 addFile("foo.h", R
"cpp(
69 PathType MainFilePath
;
70 addFile("A.cppm", R
"cpp(
78 IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
=
79 llvm::vfs::createPhysicalFileSystem();
80 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags
=
81 CompilerInstance::createDiagnostics(*VFS
, new DiagnosticOptions());
83 CreateInvocationOptions CIOpts
;
87 const char *Args
[] = {"clang++", "-std=c++20", "-working-directory",
88 TestDir
.c_str(), MainFilePath
.c_str()};
89 std::shared_ptr
<CompilerInvocation
> Invocation
=
90 createInvocation(Args
, CIOpts
);
91 ASSERT_TRUE(Invocation
);
93 llvm::ErrorOr
<std::unique_ptr
<MemoryBuffer
>> ContentsBuffer
=
94 llvm::MemoryBuffer::getFile(MainFilePath
, /*IsText=*/true);
95 EXPECT_TRUE(ContentsBuffer
);
96 std::unique_ptr
<MemoryBuffer
> Buffer
= std::move(*ContentsBuffer
);
98 PreambleBounds Bounds
=
99 ComputePreambleBounds(Invocation
->getLangOpts(), *Buffer
, 0);
101 PreambleCallbacks Callbacks
;
102 llvm::ErrorOr
<PrecompiledPreamble
> BuiltPreamble
= PrecompiledPreamble::Build(
103 *Invocation
, Buffer
.get(), Bounds
, *Diags
, VFS
,
104 std::make_shared
<PCHContainerOperations
>(),
105 /*StoreInMemory=*/false, /*StoragePath=*/TestDir
, Callbacks
);
107 ASSERT_FALSE(Diags
->hasErrorOccurred());
109 EXPECT_TRUE(BuiltPreamble
);
110 EXPECT_TRUE(BuiltPreamble
->CanReuse(*Invocation
, *Buffer
, Bounds
, *VFS
));
111 BuiltPreamble
->OverridePreamble(*Invocation
, VFS
, Buffer
.get());
113 auto Clang
= std::make_unique
<CompilerInstance
>(
114 std::make_shared
<PCHContainerOperations
>());
115 Clang
->setInvocation(std::move(Invocation
));
116 Clang
->setDiagnostics(Diags
.get());
118 if (auto VFSWithRemapping
= createVFSFromCompilerInvocation(
119 Clang
->getInvocation(), Clang
->getDiagnostics(), VFS
))
120 VFS
= VFSWithRemapping
;
122 Clang
->createFileManager(VFS
);
123 EXPECT_TRUE(Clang
->createTarget());
127 SyntaxOnlyAction Action
;
128 EXPECT_TRUE(Clang
->ExecuteAction(Action
));
129 EXPECT_FALSE(Clang
->getDiagnosticsPtr()->hasErrorOccurred());