103ea140bSSam McCall //===-- StdLibTests.cpp -----------------------------------------*- C++ -*-===//
203ea140bSSam McCall //
303ea140bSSam McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
403ea140bSSam McCall // See https://llvm.org/LICENSE.txt for license information.
503ea140bSSam McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
603ea140bSSam McCall //
703ea140bSSam McCall //===----------------------------------------------------------------------===//
803ea140bSSam McCall
903ea140bSSam McCall #include "Annotations.h"
1003ea140bSSam McCall #include "ClangdServer.h"
1103ea140bSSam McCall #include "CodeComplete.h"
1203ea140bSSam McCall #include "Compiler.h"
1303ea140bSSam McCall #include "Config.h"
1403ea140bSSam McCall #include "SyncAPI.h"
1503ea140bSSam McCall #include "TestFS.h"
1603ea140bSSam McCall #include "index/StdLib.h"
1703ea140bSSam McCall #include "clang/Basic/LangOptions.h"
1803ea140bSSam McCall #include "clang/Basic/SourceManager.h"
1903ea140bSSam McCall #include "gmock/gmock.h"
2003ea140bSSam McCall #include "gtest/gtest.h"
2103ea140bSSam McCall #include <memory>
2203ea140bSSam McCall
2303ea140bSSam McCall using namespace testing;
2403ea140bSSam McCall
2503ea140bSSam McCall namespace clang {
2603ea140bSSam McCall namespace clangd {
2703ea140bSSam McCall namespace {
2803ea140bSSam McCall
2903ea140bSSam McCall // Check the generated header sources contains usual standard library headers.
TEST(StdLibTests,getStdlibUmbrellaHeader)3003ea140bSSam McCall TEST(StdLibTests, getStdlibUmbrellaHeader) {
3103ea140bSSam McCall LangOptions LO;
3203ea140bSSam McCall LO.CPlusPlus = true;
3303ea140bSSam McCall
3403ea140bSSam McCall auto CXX = getStdlibUmbrellaHeader(LO).str();
3503ea140bSSam McCall EXPECT_THAT(CXX, HasSubstr("#include <string>"));
3603ea140bSSam McCall EXPECT_THAT(CXX, HasSubstr("#include <cstdio>"));
37c812ab73SHaojian Wu EXPECT_THAT(CXX, Not(HasSubstr("#include <ios646.h>")));
3803ea140bSSam McCall
3903ea140bSSam McCall LO.CPlusPlus = false;
4003ea140bSSam McCall auto C = getStdlibUmbrellaHeader(LO).str();
4103ea140bSSam McCall EXPECT_THAT(C, Not(HasSubstr("#include <string>")));
4203ea140bSSam McCall EXPECT_THAT(C, Not(HasSubstr("#include <cstdio>")));
4303ea140bSSam McCall EXPECT_THAT(C, HasSubstr("#include <stdio.h>"));
4403ea140bSSam McCall }
4503ea140bSSam McCall
4603ea140bSSam McCall MATCHER_P(Named, Name, "") { return arg.Name == Name; }
4703ea140bSSam McCall
4803ea140bSSam McCall // Build an index, and check if it contains the right symbols.
TEST(StdLibTests,indexStandardLibrary)4903ea140bSSam McCall TEST(StdLibTests, indexStandardLibrary) {
5003ea140bSSam McCall MockFS FS;
5103ea140bSSam McCall FS.Files["std/foo.h"] = R"cpp(
5203ea140bSSam McCall #include <platform_stuff.h>
5303ea140bSSam McCall #if __cplusplus >= 201703L
5403ea140bSSam McCall int foo17();
5503ea140bSSam McCall #elif __cplusplus >= 201402L
5603ea140bSSam McCall int foo14();
5703ea140bSSam McCall #else
5803ea140bSSam McCall bool foo98();
5903ea140bSSam McCall #endif
6003ea140bSSam McCall )cpp";
6103ea140bSSam McCall FS.Files["nonstd/platform_stuff.h"] = "int magic = 42;";
6203ea140bSSam McCall
6303ea140bSSam McCall ParseInputs OriginalInputs;
6403ea140bSSam McCall OriginalInputs.TFS = &FS;
6503ea140bSSam McCall OriginalInputs.CompileCommand.Filename = testPath("main.cc");
6603ea140bSSam McCall OriginalInputs.CompileCommand.CommandLine = {"clang++", testPath("main.cc"),
6703ea140bSSam McCall "-isystemstd/",
6803ea140bSSam McCall "-isystemnonstd/", "-std=c++14"};
6903ea140bSSam McCall OriginalInputs.CompileCommand.Directory = testRoot();
7003ea140bSSam McCall IgnoreDiagnostics Diags;
7103ea140bSSam McCall auto CI = buildCompilerInvocation(OriginalInputs, Diags);
7203ea140bSSam McCall ASSERT_TRUE(CI);
7303ea140bSSam McCall
7403ea140bSSam McCall StdLibLocation Loc;
7503ea140bSSam McCall Loc.Paths.push_back(testPath("std/"));
7603ea140bSSam McCall
7703ea140bSSam McCall auto Symbols =
7803ea140bSSam McCall indexStandardLibrary("#include <foo.h>", std::move(CI), Loc, FS);
7903ea140bSSam McCall EXPECT_THAT(Symbols, ElementsAre(Named("foo14")));
8003ea140bSSam McCall }
8103ea140bSSam McCall
TEST(StdLibTests,StdLibSet)8203ea140bSSam McCall TEST(StdLibTests, StdLibSet) {
8303ea140bSSam McCall StdLibSet Set;
8403ea140bSSam McCall MockFS FS;
8503ea140bSSam McCall FS.Files["std/_"] = "";
8603ea140bSSam McCall FS.Files["libc/_"] = "";
8703ea140bSSam McCall
8803ea140bSSam McCall auto Add = [&](const LangOptions &LO,
8903ea140bSSam McCall std::vector<llvm::StringRef> SearchPath) {
9003ea140bSSam McCall SourceManagerForFile SM("scratch", "");
91649ef338SKazu Hirata SM.get().getFileManager().setVirtualFileSystem(FS.view(std::nullopt));
9203ea140bSSam McCall HeaderSearch HS(/*HSOpts=*/nullptr, SM.get(), SM.get().getDiagnostics(), LO,
9303ea140bSSam McCall /*Target=*/nullptr);
9403ea140bSSam McCall for (auto P : SearchPath)
9503ea140bSSam McCall HS.AddSearchPath(
9603ea140bSSam McCall DirectoryLookup(
9703ea140bSSam McCall cantFail(SM.get().getFileManager().getDirectoryRef(testPath(P))),
9803ea140bSSam McCall SrcMgr::C_System, /*isFramework=*/false),
9903ea140bSSam McCall true);
10003ea140bSSam McCall return Set.add(LO, HS);
10103ea140bSSam McCall };
10203ea140bSSam McCall
10303ea140bSSam McCall Config Cfg;
10403ea140bSSam McCall Cfg.Index.StandardLibrary = false;
10503ea140bSSam McCall WithContextValue Disabled(Config::Key, std::move(Cfg));
10603ea140bSSam McCall
10703ea140bSSam McCall LangOptions LO;
10803ea140bSSam McCall LO.CPlusPlus = true;
10903ea140bSSam McCall EXPECT_FALSE(Add(LO, {"std"})) << "Disabled in config";
11003ea140bSSam McCall
11103ea140bSSam McCall Cfg = Config();
11203ea140bSSam McCall Cfg.Index.StandardLibrary = true;
11303ea140bSSam McCall WithContextValue Enabled(Config::Key, std::move(Cfg));
11403ea140bSSam McCall
11503ea140bSSam McCall EXPECT_FALSE(Add(LO, {"std"})) << "No <vector> found";
11603ea140bSSam McCall FS.Files["std/vector"] = "class vector;";
11703ea140bSSam McCall EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++98";
11803ea140bSSam McCall EXPECT_FALSE(Add(LO, {"std"})) << "Don't reindex";
11903ea140bSSam McCall LO.CPlusPlus11 = true;
12003ea140bSSam McCall EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++11";
12103ea140bSSam McCall LO.CPlusPlus = false;
12203ea140bSSam McCall EXPECT_FALSE(Add(LO, {"libc"})) << "No <stdio.h>";
12303ea140bSSam McCall FS.Files["libc/stdio.h"] = true;
12403ea140bSSam McCall EXPECT_TRUE(Add(LO, {"libc"})) << "Indexing as C";
12503ea140bSSam McCall }
12603ea140bSSam McCall
12703ea140bSSam McCall MATCHER_P(StdlibSymbol, Name, "") {
12803ea140bSSam McCall return arg.Name == Name && arg.Includes.size() == 1 &&
129*d5953e3eSKazu Hirata llvm::StringRef(arg.Includes.front().Header).starts_with("<");
13003ea140bSSam McCall }
13103ea140bSSam McCall
TEST(StdLibTests,EndToEnd)13203ea140bSSam McCall TEST(StdLibTests, EndToEnd) {
13303ea140bSSam McCall Config Cfg;
13403ea140bSSam McCall Cfg.Index.StandardLibrary = true;
13503ea140bSSam McCall WithContextValue Enabled(Config::Key, std::move(Cfg));
13603ea140bSSam McCall
13703ea140bSSam McCall MockFS FS;
13803ea140bSSam McCall FS.Files["stdlib/vector"] =
13903ea140bSSam McCall "namespace std { template <class> class vector; }";
14003ea140bSSam McCall FS.Files["stdlib/list"] =
14103ea140bSSam McCall " namespace std { template <typename T> class list; }";
14203ea140bSSam McCall MockCompilationDatabase CDB;
14303ea140bSSam McCall CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));
14403ea140bSSam McCall ClangdServer::Options Opts = ClangdServer::optsForTest();
14503ea140bSSam McCall Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index
14603ea140bSSam McCall ClangdServer Server(CDB, FS, Opts);
14703ea140bSSam McCall
14803ea140bSSam McCall Annotations A("std::^");
14903ea140bSSam McCall
15003ea140bSSam McCall Server.addDocument(testPath("foo.cc"), A.code());
15103ea140bSSam McCall ASSERT_TRUE(Server.blockUntilIdleForTest());
15203ea140bSSam McCall clangd::CodeCompleteOptions CCOpts;
15303ea140bSSam McCall auto Completions =
15403ea140bSSam McCall cantFail(runCodeComplete(Server, testPath("foo.cc"), A.point(), CCOpts));
15503ea140bSSam McCall EXPECT_THAT(
15603ea140bSSam McCall Completions.Completions,
15703ea140bSSam McCall UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));
15803ea140bSSam McCall }
15903ea140bSSam McCall
16003ea140bSSam McCall } // namespace
16103ea140bSSam McCall } // namespace clangd
16203ea140bSSam McCall } // namespace clang
163