1//===- unittests/Lex/ModuleDeclStateTest.cpp - PPCallbacks tests ------===//
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/Basic/Diagnostic.h"
10#include "clang/Basic/DiagnosticOptions.h"
11#include "clang/Basic/FileManager.h"
12#include "clang/Basic/LangOptions.h"
13#include "clang/Basic/SourceManager.h"
14#include "clang/Basic/TargetInfo.h"
15#include "clang/Basic/TargetOptions.h"
16#include "clang/Lex/HeaderSearch.h"
17#include "clang/Lex/HeaderSearchOptions.h"
18#include "clang/Lex/ModuleLoader.h"
19#include "clang/Lex/Preprocessor.h"
20#include "clang/Lex/PreprocessorOptions.h"
21#include "gtest/gtest.h"
22#include <cstddef>
23#include <initializer_list>
24
25using namespace clang;
26
27namespace {
28
29class CheckNamedModuleImportingCB : public PPCallbacks {
30 Preprocessor &PP;
31 std::vector<bool> IsImportingNamedModulesAssertions;
32 std::size_t NextCheckingIndex;
33
34public:
35 CheckNamedModuleImportingCB(Preprocessor &PP,
36 std::initializer_list<bool> lists)
37 : PP(PP), IsImportingNamedModulesAssertions(lists), NextCheckingIndex(0) {
38 }
39
40 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
41 const Module *Imported) override {
42 ASSERT_TRUE(NextCheckingIndex < IsImportingNamedModulesAssertions.size());
43 EXPECT_EQ(PP.isInImportingCXXNamedModules(),
44 IsImportingNamedModulesAssertions[NextCheckingIndex]);
45 NextCheckingIndex++;
46
47 ASSERT_EQ(Imported, nullptr);
48 }
49
50 // Currently, only the named module will be handled by `moduleImport`
51 // callback.
52 std::size_t importNamedModuleNum() { return NextCheckingIndex; }
53};
54class ModuleDeclStateTest : public ::testing::Test {
55protected:
56 ModuleDeclStateTest()
57 : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
58 Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
59 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
60 TargetOpts->Triple = "x86_64-unknown-linux-gnu";
61 Target = TargetInfo::CreateTargetInfo(Diags, Opts&: *TargetOpts);
62 }
63
64 std::unique_ptr<Preprocessor>
65 getPreprocessor(const char *source, Language Lang) {
66 std::unique_ptr<llvm::MemoryBuffer> Buf =
67 llvm::MemoryBuffer::getMemBuffer(InputData: source);
68 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(Buf)));
69
70 std::vector<std::string> Includes;
71 LangOptions::setLangDefaults(Opts&: LangOpts, Lang, T: Target->getTriple(), Includes, LangStd: LangStandard::lang_cxx20);
72 LangOpts.CPlusPlusModules = true;
73 if (Lang != Language::CXX) {
74 LangOpts.Modules = true;
75 LangOpts.ImplicitModules = true;
76 }
77
78 HeaderInfo.emplace(args&: HSOpts, args&: SourceMgr, args&: Diags, args&: LangOpts, args: Target.get());
79
80 return std::make_unique<Preprocessor>(args&: PPOpts, args&: Diags, args&: LangOpts, args&: SourceMgr,
81 args&: *HeaderInfo, args&: ModLoader,
82 /*IILookup=*/args: nullptr,
83 /*OwnsHeaderSearch=*/args: false);
84 }
85
86 void preprocess(Preprocessor &PP, std::unique_ptr<PPCallbacks> C) {
87 PP.Initialize(Target: *Target);
88 PP.addPPCallbacks(C: std::move(C));
89 PP.EnterMainSourceFile();
90
91 PP.LexTokensUntilEOF();
92 }
93
94 FileSystemOptions FileMgrOpts;
95 FileManager FileMgr;
96 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
97 DiagnosticOptions DiagOpts;
98 DiagnosticsEngine Diags;
99 SourceManager SourceMgr;
100 std::shared_ptr<TargetOptions> TargetOpts;
101 IntrusiveRefCntPtr<TargetInfo> Target;
102 LangOptions LangOpts;
103 TrivialModuleLoader ModLoader;
104 HeaderSearchOptions HSOpts;
105 std::optional<HeaderSearch> HeaderInfo;
106 PreprocessorOptions PPOpts;
107};
108
109TEST_F(ModuleDeclStateTest, NamedModuleInterface) {
110 const char *source = R"(
111export module foo;
112 )";
113 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
114
115 std::initializer_list<bool> ImportKinds = {};
116 preprocess(PP&: *PP,
117 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
118
119 auto *Callback =
120 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
121 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
122 EXPECT_TRUE(PP->isInNamedModule());
123 EXPECT_TRUE(PP->isInNamedInterfaceUnit());
124 EXPECT_FALSE(PP->isInImplementationUnit());
125 EXPECT_EQ(PP->getNamedModuleName(), "foo");
126}
127
128TEST_F(ModuleDeclStateTest, NamedModuleImplementation) {
129 const char *source = R"(
130module foo;
131 )";
132 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
133
134 std::initializer_list<bool> ImportKinds = {};
135 preprocess(PP&: *PP,
136 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
137
138 auto *Callback =
139 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
140 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
141 EXPECT_TRUE(PP->isInNamedModule());
142 EXPECT_FALSE(PP->isInNamedInterfaceUnit());
143 EXPECT_TRUE(PP->isInImplementationUnit());
144 EXPECT_EQ(PP->getNamedModuleName(), "foo");
145}
146
147TEST_F(ModuleDeclStateTest, ModuleImplementationPartition) {
148 const char *source = R"(
149module foo:part;
150 )";
151 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
152
153 std::initializer_list<bool> ImportKinds = {};
154 preprocess(PP&: *PP,
155 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
156
157 auto *Callback =
158 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
159 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
160 EXPECT_TRUE(PP->isInNamedModule());
161 EXPECT_FALSE(PP->isInNamedInterfaceUnit());
162 EXPECT_FALSE(PP->isInImplementationUnit());
163 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
164}
165
166TEST_F(ModuleDeclStateTest, ModuleInterfacePartition) {
167 const char *source = R"(
168export module foo:part;
169 )";
170 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
171
172 std::initializer_list<bool> ImportKinds = {};
173 preprocess(PP&: *PP,
174 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
175
176 auto *Callback =
177 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
178 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
179 EXPECT_TRUE(PP->isInNamedModule());
180 EXPECT_TRUE(PP->isInNamedInterfaceUnit());
181 EXPECT_FALSE(PP->isInImplementationUnit());
182 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
183}
184
185TEST_F(ModuleDeclStateTest, ModuleNameWithDot) {
186 const char *source = R"(
187export module foo.dot:part.dot;
188 )";
189 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
190
191 std::initializer_list<bool> ImportKinds = {};
192 preprocess(PP&: *PP,
193 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
194
195 auto *Callback =
196 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
197 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
198 EXPECT_TRUE(PP->isInNamedModule());
199 EXPECT_TRUE(PP->isInNamedInterfaceUnit());
200 EXPECT_FALSE(PP->isInImplementationUnit());
201 EXPECT_EQ(PP->getNamedModuleName(), "foo.dot:part.dot");
202}
203
204TEST_F(ModuleDeclStateTest, NotModule) {
205 const char *source = R"(
206// export module foo:part;
207 )";
208 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
209
210 std::initializer_list<bool> ImportKinds = {};
211 preprocess(PP&: *PP,
212 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
213
214 auto *Callback =
215 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
216 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
217 EXPECT_FALSE(PP->isInNamedModule());
218 EXPECT_FALSE(PP->isInNamedInterfaceUnit());
219 EXPECT_FALSE(PP->isInImplementationUnit());
220}
221
222TEST_F(ModuleDeclStateTest, ModuleWithGMF) {
223 const char *source = R"(
224module;
225#include "bar.h"
226#include <zoo.h>
227import "bar";
228import <zoo>;
229export module foo:part;
230import "HU";
231import M;
232import :another;
233 )";
234 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
235
236 std::initializer_list<bool> ImportKinds = {true, true};
237 preprocess(PP&: *PP,
238 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
239
240 auto *Callback =
241 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
242 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)2);
243 EXPECT_TRUE(PP->isInNamedModule());
244 EXPECT_TRUE(PP->isInNamedInterfaceUnit());
245 EXPECT_FALSE(PP->isInImplementationUnit());
246 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
247}
248
249TEST_F(ModuleDeclStateTest, ModuleWithGMFWithClangNamedModule) {
250 const char *source = R"(
251module;
252#include "bar.h"
253#include <zoo.h>
254import "bar";
255import <zoo>;
256export module foo:part;
257import "HU";
258import M;
259import :another;
260 )";
261 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
262
263 std::initializer_list<bool> ImportKinds = {true, true};
264 preprocess(PP&: *PP,
265 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
266
267 auto *Callback =
268 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
269 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)2);
270 EXPECT_TRUE(PP->isInNamedModule());
271 EXPECT_TRUE(PP->isInNamedInterfaceUnit());
272 EXPECT_FALSE(PP->isInImplementationUnit());
273 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
274}
275
276TEST_F(ModuleDeclStateTest, ImportsInNormalTU) {
277 const char *source = R"(
278#include "bar.h"
279#include <zoo.h>
280import "bar";
281import <zoo>;
282import "HU";
283import M;
284// We can't import a partition in non-module TU.
285import :another;
286 )";
287 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
288
289 std::initializer_list<bool> ImportKinds = {true};
290 preprocess(PP&: *PP,
291 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
292
293 auto *Callback =
294 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
295 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)1);
296 EXPECT_FALSE(PP->isInNamedModule());
297 EXPECT_FALSE(PP->isInNamedInterfaceUnit());
298 EXPECT_FALSE(PP->isInImplementationUnit());
299}
300
301TEST_F(ModuleDeclStateTest, ImportAClangNamedModule) {
302 const char *source = R"(
303@import anything;
304 )";
305 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::ObjCXX);
306
307 std::initializer_list<bool> ImportKinds = {false};
308 preprocess(PP&: *PP,
309 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
310
311 auto *Callback =
312 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
313 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)1);
314 EXPECT_FALSE(PP->isInNamedModule());
315 EXPECT_FALSE(PP->isInNamedInterfaceUnit());
316 EXPECT_FALSE(PP->isInImplementationUnit());
317}
318
319TEST_F(ModuleDeclStateTest, ImportWixedForm) {
320 const char *source = R"(
321import "HU";
322@import anything;
323import M;
324@import another;
325import M2;
326 )";
327 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::ObjCXX);
328
329 std::initializer_list<bool> ImportKinds = {false, true, false, true};
330 preprocess(PP&: *PP,
331 C: std::make_unique<CheckNamedModuleImportingCB>(args&: *PP, args&: ImportKinds));
332
333 auto *Callback =
334 static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
335 EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)4);
336 EXPECT_FALSE(PP->isInNamedModule());
337 EXPECT_FALSE(PP->isInNamedInterfaceUnit());
338 EXPECT_FALSE(PP->isInImplementationUnit());
339}
340
341} // namespace
342

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/unittests/Lex/ModuleDeclStateTest.cpp