1//===- unittests/Serialization/PreambleInNamedModulesTest.cpp -------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
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"
16
17#include "gtest/gtest.h"
18
19using namespace llvm;
20using namespace clang;
21
22namespace {
23
24class PreambleInNamedModulesTest : public ::testing::Test {
25 void SetUp() override {
26 ASSERT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir));
27 }
28
29 void TearDown() override { sys::fs::remove_directories(path: TestDir); }
30
31public:
32 using PathType = SmallString<256>;
33
34 PathType TestDir;
35
36 void addFile(StringRef Path, StringRef Contents, PathType &AbsPath) {
37 ASSERT_FALSE(sys::path::is_absolute(Path));
38
39 AbsPath = TestDir;
40 sys::path::append(path&: AbsPath, a: Path);
41
42 ASSERT_FALSE(
43 sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));
44
45 std::error_code EC;
46 llvm::raw_fd_ostream OS(AbsPath, EC);
47 ASSERT_FALSE(EC);
48 OS << Contents;
49 }
50
51 void addFile(StringRef Path, StringRef Contents) {
52 PathType UnusedAbsPath;
53 addFile(Path, Contents, AbsPath&: UnusedAbsPath);
54 }
55};
56
57// Testing that the use of Preamble in named modules can work basically.
58// See https://github.com/llvm/llvm-project/issues/80570
59TEST_F(PreambleInNamedModulesTest, BasicTest) {
60 addFile(Path: "foo.h", Contents: R"cpp(
61enum class E {
62 A,
63 B,
64 C,
65 D
66};
67 )cpp");
68
69 PathType MainFilePath;
70 addFile(Path: "A.cppm", Contents: R"cpp(
71module;
72#include "foo.h"
73export module A;
74export using ::E;
75 )cpp",
76 AbsPath&: MainFilePath);
77
78 IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
79 CompilerInstance::createDiagnostics(Opts: new DiagnosticOptions());
80 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
81 llvm::vfs::createPhysicalFileSystem();
82
83 CreateInvocationOptions CIOpts;
84 CIOpts.Diags = Diags;
85 CIOpts.VFS = VFS;
86
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, Opts: CIOpts);
91 ASSERT_TRUE(Invocation);
92
93 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> ContentsBuffer =
94 llvm::MemoryBuffer::getFile(Filename: MainFilePath, /*IsText=*/true);
95 EXPECT_TRUE(ContentsBuffer);
96 std::unique_ptr<MemoryBuffer> Buffer = std::move(*ContentsBuffer);
97
98 PreambleBounds Bounds =
99 ComputePreambleBounds(LangOpts: Invocation->getLangOpts(), Buffer: *Buffer, MaxLines: 0);
100
101 PreambleCallbacks Callbacks;
102 llvm::ErrorOr<PrecompiledPreamble> BuiltPreamble = PrecompiledPreamble::Build(
103 Invocation: *Invocation, MainFileBuffer: Buffer.get(), Bounds, Diagnostics&: *Diags, VFS,
104 PCHContainerOps: std::make_shared<PCHContainerOperations>(),
105 /*StoreInMemory=*/false, /*StoragePath=*/TestDir, Callbacks);
106
107 ASSERT_FALSE(Diags->hasErrorOccurred());
108
109 EXPECT_TRUE(BuiltPreamble);
110 EXPECT_TRUE(BuiltPreamble->CanReuse(*Invocation, *Buffer, Bounds, *VFS));
111 BuiltPreamble->OverridePreamble(CI&: *Invocation, VFS, MainFileBuffer: Buffer.get());
112
113 auto Clang = std::make_unique<CompilerInstance>(
114 args: std::make_shared<PCHContainerOperations>());
115 Clang->setInvocation(std::move(Invocation));
116 Clang->setDiagnostics(Diags.get());
117
118 if (auto VFSWithRemapping = createVFSFromCompilerInvocation(
119 CI: Clang->getInvocation(), Diags&: Clang->getDiagnostics(), BaseFS: VFS))
120 VFS = VFSWithRemapping;
121
122 Clang->createFileManager(VFS);
123 EXPECT_TRUE(Clang->createTarget());
124
125 Buffer.release();
126
127 SyntaxOnlyAction Action;
128 EXPECT_TRUE(Clang->ExecuteAction(Action));
129 EXPECT_FALSE(Clang->getDiagnosticsPtr()->hasErrorOccurred());
130}
131
132} // namespace
133

source code of clang/unittests/Serialization/PreambleInNamedModulesTest.cpp