mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-05-14 01:46:41 +00:00

This new method repeatedly calls Lex() until end of file is reached and optionally fills a std::vector of Tokens. Use it in Clang's unit tests to avoid quite some code duplication. Differential Revision: https://reviews.llvm.org/D158413
341 lines
11 KiB
C++
341 lines
11 KiB
C++
//===- unittests/Lex/ModuleDeclStateTest.cpp - PPCallbacks tests ------===//
|
|
//
|
|
// 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/Basic/Diagnostic.h"
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
#include "clang/Basic/FileManager.h"
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "clang/Basic/TargetInfo.h"
|
|
#include "clang/Basic/TargetOptions.h"
|
|
#include "clang/Lex/HeaderSearch.h"
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
|
#include "clang/Lex/ModuleLoader.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Lex/PreprocessorOptions.h"
|
|
#include "gtest/gtest.h"
|
|
#include <cstddef>
|
|
#include <initializer_list>
|
|
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
|
|
class CheckNamedModuleImportingCB : public PPCallbacks {
|
|
Preprocessor &PP;
|
|
std::vector<bool> IsImportingNamedModulesAssertions;
|
|
std::size_t NextCheckingIndex;
|
|
|
|
public:
|
|
CheckNamedModuleImportingCB(Preprocessor &PP,
|
|
std::initializer_list<bool> lists)
|
|
: PP(PP), IsImportingNamedModulesAssertions(lists), NextCheckingIndex(0) {
|
|
}
|
|
|
|
void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
|
|
const Module *Imported) override {
|
|
ASSERT_TRUE(NextCheckingIndex < IsImportingNamedModulesAssertions.size());
|
|
EXPECT_EQ(PP.isInImportingCXXNamedModules(),
|
|
IsImportingNamedModulesAssertions[NextCheckingIndex]);
|
|
NextCheckingIndex++;
|
|
|
|
ASSERT_EQ(Imported, nullptr);
|
|
}
|
|
|
|
// Currently, only the named module will be handled by `moduleImport`
|
|
// callback.
|
|
std::size_t importNamedModuleNum() { return NextCheckingIndex; }
|
|
};
|
|
class ModuleDeclStateTest : public ::testing::Test {
|
|
protected:
|
|
ModuleDeclStateTest()
|
|
: FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
|
|
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
|
|
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
|
|
TargetOpts->Triple = "x86_64-unknown-linux-gnu";
|
|
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
|
|
}
|
|
|
|
std::unique_ptr<Preprocessor>
|
|
getPreprocessor(const char *source, Language Lang) {
|
|
std::unique_ptr<llvm::MemoryBuffer> Buf =
|
|
llvm::MemoryBuffer::getMemBuffer(source);
|
|
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
|
|
|
|
std::vector<std::string> Includes;
|
|
LangOptions::setLangDefaults(LangOpts, Lang, Target->getTriple(), Includes, LangStandard::lang_cxx20);
|
|
LangOpts.CPlusPlusModules = true;
|
|
if (Lang != Language::CXX) {
|
|
LangOpts.Modules = true;
|
|
LangOpts.ImplicitModules = true;
|
|
}
|
|
|
|
HeaderInfo.emplace(std::make_shared<HeaderSearchOptions>(), SourceMgr,
|
|
Diags, LangOpts, Target.get());
|
|
|
|
return std::make_unique<Preprocessor>(
|
|
std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
|
|
*HeaderInfo, ModLoader,
|
|
/*IILookup =*/nullptr,
|
|
/*OwnsHeaderSearch =*/false);
|
|
}
|
|
|
|
void preprocess(Preprocessor &PP, std::unique_ptr<PPCallbacks> C) {
|
|
PP.Initialize(*Target);
|
|
PP.addPPCallbacks(std::move(C));
|
|
PP.EnterMainSourceFile();
|
|
|
|
PP.LexTokensUntilEOF();
|
|
}
|
|
|
|
FileSystemOptions FileMgrOpts;
|
|
FileManager FileMgr;
|
|
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
|
|
DiagnosticsEngine Diags;
|
|
SourceManager SourceMgr;
|
|
std::shared_ptr<TargetOptions> TargetOpts;
|
|
IntrusiveRefCntPtr<TargetInfo> Target;
|
|
LangOptions LangOpts;
|
|
TrivialModuleLoader ModLoader;
|
|
std::optional<HeaderSearch> HeaderInfo;
|
|
};
|
|
|
|
TEST_F(ModuleDeclStateTest, NamedModuleInterface) {
|
|
const char *source = R"(
|
|
export module foo;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_TRUE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, NamedModuleImplementation) {
|
|
const char *source = R"(
|
|
module foo;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_FALSE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_TRUE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ModuleImplementationPartition) {
|
|
const char *source = R"(
|
|
module foo:part;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_FALSE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ModuleInterfacePartition) {
|
|
const char *source = R"(
|
|
export module foo:part;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_TRUE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ModuleNameWithDot) {
|
|
const char *source = R"(
|
|
export module foo.dot:part.dot;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_TRUE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo.dot:part.dot");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, NotModule) {
|
|
const char *source = R"(
|
|
// export module foo:part;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)0);
|
|
EXPECT_FALSE(PP->isInNamedModule());
|
|
EXPECT_FALSE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ModuleWithGMF) {
|
|
const char *source = R"(
|
|
module;
|
|
#include "bar.h"
|
|
#include <zoo.h>
|
|
import "bar";
|
|
import <zoo>;
|
|
export module foo:part;
|
|
import "HU";
|
|
import M;
|
|
import :another;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {true, true};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)2);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_TRUE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ModuleWithGMFWithClangNamedModule) {
|
|
const char *source = R"(
|
|
module;
|
|
#include "bar.h"
|
|
#include <zoo.h>
|
|
import "bar";
|
|
import <zoo>;
|
|
export module foo:part;
|
|
import "HU";
|
|
import M;
|
|
import :another;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {true, true};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)2);
|
|
EXPECT_TRUE(PP->isInNamedModule());
|
|
EXPECT_TRUE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
EXPECT_EQ(PP->getNamedModuleName(), "foo:part");
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ImportsInNormalTU) {
|
|
const char *source = R"(
|
|
#include "bar.h"
|
|
#include <zoo.h>
|
|
import "bar";
|
|
import <zoo>;
|
|
import "HU";
|
|
import M;
|
|
// We can't import a partition in non-module TU.
|
|
import :another;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {true};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)1);
|
|
EXPECT_FALSE(PP->isInNamedModule());
|
|
EXPECT_FALSE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ImportAClangNamedModule) {
|
|
const char *source = R"(
|
|
@import anything;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::ObjCXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {false};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)1);
|
|
EXPECT_FALSE(PP->isInNamedModule());
|
|
EXPECT_FALSE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
}
|
|
|
|
TEST_F(ModuleDeclStateTest, ImportWixedForm) {
|
|
const char *source = R"(
|
|
import "HU";
|
|
@import anything;
|
|
import M;
|
|
@import another;
|
|
import M2;
|
|
)";
|
|
std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::ObjCXX);
|
|
|
|
std::initializer_list<bool> ImportKinds = {false, true, false, true};
|
|
preprocess(*PP,
|
|
std::make_unique<CheckNamedModuleImportingCB>(*PP, ImportKinds));
|
|
|
|
auto *Callback =
|
|
static_cast<CheckNamedModuleImportingCB *>(PP->getPPCallbacks());
|
|
EXPECT_EQ(Callback->importNamedModuleNum(), (size_t)4);
|
|
EXPECT_FALSE(PP->isInNamedModule());
|
|
EXPECT_FALSE(PP->isInNamedInterfaceUnit());
|
|
EXPECT_FALSE(PP->isInImplementationUnit());
|
|
}
|
|
|
|
} // namespace
|