1 //===-- StdLibTests.cpp -----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "Annotations.h"
10 #include "ClangdServer.h"
11 #include "CodeComplete.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"
23 using namespace testing
;
29 // Check the generated header sources contains usual standard library headers.
30 TEST(StdLibTests
, getStdlibUmbrellaHeader
) {
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>")));
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>"));
46 MATCHER_P(Named
, Name
, "") { return arg
.Name
== Name
; }
48 // Build an index, and check if it contains the right symbols.
49 TEST(StdLibTests
, indexStandardLibrary
) {
51 FS
.Files
["std/foo.h"] = R
"cpp(
52 #include <platform_stuff.h>
53 #if __cplusplus >= 201703L
55 #elif __cplusplus >= 201402L
61 FS
.Files
["nonstd/platform_stuff.h"] = "int magic = 42;";
63 ParseInputs OriginalInputs
;
64 OriginalInputs
.TFS
= &FS
;
65 OriginalInputs
.CompileCommand
.Filename
= testPath("main.cc");
66 OriginalInputs
.CompileCommand
.CommandLine
= {"clang++", testPath("main.cc"),
68 "-isystemnonstd/", "-std=c++14"};
69 OriginalInputs
.CompileCommand
.Directory
= testRoot();
70 IgnoreDiagnostics Diags
;
71 auto CI
= buildCompilerInvocation(OriginalInputs
, Diags
);
75 Loc
.Paths
.push_back(testPath("std/"));
78 indexStandardLibrary("#include <foo.h>", std::move(CI
), Loc
, FS
);
79 EXPECT_THAT(Symbols
, ElementsAre(Named("foo14")));
82 TEST(StdLibTests
, StdLibSet
) {
85 FS
.Files
["std/_"] = "";
86 FS
.Files
["libc/_"] = "";
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
,
94 for (auto P
: SearchPath
)
97 cantFail(SM
.get().getFileManager().getDirectoryRef(testPath(P
))),
98 SrcMgr::C_System
, /*isFramework=*/false),
100 return Set
.add(LO
, HS
);
104 Cfg
.Index
.StandardLibrary
= false;
105 WithContextValue
Disabled(Config::Key
, std::move(Cfg
));
109 EXPECT_FALSE(Add(LO
, {"std"})) << "Disabled in config";
112 Cfg
.Index
.StandardLibrary
= true;
113 WithContextValue
Enabled(Config::Key
, std::move(Cfg
));
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";
127 MATCHER_P(StdlibSymbol
, Name
, "") {
128 return arg
.Name
== Name
&& arg
.Includes
.size() == 1 &&
129 llvm::StringRef(arg
.Includes
.front().Header
).startswith("<");
132 TEST(StdLibTests
, EndToEnd
) {
134 Cfg
.Index
.StandardLibrary
= true;
135 WithContextValue
Enabled(Config::Key
, std::move(Cfg
));
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
);
148 Annotations
A("std::^");
150 Server
.addDocument(testPath("foo.cc"), A
.code());
151 ASSERT_TRUE(Server
.blockUntilIdleForTest());
152 clangd::CodeCompleteOptions CCOpts
;
154 cantFail(runCodeComplete(Server
, testPath("foo.cc"), A
.point(), CCOpts
));
156 Completions
.Completions
,
157 UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));
161 } // namespace clangd