llvm-project
162 строки · 5.1 Кб
1//===-- StdLibTests.cpp -----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Annotations.h"10#include "ClangdServer.h"11#include "CodeComplete.h"12#include "Compiler.h"13#include "Config.h"14#include "SyncAPI.h"15#include "TestFS.h"16#include "index/StdLib.h"17#include "clang/Basic/LangOptions.h"18#include "clang/Basic/SourceManager.h"19#include "gmock/gmock.h"20#include "gtest/gtest.h"21#include <memory>22
23using namespace testing;24
25namespace clang {26namespace clangd {27namespace {28
29// Check the generated header sources contains usual standard library headers.
30TEST(StdLibTests, getStdlibUmbrellaHeader) {31LangOptions LO;32LO.CPlusPlus = true;33
34auto CXX = getStdlibUmbrellaHeader(LO).str();35EXPECT_THAT(CXX, HasSubstr("#include <string>"));36EXPECT_THAT(CXX, HasSubstr("#include <cstdio>"));37EXPECT_THAT(CXX, Not(HasSubstr("#include <ios646.h>")));38
39LO.CPlusPlus = false;40auto C = getStdlibUmbrellaHeader(LO).str();41EXPECT_THAT(C, Not(HasSubstr("#include <string>")));42EXPECT_THAT(C, Not(HasSubstr("#include <cstdio>")));43EXPECT_THAT(C, HasSubstr("#include <stdio.h>"));44}
45
46MATCHER_P(Named, Name, "") { return arg.Name == Name; }47
48// Build an index, and check if it contains the right symbols.
49TEST(StdLibTests, indexStandardLibrary) {50MockFS FS;51FS.Files["std/foo.h"] = R"cpp(52#include <platform_stuff.h>
53#if __cplusplus >= 201703L
54int foo17();
55#elif __cplusplus >= 201402L
56int foo14();
57#else
58bool foo98();
59#endif
60)cpp";61FS.Files["nonstd/platform_stuff.h"] = "int magic = 42;";62
63ParseInputs OriginalInputs;64OriginalInputs.TFS = &FS;65OriginalInputs.CompileCommand.Filename = testPath("main.cc");66OriginalInputs.CompileCommand.CommandLine = {"clang++", testPath("main.cc"),67"-isystemstd/",68"-isystemnonstd/", "-std=c++14"};69OriginalInputs.CompileCommand.Directory = testRoot();70IgnoreDiagnostics Diags;71auto CI = buildCompilerInvocation(OriginalInputs, Diags);72ASSERT_TRUE(CI);73
74StdLibLocation Loc;75Loc.Paths.push_back(testPath("std/"));76
77auto Symbols =78indexStandardLibrary("#include <foo.h>", std::move(CI), Loc, FS);79EXPECT_THAT(Symbols, ElementsAre(Named("foo14")));80}
81
82TEST(StdLibTests, StdLibSet) {83StdLibSet Set;84MockFS FS;85FS.Files["std/_"] = "";86FS.Files["libc/_"] = "";87
88auto Add = [&](const LangOptions &LO,89std::vector<llvm::StringRef> SearchPath) {90SourceManagerForFile SM("scratch", "");91SM.get().getFileManager().setVirtualFileSystem(FS.view(std::nullopt));92HeaderSearch HS(/*HSOpts=*/nullptr, SM.get(), SM.get().getDiagnostics(), LO,93/*Target=*/nullptr);94for (auto P : SearchPath)95HS.AddSearchPath(96DirectoryLookup(97cantFail(SM.get().getFileManager().getDirectoryRef(testPath(P))),98SrcMgr::C_System, /*isFramework=*/false),99true);100return Set.add(LO, HS);101};102
103Config Cfg;104Cfg.Index.StandardLibrary = false;105WithContextValue Disabled(Config::Key, std::move(Cfg));106
107LangOptions LO;108LO.CPlusPlus = true;109EXPECT_FALSE(Add(LO, {"std"})) << "Disabled in config";110
111Cfg = Config();112Cfg.Index.StandardLibrary = true;113WithContextValue Enabled(Config::Key, std::move(Cfg));114
115EXPECT_FALSE(Add(LO, {"std"})) << "No <vector> found";116FS.Files["std/vector"] = "class vector;";117EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++98";118EXPECT_FALSE(Add(LO, {"std"})) << "Don't reindex";119LO.CPlusPlus11 = true;120EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++11";121LO.CPlusPlus = false;122EXPECT_FALSE(Add(LO, {"libc"})) << "No <stdio.h>";123FS.Files["libc/stdio.h"] = true;124EXPECT_TRUE(Add(LO, {"libc"})) << "Indexing as C";125}
126
127MATCHER_P(StdlibSymbol, Name, "") {128return arg.Name == Name && arg.Includes.size() == 1 &&129llvm::StringRef(arg.Includes.front().Header).starts_with("<");130}
131
132TEST(StdLibTests, EndToEnd) {133Config Cfg;134Cfg.Index.StandardLibrary = true;135WithContextValue Enabled(Config::Key, std::move(Cfg));136
137MockFS FS;138FS.Files["stdlib/vector"] =139"namespace std { template <class> class vector; }";140FS.Files["stdlib/list"] =141" namespace std { template <typename T> class list; }";142MockCompilationDatabase CDB;143CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));144ClangdServer::Options Opts = ClangdServer::optsForTest();145Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index146ClangdServer Server(CDB, FS, Opts);147
148Annotations A("std::^");149
150Server.addDocument(testPath("foo.cc"), A.code());151ASSERT_TRUE(Server.blockUntilIdleForTest());152clangd::CodeCompleteOptions CCOpts;153auto Completions =154cantFail(runCodeComplete(Server, testPath("foo.cc"), A.point(), CCOpts));155EXPECT_THAT(156Completions.Completions,157UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));158}
159
160} // namespace161} // namespace clangd162} // namespace clang163