xref: /llvm-project/clang/unittests/Lex/ModuleDeclStateTest.cpp (revision 3116d60494f219bfcb284d05d9ebed5b6c196ca5)
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