331 lines · cpp
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-exception6//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),58 Diags(DiagnosticIDs::create(), DiagOpts, 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,65 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,72 LangStandard::lang_cxx20);73 LangOpts.CPlusPlusModules = true;74 if (Lang != Language::CXX) {75 LangOpts.Modules = true;76 LangOpts.ImplicitModules = true;77 }78 79 HeaderInfo.emplace(HSOpts, SourceMgr, Diags, LangOpts, Target.get());80 81 return std::make_unique<Preprocessor>(PPOpts, Diags, LangOpts, SourceMgr,82 *HeaderInfo, ModLoader,83 /*IILookup=*/nullptr,84 /*OwnsHeaderSearch=*/false);85 }86 87 void preprocess(Preprocessor &PP, std::unique_ptr<PPCallbacks> C) {88 PP.Initialize(*Target);89 PP.addPPCallbacks(std::move(C));90 PP.EnterMainSourceFile();91 92 PP.LexTokensUntilEOF();93 }94 95 FileSystemOptions FileMgrOpts;96 FileManager FileMgr;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, Language::CXX);114 115 std::initializer_list<bool> ImportKinds = {};116 auto Callback =117 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);118 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();119 preprocess(*PP, std::move(Callback));120 EXPECT_EQ(CallbackPtr->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 127TEST_F(ModuleDeclStateTest, NamedModuleImplementation) {128 const char *source = R"(129module foo;130 )";131 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);132 133 std::initializer_list<bool> ImportKinds = {};134 auto Callback =135 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);136 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();137 preprocess(*PP, std::move(Callback));138 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)0);139 EXPECT_TRUE(PP->isInNamedModule());140 EXPECT_FALSE(PP->isInNamedInterfaceUnit());141 EXPECT_TRUE(PP->isInImplementationUnit());142 EXPECT_EQ(PP->getNamedModuleName(), "foo");143}144 145TEST_F(ModuleDeclStateTest, ModuleImplementationPartition) {146 const char *source = R"(147module foo:part;148 )";149 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);150 151 std::initializer_list<bool> ImportKinds = {};152 auto Callback =153 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);154 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();155 preprocess(*PP, std::move(Callback));156 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)0);157 EXPECT_TRUE(PP->isInNamedModule());158 EXPECT_FALSE(PP->isInNamedInterfaceUnit());159 EXPECT_FALSE(PP->isInImplementationUnit());160 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");161}162 163TEST_F(ModuleDeclStateTest, ModuleInterfacePartition) {164 const char *source = R"(165export module foo:part;166 )";167 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);168 169 std::initializer_list<bool> ImportKinds = {};170 auto Callback =171 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);172 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();173 preprocess(*PP, std::move(Callback));174 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)0);175 EXPECT_TRUE(PP->isInNamedModule());176 EXPECT_TRUE(PP->isInNamedInterfaceUnit());177 EXPECT_FALSE(PP->isInImplementationUnit());178 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");179}180 181TEST_F(ModuleDeclStateTest, ModuleNameWithDot) {182 const char *source = R"(183export module foo.dot:part.dot;184 )";185 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);186 187 std::initializer_list<bool> ImportKinds = {};188 auto Callback =189 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);190 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();191 preprocess(*PP, std::move(Callback));192 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)0);193 EXPECT_TRUE(PP->isInNamedModule());194 EXPECT_TRUE(PP->isInNamedInterfaceUnit());195 EXPECT_FALSE(PP->isInImplementationUnit());196 EXPECT_EQ(PP->getNamedModuleName(), "foo.dot:part.dot");197}198 199TEST_F(ModuleDeclStateTest, NotModule) {200 const char *source = R"(201// export module foo:part;202 )";203 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);204 205 std::initializer_list<bool> ImportKinds = {};206 auto Callback =207 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);208 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();209 preprocess(*PP, std::move(Callback));210 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)0);211 EXPECT_FALSE(PP->isInNamedModule());212 EXPECT_FALSE(PP->isInNamedInterfaceUnit());213 EXPECT_FALSE(PP->isInImplementationUnit());214}215 216TEST_F(ModuleDeclStateTest, ModuleWithGMF) {217 const char *source = R"(218module;219#include "bar.h"220#include <zoo.h>221import "bar";222import <zoo>;223export module foo:part;224import "HU";225import M;226import :another;227 )";228 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);229 230 std::initializer_list<bool> ImportKinds = {true, true};231 auto Callback =232 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);233 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();234 preprocess(*PP, std::move(Callback));235 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)2);236 EXPECT_TRUE(PP->isInNamedModule());237 EXPECT_TRUE(PP->isInNamedInterfaceUnit());238 EXPECT_FALSE(PP->isInImplementationUnit());239 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");240}241 242TEST_F(ModuleDeclStateTest, ModuleWithGMFWithClangNamedModule) {243 const char *source = R"(244module;245#include "bar.h"246#include <zoo.h>247import "bar";248import <zoo>;249export module foo:part;250import "HU";251import M;252import :another;253 )";254 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);255 256 std::initializer_list<bool> ImportKinds = {true, true};257 auto Callback =258 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);259 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();260 preprocess(*PP, std::move(Callback));261 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)2);262 EXPECT_TRUE(PP->isInNamedModule());263 EXPECT_TRUE(PP->isInNamedInterfaceUnit());264 EXPECT_FALSE(PP->isInImplementationUnit());265 EXPECT_EQ(PP->getNamedModuleName(), "foo:part");266}267 268TEST_F(ModuleDeclStateTest, ImportsInNormalTU) {269 const char *source = R"(270#include "bar.h"271#include <zoo.h>272import "bar";273import <zoo>;274import "HU";275import M;276// We can't import a partition in non-module TU.277import :another;278 )";279 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);280 281 std::initializer_list<bool> ImportKinds = {true};282 auto Callback =283 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);284 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();285 preprocess(*PP, std::move(Callback));286 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)1);287 EXPECT_FALSE(PP->isInNamedModule());288 EXPECT_FALSE(PP->isInNamedInterfaceUnit());289 EXPECT_FALSE(PP->isInImplementationUnit());290}291 292TEST_F(ModuleDeclStateTest, ImportAClangNamedModule) {293 const char *source = R"(294@import anything;295 )";296 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::ObjCXX);297 298 std::initializer_list<bool> ImportKinds = {false};299 auto Callback =300 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);301 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();302 preprocess(*PP, std::move(Callback));303 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)1);304 EXPECT_FALSE(PP->isInNamedModule());305 EXPECT_FALSE(PP->isInNamedInterfaceUnit());306 EXPECT_FALSE(PP->isInImplementationUnit());307}308 309TEST_F(ModuleDeclStateTest, ImportWixedForm) {310 const char *source = R"(311import "HU";312@import anything;313import M;314@import another;315import M2;316 )";317 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::ObjCXX);318 319 std::initializer_list<bool> ImportKinds = {false, true, false, true};320 auto Callback =321 std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds);322 CheckNamedModuleImportingCB *CallbackPtr = Callback.get();323 preprocess(*PP, std::move(Callback));324 EXPECT_EQ(CallbackPtr->importNamedModuleNum(), (size_t)4);325 EXPECT_FALSE(PP->isInNamedModule());326 EXPECT_FALSE(PP->isInNamedInterfaceUnit());327 EXPECT_FALSE(PP->isInImplementationUnit());328}329 330} // namespace331