clang-tools 19.0.0git
StdLibTests.cpp
Go to the documentation of this file.
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) {
31 LangOptions LO;
32 LO.CPlusPlus = true;
33
34 auto CXX = getStdlibUmbrellaHeader(LO).str();
35 EXPECT_THAT(CXX, HasSubstr("#include <string>"));
36 EXPECT_THAT(CXX, HasSubstr("#include <cstdio>"));
37 EXPECT_THAT(CXX, Not(HasSubstr("#include <ios646.h>")));
38
39 LO.CPlusPlus = false;
40 auto C = getStdlibUmbrellaHeader(LO).str();
41 EXPECT_THAT(C, Not(HasSubstr("#include <string>")));
42 EXPECT_THAT(C, Not(HasSubstr("#include <cstdio>")));
43 EXPECT_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) {
50 MockFS FS;
51 FS.Files["std/foo.h"] = R"cpp(
52 #include <platform_stuff.h>
53 #if __cplusplus >= 201703L
54 int foo17();
55 #elif __cplusplus >= 201402L
56 int foo14();
57 #else
58 bool foo98();
59 #endif
60 )cpp";
61 FS.Files["nonstd/platform_stuff.h"] = "int magic = 42;";
62
63 ParseInputs OriginalInputs;
64 OriginalInputs.TFS = &FS;
65 OriginalInputs.CompileCommand.Filename = testPath("main.cc");
66 OriginalInputs.CompileCommand.CommandLine = {"clang++", testPath("main.cc"),
67 "-isystemstd/",
68 "-isystemnonstd/", "-std=c++14"};
69 OriginalInputs.CompileCommand.Directory = testRoot();
70 IgnoreDiagnostics Diags;
71 auto CI = buildCompilerInvocation(OriginalInputs, Diags);
72 ASSERT_TRUE(CI);
73
74 StdLibLocation Loc;
75 Loc.Paths.push_back(testPath("std/"));
76
77 auto Symbols =
78 indexStandardLibrary("#include <foo.h>", std::move(CI), Loc, FS);
79 EXPECT_THAT(Symbols, ElementsAre(Named("foo14")));
80}
81
82TEST(StdLibTests, StdLibSet) {
83 StdLibSet Set;
84 MockFS FS;
85 FS.Files["std/_"] = "";
86 FS.Files["libc/_"] = "";
87
88 auto Add = [&](const LangOptions &LO,
89 std::vector<llvm::StringRef> SearchPath) {
90 SourceManagerForFile SM("scratch", "");
91 SM.get().getFileManager().setVirtualFileSystem(FS.view(std::nullopt));
92 HeaderSearch HS(/*HSOpts=*/nullptr, SM.get(), SM.get().getDiagnostics(), LO,
93 /*Target=*/nullptr);
94 for (auto P : SearchPath)
95 HS.AddSearchPath(
96 DirectoryLookup(
97 cantFail(SM.get().getFileManager().getDirectoryRef(testPath(P))),
98 SrcMgr::C_System, /*isFramework=*/false),
99 true);
100 return Set.add(LO, HS);
101 };
102
103 Config Cfg;
104 Cfg.Index.StandardLibrary = false;
105 WithContextValue Disabled(Config::Key, std::move(Cfg));
106
107 LangOptions LO;
108 LO.CPlusPlus = true;
109 EXPECT_FALSE(Add(LO, {"std"})) << "Disabled in config";
110
111 Cfg = Config();
112 Cfg.Index.StandardLibrary = true;
113 WithContextValue Enabled(Config::Key, std::move(Cfg));
114
115 EXPECT_FALSE(Add(LO, {"std"})) << "No <vector> found";
116 FS.Files["std/vector"] = "class vector;";
117 EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++98";
118 EXPECT_FALSE(Add(LO, {"std"})) << "Don't reindex";
119 LO.CPlusPlus11 = true;
120 EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++11";
121 LO.CPlusPlus = false;
122 EXPECT_FALSE(Add(LO, {"libc"})) << "No <stdio.h>";
123 FS.Files["libc/stdio.h"] = true;
124 EXPECT_TRUE(Add(LO, {"libc"})) << "Indexing as C";
125}
126
127MATCHER_P(StdlibSymbol, Name, "") {
128 return arg.Name == Name && arg.Includes.size() == 1 &&
129 llvm::StringRef(arg.Includes.front().Header).starts_with("<");
130}
131
132TEST(StdLibTests, EndToEnd) {
133 Config Cfg;
134 Cfg.Index.StandardLibrary = true;
135 WithContextValue Enabled(Config::Key, std::move(Cfg));
136
137 MockFS FS;
138 FS.Files["stdlib/vector"] =
139 "namespace std { template <class> class vector; }";
140 FS.Files["stdlib/list"] =
141 " namespace std { template <typename T> class list; }";
142 MockCompilationDatabase CDB;
143 CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));
144 ClangdServer::Options Opts = ClangdServer::optsForTest();
145 Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index
146 ClangdServer Server(CDB, FS, Opts);
147
148 Annotations A("std::^");
149
150 Server.addDocument(testPath("foo.cc"), A.code());
151 ASSERT_TRUE(Server.blockUntilIdleForTest());
152 clangd::CodeCompleteOptions CCOpts;
153 auto Completions =
154 cantFail(runCodeComplete(Server, testPath("foo.cc"), A.point(), CCOpts));
155 EXPECT_THAT(
156 Completions.Completions,
157 UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));
158}
159
160} // namespace
161} // namespace clangd
162} // namespace clang
llvm::SmallString< 256U > Name
const Criteria C
SourceLocation Loc
const bool Enabled
Whether the heuristic is to be enabled by default.
std::unique_ptr< CompilerInvocation > CI
static Options optsForTest()
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
Definition: ThreadsafeFS.h:32
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
Definition: Compiler.cpp:95
llvm::Expected< CodeCompleteResult > runCodeComplete(ClangdServer &Server, PathRef File, Position Pos, clangd::CodeCompleteOptions Opts)
Definition: SyncAPI.cpp:72
MATCHER_P(named, N, "")
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:93
TEST(BackgroundQueueTest, Priority)
llvm::StringRef getStdlibUmbrellaHeader(const LangOptions &LO)
Definition: StdLib.cpp:96
const char * testRoot()
Definition: TestFS.cpp:85
SymbolSlab indexStandardLibrary(llvm::StringRef HeaderSources, std::unique_ptr< CompilerInvocation > CI, const StdLibLocation &Loc, const ThreadsafeFS &TFS)
Definition: StdLib.cpp:198
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition: Config.h:48
struct clang::clangd::Config::@3 Index
Controls index behavior.