aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
blob: 55ee72875ead241c85adef4ab35920d66e049616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//===- unittests/Serialization/PreambleInNamedModulesTest.cpp -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/PrecompiledPreamble.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"

#include "gtest/gtest.h"

using namespace llvm;
using namespace clang;

namespace {

class PreambleInNamedModulesTest : public ::testing::Test {
  void SetUp() override {
    ASSERT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir));
  }

  void TearDown() override { sys::fs::remove_directories(TestDir); }

public:
  using PathType = SmallString<256>;

  PathType TestDir;

  void addFile(StringRef Path, StringRef Contents, PathType &AbsPath) {
    ASSERT_FALSE(sys::path::is_absolute(Path));

    AbsPath = TestDir;
    sys::path::append(AbsPath, Path);

    ASSERT_FALSE(
        sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));

    std::error_code EC;
    llvm::raw_fd_ostream OS(AbsPath, EC);
    ASSERT_FALSE(EC);
    OS << Contents;
  }

  void addFile(StringRef Path, StringRef Contents) {
    PathType UnusedAbsPath;
    addFile(Path, Contents, UnusedAbsPath);
  }
};

// Testing that the use of Preamble in named modules can work basically.
// See https://github.com/llvm/llvm-project/issues/80570
TEST_F(PreambleInNamedModulesTest, BasicTest) {
  addFile("foo.h", R"cpp(
enum class E {
    A,
    B,
    C,
    D
};
  )cpp");

  PathType MainFilePath;
  addFile("A.cppm", R"cpp(
module;
#include "foo.h"
export module A;
export using ::E;
  )cpp",
          MainFilePath);

  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
      llvm::vfs::createPhysicalFileSystem();
  DiagnosticOptions DiagOpts;
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
      CompilerInstance::createDiagnostics(*VFS, DiagOpts);

  CreateInvocationOptions CIOpts;
  CIOpts.Diags = Diags;
  CIOpts.VFS = VFS;

  const char *Args[] = {"clang++", "-std=c++20", "-working-directory",
                        TestDir.c_str(), MainFilePath.c_str()};
  std::shared_ptr<CompilerInvocation> Invocation =
      createInvocation(Args, CIOpts);
  ASSERT_TRUE(Invocation);

  llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> ContentsBuffer =
      llvm::MemoryBuffer::getFile(MainFilePath, /*IsText=*/true);
  EXPECT_TRUE(ContentsBuffer);
  std::unique_ptr<MemoryBuffer> Buffer = std::move(*ContentsBuffer);

  PreambleBounds Bounds =
      ComputePreambleBounds(Invocation->getLangOpts(), *Buffer, 0);

  PreambleCallbacks Callbacks;
  llvm::ErrorOr<PrecompiledPreamble> BuiltPreamble = PrecompiledPreamble::Build(
      *Invocation, Buffer.get(), Bounds, Diags, VFS,
      std::make_shared<PCHContainerOperations>(),
      /*StoreInMemory=*/false, /*StoragePath=*/TestDir, Callbacks);

  ASSERT_FALSE(Diags->hasErrorOccurred());

  EXPECT_TRUE(BuiltPreamble);
  EXPECT_TRUE(BuiltPreamble->CanReuse(*Invocation, *Buffer, Bounds, *VFS));
  BuiltPreamble->OverridePreamble(*Invocation, VFS, Buffer.get());

  auto Clang = std::make_unique<CompilerInstance>(std::move(Invocation));
  Clang->setDiagnostics(Diags);
  Clang->createVirtualFileSystem(VFS);
  Clang->createFileManager();
  EXPECT_TRUE(Clang->createTarget());

  Buffer.release();

  SyntaxOnlyAction Action;
  EXPECT_TRUE(Clang->ExecuteAction(Action));
  EXPECT_FALSE(Clang->getDiagnosticsPtr()->hasErrorOccurred());
}

} // namespace