clang-tools 22.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/Index.h"
17#include "index/StdLib.h"
18#include "clang/Basic/LangOptions.h"
19#include "clang/Basic/SourceManager.h"
20#include "llvm/Testing/Support/Error.h"
21#include "gmock/gmock.h"
22#include "gtest/gtest.h"
23#include <memory>
24
25using namespace testing;
26
27namespace clang {
28namespace clangd {
29namespace {
30
31// Check the generated header sources contains usual standard library headers.
32TEST(StdLibTests, getStdlibUmbrellaHeader) {
33 LangOptions LO;
34 LO.CPlusPlus = true;
35
36 auto CXX = getStdlibUmbrellaHeader(LO).str();
37 EXPECT_THAT(CXX, HasSubstr("#include <string>"));
38 EXPECT_THAT(CXX, HasSubstr("#include <cstdio>"));
39 EXPECT_THAT(CXX, Not(HasSubstr("#include <ios646.h>")));
40
41 LO.CPlusPlus = false;
42 auto C = getStdlibUmbrellaHeader(LO).str();
43 EXPECT_THAT(C, Not(HasSubstr("#include <string>")));
44 EXPECT_THAT(C, Not(HasSubstr("#include <cstdio>")));
45 EXPECT_THAT(C, HasSubstr("#include <stdio.h>"));
46}
47
48MATCHER_P(Named, Name, "") { return arg.Name == Name; }
49
50// Build an index, and check if it contains the right symbols.
51TEST(StdLibTests, indexStandardLibrary) {
52 MockFS FS;
53 FS.Files["std/foo.h"] = R"cpp(
54 #include <platform_stuff.h>
55 #if __cplusplus >= 201703L
56 int foo17();
57 #elif __cplusplus >= 201402L
58 int foo14();
59 #else
60 bool foo98();
61 #endif
62 )cpp";
63 FS.Files["nonstd/platform_stuff.h"] = "int magic = 42;";
64
65 ParseInputs OriginalInputs;
66 OriginalInputs.TFS = &FS;
67 OriginalInputs.CompileCommand.Filename = testPath("main.cc");
68 OriginalInputs.CompileCommand.CommandLine = {"clang++", testPath("main.cc"),
69 "-isystemstd/",
70 "-isystemnonstd/", "-std=c++14"};
71 OriginalInputs.CompileCommand.Directory = testRoot();
73 auto CI = buildCompilerInvocation(OriginalInputs, Diags);
74 ASSERT_TRUE(CI);
75
77 Loc.Paths.push_back(testPath("std/"));
78
79 auto Symbols =
80 indexStandardLibrary("#include <foo.h>", std::move(CI), Loc, FS);
81 EXPECT_THAT(Symbols, ElementsAre(Named("foo14")));
82}
83
84TEST(StdLibTests, StdLibSet) {
85 StdLibSet Set;
86 MockFS FS;
87 FS.Files["std/_"] = "";
88 FS.Files["libc/_"] = "";
89
90 HeaderSearchOptions HSOpts;
91 auto Add = [&](const LangOptions &LO,
92 std::vector<llvm::StringRef> SearchPath) {
93 SourceManagerForFile SM("scratch", "");
94 SM.get().getFileManager().setVirtualFileSystem(FS.view(std::nullopt));
95 HeaderSearch HS(HSOpts, SM.get(), SM.get().getDiagnostics(), LO,
96 /*Target=*/nullptr);
97 for (auto P : SearchPath)
98 HS.AddSearchPath(
99 DirectoryLookup(
100 cantFail(SM.get().getFileManager().getDirectoryRef(testPath(P))),
101 SrcMgr::C_System, /*isFramework=*/false),
102 true);
103 return Set.add(LO, HS);
104 };
105
106 Config Cfg;
107 Cfg.Index.StandardLibrary = false;
108 WithContextValue Disabled(Config::Key, std::move(Cfg));
109
110 LangOptions LO;
111 LO.CPlusPlus = true;
112 EXPECT_FALSE(Add(LO, {"std"})) << "Disabled in config";
113
114 Cfg = Config();
115 Cfg.Index.StandardLibrary = true;
116 WithContextValue Enabled(Config::Key, std::move(Cfg));
117
118 EXPECT_FALSE(Add(LO, {"std"})) << "No <vector> found";
119 FS.Files["std/vector"] = "class vector;";
120 EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++98";
121 EXPECT_FALSE(Add(LO, {"std"})) << "Don't reindex";
122 LO.CPlusPlus11 = true;
123 EXPECT_TRUE(Add(LO, {"std"})) << "Indexing as C++11";
124 LO.CPlusPlus = false;
125 EXPECT_FALSE(Add(LO, {"libc"})) << "No <stdio.h>";
126 FS.Files["libc/stdio.h"] = true;
127 EXPECT_TRUE(Add(LO, {"libc"})) << "Indexing as C";
128}
129
130MATCHER_P(StdlibSymbol, Name, "") {
131 return arg.Name == Name && arg.Includes.size() == 1 &&
132 llvm::StringRef(arg.Includes.front().Header).starts_with("<");
133}
134
135TEST(StdLibTests, EndToEnd) {
136 Config Cfg;
137 Cfg.Index.StandardLibrary = true;
138 WithContextValue Enabled(Config::Key, std::move(Cfg));
139
140 MockFS FS;
141 FS.Files["stdlib/vector"] =
142 "namespace std { template <class> class vector; }";
143 FS.Files["stdlib/list"] =
144 " namespace std { template <typename T> class list; }";
146 CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));
148 Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index
149 ClangdServer Server(CDB, FS, Opts);
150
151 Annotations A("std::^");
152
153 Server.addDocument(testPath("foo.cc"), A.code());
154 ASSERT_TRUE(Server.blockUntilIdleForTest());
155 clangd::CodeCompleteOptions CCOpts;
156 auto Completions =
157 cantFail(runCodeComplete(Server, testPath("foo.cc"), A.point(), CCOpts));
158 EXPECT_THAT(
159 Completions.Completions,
160 UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));
161}
162
163TEST(StdLibTests, StdLibDocComments) {
164 Config Cfg;
165 Cfg.Index.StandardLibrary = true;
166 WithContextValue Enabled(Config::Key, std::move(Cfg));
167
168 MockFS FS;
169 FS.Files["stdlib/vector"] = R"cpp(
170 namespace std {
171 struct vector {
172 /**doc comment*/
173 struct inner {};
174 };
175 }
176 )cpp";
178 CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));
180 Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index
181 ClangdServer Server(CDB, FS, Opts);
182
183 // Open an empty file. <vector> will not be part of the preamble index,
184 // but it will be part of the stdlib index.
185 Server.addDocument(testPath("foo.cc"), "");
186
187 // Wait for the stdlib index to be built.
188 ASSERT_TRUE(Server.blockUntilIdleForTest());
189
190 // Check that the index contains the doc comment.
191 SymbolSlab Result;
192 EXPECT_THAT_ERROR(runCustomAction(Server, testPath("foo.cc"),
193 [&](InputsAndAST Inputs) {
195 Req.Query = "inner";
196 Req.Scopes = {"std::vector::"};
197 SymbolSlab::Builder Builder;
198 Inputs.Inputs.Index->fuzzyFind(
199 Req, [&](const Symbol &Sym) {
200 Builder.insert(Sym);
201 });
202 Result = std::move(Builder).build();
203 }),
204 llvm::Succeeded());
205 ASSERT_EQ(Result.size(), 1u);
206 EXPECT_EQ(Result.begin()->Documentation, "doc comment");
207}
208
209} // namespace
210} // namespace clangd
211} // namespace clang
static cl::opt< std::string > Config("config", desc(R"( Specifies a configuration in YAML/JSON format: -config="{Checks:' *', CheckOptions:{x:y}}" When the value is empty, clang-tidy will attempt to find a file named .clang-tidy for each source file in its parent directories. )"), cl::init(""), cl::cat(ClangTidyCategory))
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Definition Annotations.h:23
Manages a collection of source files and derived data (ASTs, indexes), and provides language-aware fe...
std::vector< std::string > ExtraClangFlags
Definition TestFS.h:68
llvm::StringMap< std::string > Files
Definition TestFS.h:45
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
Definition Symbol.h:224
SymbolSlab build() &&
Consumes the builder to finalize the slab.
Definition Symbol.cpp:56
An immutable symbol container that stores a set of symbols.
Definition Symbol.h:201
WithContextValue extends Context::current() with a single value.
Definition Context.h:200
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
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:98
llvm::Error runCustomAction(ClangdServer &Server, PathRef File, llvm::function_ref< void(InputsAndAST)> Action)
Definition SyncAPI.cpp:162
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:200
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
Definition Config.h:44
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
Definition Config.h:48
struct clang::clangd::Config::@072252370142323110175010006107105013140064217165 Index
Controls index behavior.
std::string Query
A query string for the fuzzy find.
Definition Index.h:29
Information required to run clang, e.g. to parse AST or do code completion.
Definition Compiler.h:49
const ThreadsafeFS * TFS
Definition Compiler.h:51
llvm::SmallVector< std::string > Paths
Definition StdLib.h:46
The class presents a C++ symbol, e.g.
Definition Symbol.h:39