[clang-tools-extra] [clangd] [C++20] [Modules] Introduce initial support for C++20 Modules (PR #66462)
kadir çetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 12 06:17:16 PDT 2024
================
@@ -0,0 +1,355 @@
+//===--------------- PrerequisiteModulesTests.cpp -------------------*- C++
+//-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+/// FIXME: Skip testing on windows temporarily due to the different escaping
+/// code mode.
+#ifndef _WIN32
+
+#include "ModulesBuilder.h"
+#include "ScanningProjectModules.h"
+
+#include "Annotations.h"
+#include "CodeComplete.h"
+#include "Compiler.h"
+#include "TestTU.h"
+#include "support/ThreadsafeFS.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang::clangd {
+namespace {
+
+class MockDirectoryCompilationDatabase : public MockCompilationDatabase {
+public:
+ MockDirectoryCompilationDatabase(StringRef TestDir, const ThreadsafeFS &TFS)
+ : MockCompilationDatabase(TestDir),
+ MockedCDBPtr(std::make_shared<MockClangCompilationDatabase>(*this)),
+ TFS(TFS) {
+ this->ExtraClangFlags.push_back("-std=c++20");
+ this->ExtraClangFlags.push_back("-c");
+ }
+
+ void addFile(llvm::StringRef Path, llvm::StringRef Contents);
+
+ std::unique_ptr<ProjectModules> getProjectModules(PathRef) const override {
+ return scanningProjectModules(MockedCDBPtr, TFS);
+ }
+
+private:
+ class MockClangCompilationDatabase : public tooling::CompilationDatabase {
+ public:
+ MockClangCompilationDatabase(MockDirectoryCompilationDatabase &MCDB)
+ : MCDB(MCDB) {}
+
+ std::vector<tooling::CompileCommand>
+ getCompileCommands(StringRef FilePath) const override {
+ std::optional<tooling::CompileCommand> Cmd =
+ MCDB.getCompileCommand(FilePath);
+ EXPECT_TRUE(Cmd);
+ return {*Cmd};
+ }
+
+ std::vector<std::string> getAllFiles() const override { return Files; }
+
+ void AddFile(StringRef File) { Files.push_back(File.str()); }
+
+ private:
+ MockDirectoryCompilationDatabase &MCDB;
+ std::vector<std::string> Files;
+ };
+
+ std::shared_ptr<MockClangCompilationDatabase> MockedCDBPtr;
+ const ThreadsafeFS &TFS;
+};
+
+// Add files to the working testing directory and the compilation database.
+void MockDirectoryCompilationDatabase::addFile(llvm::StringRef Path,
+ llvm::StringRef Contents) {
+ ASSERT_FALSE(llvm::sys::path::is_absolute(Path));
+
+ SmallString<256> AbsPath(Directory);
+ llvm::sys::path::append(AbsPath, Path);
+
+ ASSERT_FALSE(
+ llvm::sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));
+
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(AbsPath, EC);
+ ASSERT_FALSE(EC);
+ OS << Contents;
+
+ MockedCDBPtr->AddFile(Path);
+}
+
+class PrerequisiteModulesTests : public ::testing::Test {
+protected:
+ void SetUp() override {
+ ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("modules-test", TestDir));
+ }
+
+ void TearDown() override {
+ ASSERT_FALSE(llvm::sys::fs::remove_directories(TestDir));
+ }
+
+public:
+ // Get the absolute path for file specified by Path under testing working
+ // directory.
+ std::string getFullPath(llvm::StringRef Path) {
+ SmallString<128> Result(TestDir);
+ llvm::sys::path::append(Result, Path);
+ EXPECT_TRUE(llvm::sys::fs::exists(Result.str()));
+ return Result.str().str();
+ }
+
+ std::unique_ptr<GlobalCompilationDatabase> getGlobalCompilationDatabase() {
+ // The compilation flags with modules are much complex so it looks better
+ // to use DirectoryBasedGlobalCompilationDatabase than a mocked compilation
+ // database.
+ DirectoryBasedGlobalCompilationDatabase::Options Opts(TFS);
+ return std::make_unique<DirectoryBasedGlobalCompilationDatabase>(Opts);
+ }
+
+ ParseInputs getInputs(llvm::StringRef FileName,
+ const GlobalCompilationDatabase &CDB) {
+ std::string FullPathName = getFullPath(FileName);
+
+ ParseInputs Inputs;
+ std::optional<tooling::CompileCommand> Cmd =
+ CDB.getCompileCommand(FullPathName);
+ EXPECT_TRUE(Cmd);
+ Inputs.CompileCommand = std::move(*Cmd);
+ Inputs.TFS = &TFS;
+
+ if (auto Contents = TFS.view(TestDir)->getBufferForFile(FullPathName))
+ Inputs.Contents = Contents->get()->getBuffer().str();
+
+ return Inputs;
+ }
+
+ SmallString<256> TestDir;
+ // Noticed MockFS but its member variable 'OverlayRealFileSystemForModules'
+ // implies that it will better to use RealThreadsafeFS directly.
+ RealThreadsafeFS TFS;
+
+ DiagnosticConsumer DiagConsumer;
+};
+
+TEST_F(PrerequisiteModulesTests, PrerequisiteModulesTest) {
+ MockDirectoryCompilationDatabase CDB(TestDir, TFS);
+
+ CDB.addFile("foo.h", R"cpp(
+inline void foo() {}
+ )cpp");
+
+ CDB.addFile("M.cppm", R"cpp(
+module;
+#include "foo.h"
+export module M;
+ )cpp");
+
+ CDB.addFile("N.cppm", R"cpp(
+export module N;
+import :Part;
+import M;
+ )cpp");
+
+ CDB.addFile("N-part.cppm", R"cpp(
+// Different name with filename intentionally.
+export module N:Part;
+ )cpp");
+
+ CDB.addFile("bar.h", R"cpp(
+inline void bar() {}
+ )cpp");
+
+ CDB.addFile("L.cppm", R"cpp(
+module;
+#include "bar.h"
+export module L;
+ )cpp");
+
+ CDB.addFile("NonModular.cpp", R"cpp(
+#include "bar.h"
+#include "foo.h"
+void use() {
+ foo();
+ bar();
+}
+ )cpp");
+
+ ModulesBuilder Builder(CDB);
+
+ // NonModular.cpp is not related to modules. So nothing should be built.
+ {
+ auto NonModularInfo =
+ Builder.buildPrerequisiteModulesFor(getFullPath("NonModular.cpp"), TFS);
+ EXPECT_TRUE(NonModularInfo);
+ auto Invocation =
+ buildCompilerInvocation(getInputs("NonModular.cpp", CDB), DiagConsumer);
+ EXPECT_TRUE(NonModularInfo->canReuse(*Invocation, TFS.view(TestDir)));
+ }
+
+ {
+ auto MInfo =
+ Builder.buildPrerequisiteModulesFor(getFullPath("M.cppm"), TFS);
+ // buildPrerequisiteModulesFor won't built the module itself.
+ EXPECT_TRUE(MInfo);
+ auto Invocation =
+ buildCompilerInvocation(getInputs("M.cppm", CDB), DiagConsumer);
+ EXPECT_TRUE(MInfo->canReuse(*Invocation, TFS.view(TestDir)));
+ }
+
+ // Module N shouldn't be able to be built.
----------------
kadircet wrote:
why? and which assertion below is checking that?
https://github.com/llvm/llvm-project/pull/66462
More information about the cfe-commits
mailing list