diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Compiler.h" +#include "Config.h" #include "support/Logger.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInvocation.h" @@ -89,6 +90,11 @@ CI.getLangOpts()->ProfileListFiles.clear(); CI.getLangOpts()->XRayAlwaysInstrumentFiles.clear(); CI.getLangOpts()->XRayNeverInstrumentFiles.clear(); + + if (!Config::current().CompileFlags.NaiveModules) { + CI.getLangOpts()->Modules = false; + CI.getLangOpts()->CPlusPlusModules = false; + } } std::unique_ptr diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -66,6 +66,8 @@ Edits; /// Where to search for compilation databases for this file's flags. CDBSearchSpec CDBSearch = {CDBSearchSpec::Ancestors, std::nullopt}; + /// Allow modules when enabled by -fmodules, -std=c++20, etc. + bool NaiveModules = true; } CompileFlags; enum class BackgroundPolicy { Build, Skip }; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -320,6 +320,12 @@ C.CompileFlags.CDBSearch = Spec; }); } + + if (F.NaiveModules) + Out.Apply.push_back( + [NaiveModules(**F.NaiveModules)](const Params &, Config &C) { + C.CompileFlags.NaiveModules = NaiveModules; + }); } void compile(Fragment::IndexBlock &&F) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -169,6 +169,11 @@ /// - Ancestors: search all parent directories (the default) /// - std::nullopt: do not use a compilation database, just default flags. std::optional> CompilationDatabase; + + /// Allow flags such as -fmodules or -std=c++20 to enable modules. + /// We don't support modules: https://github.com/clangd/clangd/issues/1293 + /// However some configurations may happen to work anyway. + std::optional> NaiveModules; }; CompileFlagsBlock CompileFlags; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -108,6 +108,9 @@ Dict.handle("CompilationDatabase", [&](Node &N) { F.CompilationDatabase = scalarValue(N, "CompilationDatabase"); }); + Dict.handle("NaiveModules", [&](Node &N) { + F.NaiveModules = boolValue(N, "NaiveModules"); + }); Dict.parse(N); } diff --git a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp --- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp @@ -6,12 +6,15 @@ // //===----------------------------------------------------------------------===// #include "Annotations.h" +#include "Config.h" #include "FindSymbols.h" #include "TestFS.h" #include "TestTU.h" +#include "support/Context.h" #include "llvm/ADT/StringRef.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include namespace clang { namespace clangd { @@ -491,6 +494,10 @@ } TEST(DocumentSymbols, ExportContext) { + Config EnableModules; + EnableModules.CompileFlags.NaiveModules = true; + WithContextValue WithCfg(Config::Key, std::move(EnableModules)); + TestTU TU; TU.ExtraArgs = {"-std=c++20"}; TU.Code = R"cpp( diff --git a/clang-tools-extra/clangd/unittests/ModulesTests.cpp b/clang-tools-extra/clangd/unittests/ModulesTests.cpp --- a/clang-tools-extra/clangd/unittests/ModulesTests.cpp +++ b/clang-tools-extra/clangd/unittests/ModulesTests.cpp @@ -6,8 +6,10 @@ // //===----------------------------------------------------------------------===// +#include "Config.h" #include "TestFS.h" #include "TestTU.h" +#include "support/Context.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -18,7 +20,21 @@ namespace clangd { namespace { -TEST(Modules, TextualIncludeInPreamble) { +enum class ModulesMode { Disabled, Naive }; +Config makeModuleConfig(ModulesMode M) { + Config EnableModules; + EnableModules.CompileFlags.NaiveModules = M == ModulesMode::Naive; + return EnableModules; +} + +class ModulesTest : public ::testing::TestWithParam { + WithContextValue WithCfg; + +protected: + ModulesTest() : WithCfg(Config::Key, makeModuleConfig(GetParam())) {} +}; + +TEST_P(ModulesTest, TextualIncludeInPreamble) { TestTU TU = TestTU::withCode(R"cpp( #include "Textual.h" @@ -40,7 +56,7 @@ // Verify that visibility of AST nodes belonging to modules, but loaded from // preamble PCH, is restored. -TEST(Modules, PreambleBuildVisibility) { +TEST_P(ModulesTest, PreambleBuildVisibility) { TestTU TU = TestTU::withCode(R"cpp( #include "module.h" @@ -63,7 +79,7 @@ EXPECT_TRUE(TU.build().getDiagnostics().empty()); } -TEST(Modules, Diagnostic) { +TEST_P(ModulesTest, Diagnostic) { // Produce a diagnostic while building an implicit module. Use // -fmodules-strict-decluse, but any non-silenced diagnostic will do. TestTU TU = TestTU::withCode(R"cpp( @@ -92,7 +108,7 @@ } // Unknown module formats are a fatal failure for clang. Ensure we don't crash. -TEST(Modules, UnknownFormat) { +TEST_P(ModulesTest, UnknownFormat) { TestTU TU = TestTU::withCode(R"(#include "modular.h")"); TU.OverlayRealFileSystemForModules = true; TU.ExtraArgs.push_back("-Xclang"); @@ -109,6 +125,25 @@ // Test that we do not crash. TU.build(); } + +MATCHER_P(diag, M, "") { return arg.Message == M; } + +TEST_P(ModulesTest, Cpp20Import) { + TestTU TU = TestTU::withCode("import foo; // error-ok"); + TU.ExtraArgs.push_back("-Xclang"); + TU.ExtraArgs.push_back("-std=c++20"); + + auto AST = TU.build(); + EXPECT_THAT(AST.getDiagnostics(), + testing::ElementsAre(GetParam() == ModulesMode::Naive + ? diag("module 'foo' not found") + : diag("unknown type name 'import'"))); +} + +INSTANTIATE_TEST_SUITE_P(ModulesTestModes, ModulesTest, + testing::Values(ModulesMode::Disabled, + ModulesMode::Naive)); + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -7,9 +7,11 @@ //===----------------------------------------------------------------------===// #include "Annotations.h" +#include "Config.h" #include "TestFS.h" #include "TestTU.h" #include "index/SymbolCollector.h" +#include "support/Context.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Frontend/CompilerInstance.h" @@ -28,6 +30,7 @@ #include #include #include +#include namespace clang { namespace clangd { @@ -1918,6 +1921,10 @@ // Regression test for a crash-bug we used to have. TEST_F(SymbolCollectorTest, UndefOfModuleMacro) { + Config EnableModules; + EnableModules.CompileFlags.NaiveModules = true; + WithContextValue WithCfg(Config::Key, std::move(EnableModules)); + auto TU = TestTU::withCode(R"cpp(#include "bar.h")cpp"); TU.AdditionalFiles["bar.h"] = R"cpp( #include "foo.h"