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