xref: /llvm-project/clang-tools-extra/clangd/unittests/StdLibTests.cpp (revision d5953e3e3092f7142a07aa012fc9665ede09e53b)
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