forked from OSchip/llvm-project
163 lines
5.1 KiB
C++
163 lines
5.1 KiB
C++
//===-- StdLibTests.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Annotations.h"
|
|
#include "ClangdServer.h"
|
|
#include "CodeComplete.h"
|
|
#include "Compiler.h"
|
|
#include "Config.h"
|
|
#include "SyncAPI.h"
|
|
#include "TestFS.h"
|
|
#include "index/StdLib.h"
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include <memory>
|
|
|
|
using namespace testing;
|
|
|
|
namespace clang {
|
|
namespace clangd {
|
|
namespace {
|
|
|
|
// Check the generated header sources contains usual standard library headers.
|
|
TEST(StdLibTests, getStdlibUmbrellaHeader) {
|
|
LangOptions LO;
|
|
LO.CPlusPlus = true;
|
|
|
|
auto CXX = getStdlibUmbrellaHeader(LO).str();
|
|
EXPECT_THAT(CXX, HasSubstr("#include <string>"));
|
|
EXPECT_THAT(CXX, HasSubstr("#include <cstdio>"));
|
|
EXPECT_THAT(CXX, Not(HasSubstr("#include <stdio.h>")));
|
|
|
|
LO.CPlusPlus = false;
|
|
auto C = getStdlibUmbrellaHeader(LO).str();
|
|
EXPECT_THAT(C, Not(HasSubstr("#include <string>")));
|
|
EXPECT_THAT(C, Not(HasSubstr("#include <cstdio>")));
|
|
EXPECT_THAT(C, HasSubstr("#include <stdio.h>"));
|
|
}
|
|
|
|
MATCHER_P(Named, Name, "") { return arg.Name == Name; }
|
|
|
|
// Build an index, and check if it contains the right symbols.
|
|
TEST(StdLibTests, indexStandardLibrary) {
|
|
MockFS FS;
|
|
FS.Files["std/foo.h"] = R"cpp(
|
|
#include <platform_stuff.h>
|
|
#if __cplusplus >= 201703L
|
|
int foo17();
|
|
#elif __cplusplus >= 201402L
|
|
int foo14();
|
|
#else
|
|
bool foo98();
|
|
#endif
|
|
)cpp";
|
|
FS.Files["nonstd/platform_stuff.h"] = "int magic = 42;";
|
|
|
|
ParseInputs OriginalInputs;
|
|
OriginalInputs.TFS = &FS;
|
|
OriginalInputs.CompileCommand.Filename = testPath("main.cc");
|
|
OriginalInputs.CompileCommand.CommandLine = {"clang++", testPath("main.cc"),
|
|
"-isystemstd/",
|
|
"-isystemnonstd/", "-std=c++14"};
|
|
OriginalInputs.CompileCommand.Directory = testRoot();
|
|
IgnoreDiagnostics Diags;
|
|
auto CI = buildCompilerInvocation(OriginalInputs, Diags);
|
|
ASSERT_TRUE(CI);
|
|
|
|
StdLibLocation Loc;
|
|
Loc.Paths.push_back(testPath("std/"));
|
|
|
|
auto Symbols =
|
|
indexStandardLibrary("#include <foo.h>", std::move(CI), Loc, FS);
|
|
EXPECT_THAT(Symbols, ElementsAre(Named("foo14")));
|
|
}
|
|
|
|
TEST(StdLibTests, StdLibSet) {
|
|
StdLibSet Set;
|
|
MockFS FS;
|
|
FS.Files["std/_"] = "";
|
|
FS.Files["libc/_"] = "";
|
|
|
|
auto Add = [&](const LangOptions &LO,
|
|
std::vector<llvm::StringRef> SearchPath) {
|
|
SourceManagerForFile SM("scratch", "");
|
|
SM.get().getFileManager().setVirtualFileSystem(FS.view(llvm::None));
|
|
HeaderSearch HS(/*HSOpts=*/nullptr, SM.get(), SM.get().getDiagnostics(), LO,
|
|
/*Target=*/nullptr);
|
|
for (auto P : SearchPath)
|
|
HS.AddSearchPath(
|
|
DirectoryLookup(
|
|
cantFail(SM.get().getFileManager().getDirectoryRef(testPath(P))),
|
|
SrcMgr::C_System, /*isFramework=*/false),
|
|
true);
|
|
return Set.add(LO, HS);
|
|
};
|
|
|
|
Config Cfg;
|
|
Cfg.Index.StandardLibrary = false;
|
|
WithContextValue Disabled(Config::Key, std::move(Cfg));
|
|
|
|
LangOptions LO;
|
|
LO.CPlusPlus = true;
|
|
EXPECT_FALSE(Add(LO, {"std"})) << "Disabled in config";
|
|
|
|
Cfg = Config();
|
|
Cfg.Index.StandardLibrary = true;
|
|
WithContextValue Enabled(Config::Key, std::move(Cfg));
|
|
|
|
EXPECT_FALSE(Add(LO, {"std"})) << "No <vector> found";
|
|
FS.Files["std/vector"] = "class vector;";
|
|
EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++98";
|
|
EXPECT_FALSE(Add(LO, {"std"})) << "Don't reindex";
|
|
LO.CPlusPlus11 = true;
|
|
EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++11";
|
|
LO.CPlusPlus = false;
|
|
EXPECT_FALSE(Add(LO, {"libc"})) << "No <stdio.h>";
|
|
FS.Files["libc/stdio.h"] = true;
|
|
EXPECT_TRUE(Add(LO, {"libc"})) << "Indexing as C";
|
|
}
|
|
|
|
MATCHER_P(StdlibSymbol, Name, "") {
|
|
return arg.Name == Name && arg.Includes.size() == 1 &&
|
|
llvm::StringRef(arg.Includes.front().Header).startswith("<");
|
|
}
|
|
|
|
TEST(StdLibTests, EndToEnd) {
|
|
Config Cfg;
|
|
Cfg.Index.StandardLibrary = true;
|
|
WithContextValue Enabled(Config::Key, std::move(Cfg));
|
|
|
|
MockFS FS;
|
|
FS.Files["stdlib/vector"] =
|
|
"namespace std { template <class> class vector; }";
|
|
FS.Files["stdlib/list"] =
|
|
" namespace std { template <typename T> class list; }";
|
|
MockCompilationDatabase CDB;
|
|
CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));
|
|
ClangdServer::Options Opts = ClangdServer::optsForTest();
|
|
Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index
|
|
ClangdServer Server(CDB, FS, Opts);
|
|
|
|
Annotations A("std::^");
|
|
|
|
Server.addDocument(testPath("foo.cc"), A.code());
|
|
ASSERT_TRUE(Server.blockUntilIdleForTest());
|
|
clangd::CodeCompleteOptions CCOpts;
|
|
auto Completions =
|
|
cantFail(runCodeComplete(Server, testPath("foo.cc"), A.point(), CCOpts));
|
|
EXPECT_THAT(
|
|
Completions.Completions,
|
|
UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace clangd
|
|
} // namespace clang
|