view clang/unittests/Lex/ModuleDeclStateTest.cpp @ 266:00f31e85ec16 default tip

Added tag current for changeset 31d058e83c98
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 14 Oct 2023 10:13:55 +0900
parents 1f2b6ac9f198
children
line wrap: on
line source

//===- 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();

    while (1) {
      Token tok;
      PP.Lex(tok);
      if (tok.is(tok::eof))
        break;
    }
  }

  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