13 #include "gmock/gmock.h" 14 #include "gtest/gtest.h" 21 using ::testing::AllOf;
22 using ::testing::AnyOf;
23 using ::testing::ElementsAre;
24 using ::testing::ElementsAreArray;
25 using ::testing::Field;
26 using ::testing::IsEmpty;
27 using ::testing::UnorderedElementsAre;
29 class IgnoreDiagnostics :
public DiagnosticsConsumer {
31 std::vector<Diag> Diagnostics)
override {}
36 if (arg.containerName.empty())
37 return arg.name ==
Name;
38 return (arg.containerName +
"::" + arg.name) ==
Name;
40 MATCHER_P(WithName, N,
"") {
return arg.name == N; }
46 template <
class... ChildMatchers>
47 ::testing::Matcher<DocumentSymbol>
Children(ChildMatchers... ChildrenM) {
51 ClangdServer::Options optsForTests() {
53 ServerOpts.WorkspaceRoot =
testRoot();
54 ServerOpts.BuildDynamicSymbolIndex =
true;
58 class WorkspaceSymbolsTest :
public ::testing::Test {
60 WorkspaceSymbolsTest()
64 CDB.ExtraClangFlags = {
"-xc++"};
69 MockCompilationDatabase
CDB;
74 std::vector<SymbolInformation> getSymbols(llvm::StringRef Query) {
75 EXPECT_TRUE(Server.blockUntilIdleForTest()) <<
"Waiting for preamble";
77 EXPECT_TRUE(
bool(SymbolInfos)) <<
"workspaceSymbols returned an error";
84 Server.addDocument(
Path, Contents);
91 addFile(
"foo.cpp", R
"cpp( 98 EXPECT_THAT(getSymbols(
"macro"),
103 addFile(
"foo.cpp", R
"cpp( 104 void test(int FirstParam, int SecondParam) { 105 struct LocalClass {}; 108 EXPECT_THAT(getSymbols("l"), IsEmpty());
109 EXPECT_THAT(getSymbols(
"p"), IsEmpty());
113 addFile(
"foo.h", R
"cpp( 118 struct GlobalStruct {};)cpp"); 119 addFile("foo.cpp", R
"cpp( 122 EXPECT_THAT(getSymbols("global"),
123 UnorderedElementsAre(
130 addFile(
"foo.h", R
"cpp( 133 } UnnamedStruct;)cpp"); 134 addFile("foo.cpp", R
"cpp( 137 EXPECT_THAT(getSymbols("UnnamedStruct"),
138 ElementsAre(AllOf(
QName(
"UnnamedStruct"),
140 EXPECT_THAT(getSymbols(
"InUnnamed"),
141 ElementsAre(AllOf(
QName(
"(anonymous struct)::InUnnamed"),
145 TEST_F(WorkspaceSymbolsTest, InMainFile) {
146 addFile(
"foo.cpp", R
"cpp( 150 EXPECT_THAT(getSymbols("test"), ElementsAre(
QName(
"test"),
QName(
"test2")));
153 TEST_F(WorkspaceSymbolsTest, Namespaces) {
154 addFile(
"foo.h", R
"cpp( 162 addFile("foo.cpp", R
"cpp( 165 EXPECT_THAT(getSymbols("a"),
166 UnorderedElementsAre(
QName(
"ans1"),
QName(
"ans1::ai1"),
168 QName(
"ans1::ans2::ai2")));
169 EXPECT_THAT(getSymbols(
"::"), ElementsAre(
QName(
"ans1")));
170 EXPECT_THAT(getSymbols(
"::a"), ElementsAre(
QName(
"ans1")));
171 EXPECT_THAT(getSymbols(
"ans1::"),
172 UnorderedElementsAre(
QName(
"ans1::ai1"),
QName(
"ans1::ans2")));
173 EXPECT_THAT(getSymbols(
"::ans1"), ElementsAre(
QName(
"ans1")));
174 EXPECT_THAT(getSymbols(
"::ans1::"),
175 UnorderedElementsAre(
QName(
"ans1::ai1"),
QName(
"ans1::ans2")));
176 EXPECT_THAT(getSymbols(
"::ans1::ans2"), ElementsAre(
QName(
"ans1::ans2")));
177 EXPECT_THAT(getSymbols(
"::ans1::ans2::"),
178 ElementsAre(
QName(
"ans1::ans2::ai2")));
181 TEST_F(WorkspaceSymbolsTest, AnonymousNamespace) {
182 addFile(
"foo.h", R
"cpp( 187 addFile("foo.cpp", R
"cpp( 190 EXPECT_THAT(getSymbols("test"), ElementsAre(
QName(
"test")));
193 TEST_F(WorkspaceSymbolsTest, MultiFile) {
194 addFile(
"foo.h", R
"cpp( 198 addFile("foo2.h", R
"cpp( 202 addFile("foo.cpp", R
"cpp( 206 EXPECT_THAT(getSymbols("foo"),
207 UnorderedElementsAre(
QName(
"foo"),
QName(
"foo2")));
210 TEST_F(WorkspaceSymbolsTest, GlobalNamespaceQueries) {
211 addFile(
"foo.h", R
"cpp( 222 addFile("foo.cpp", R
"cpp( 225 EXPECT_THAT(getSymbols("::"),
226 UnorderedElementsAre(
230 EXPECT_THAT(getSymbols(
":"), IsEmpty());
231 EXPECT_THAT(getSymbols(
""), IsEmpty());
235 addFile(
"foo.h", R
"cpp( 257 addFile("foo.cpp", R
"cpp( 260 EXPECT_THAT(getSymbols("Red"), ElementsAre(
QName(
"Red")));
261 EXPECT_THAT(getSymbols(
"::Red"), ElementsAre(
QName(
"Red")));
262 EXPECT_THAT(getSymbols(
"Green"), ElementsAre(
QName(
"Green")));
263 EXPECT_THAT(getSymbols(
"Green"), ElementsAre(
QName(
"Green")));
264 EXPECT_THAT(getSymbols(
"Color2::Yellow"),
265 ElementsAre(
QName(
"Color2::Yellow")));
266 EXPECT_THAT(getSymbols(
"Yellow"), ElementsAre(
QName(
"Color2::Yellow")));
268 EXPECT_THAT(getSymbols(
"ns::Black"), ElementsAre(
QName(
"ns::Black")));
269 EXPECT_THAT(getSymbols(
"ns::Blue"), ElementsAre(
QName(
"ns::Blue")));
270 EXPECT_THAT(getSymbols(
"ns::Color4::White"),
271 ElementsAre(
QName(
"ns::Color4::White")));
275 addFile(
"foo.h", R
"cpp( 279 addFile("foo.cpp", R
"cpp( 282 EXPECT_THAT(getSymbols("::"), ElementsAre(
QName(
"func"),
QName(
"ns")));
285 TEST_F(WorkspaceSymbolsTest, WithLimit) {
286 addFile(
"foo.h", R
"cpp( 290 addFile("foo.cpp", R
"cpp( 294 EXPECT_THAT(getSymbols(
"foo"),
295 UnorderedElementsAre(
300 EXPECT_THAT(getSymbols(
"foo"), ElementsAre(
QName(
"foo")));
303 TEST_F(WorkspaceSymbolsTest, TempSpecs) {
304 addFile(
"foo.h", R
"cpp( 305 template <typename T, typename U, int X = 5> class Foo {}; 306 template <typename T> class Foo<int, T> {}; 307 template <> class Foo<bool, int> {}; 308 template <> class Foo<bool, int, 3> {}; 313 UnorderedElementsAre(
321 class DocumentSymbolsTest :
public ::testing::Test {
323 DocumentSymbolsTest()
332 std::vector<DocumentSymbol> getSymbols(
PathRef File) {
335 EXPECT_TRUE(
bool(SymbolInfos)) <<
"documentSymbols returned an error";
339 void addFile(llvm::StringRef FilePath, llvm::StringRef
Contents) {
346 TEST_F(DocumentSymbolsTest, BasicSymbols) {
347 std::string FilePath =
testPath(
"foo.cpp");
356 Foo& operator=(const Foo&); 367 static const int KInt = 2; 368 const char* kStr = "123"; 375 using int32_t = int32; 391 addFile(FilePath, Main.code()); 393 getSymbols(FilePath), 403 AllOf(WithName(
"operator="),
434 TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
435 std::string FilePath =
testPath(
"foo.cpp");
440 void Foo::$def[[f]]() { 444 addFile(FilePath, Main.code()); 445 EXPECT_THAT(getSymbols(FilePath), 449 SymNameRange(Main.
range(
"decl"))))),
451 SymNameRange(Main.
range(
"def")))));
454 TEST_F(DocumentSymbolsTest, ExternSymbol) {
455 std::string FilePath =
testPath(
"foo.cpp");
459 addFile(FilePath, R"cpp( 463 EXPECT_THAT(getSymbols(FilePath), IsEmpty()); 467 std::string FilePath = testPath("foo.cpp");
470 void test(int FirstParam, int SecondParam) { 471 struct LocalClass {}; 474 EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test")));
478 std::string FilePath =
testPath(
"foo.h");
486 getSymbols(FilePath), 489 Children(AllOf(WithName(
"InUnnamed"),
495 TEST_F(DocumentSymbolsTest, InHeaderFile) {
500 std::string FilePath = testPath("foo.h");
501 addFile(FilePath, R
"cpp( 509 EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test")));
513 std::string FilePath =
testPath(
"foo.cpp");
514 addFile(FilePath, R
"( 515 template <class T> struct Tmpl {T x = 0;}; 516 template <> struct Tmpl<int> { 519 extern template struct Tmpl<float>; 520 template struct Tmpl<double>; 522 template <class T, class U, class Z = float> 525 int funcTmpl<int>(double a); 527 template <class T, class U = double> 530 double varTmpl<int> = 10.0; 533 getSymbols(FilePath), 543 AllOf(WithName(
"funcTmpl"),
Children()),
544 AllOf(WithName(
"funcTmpl<int>"),
Children()),
545 AllOf(WithName(
"varTmpl"),
Children()),
546 AllOf(WithName(
"varTmpl<int>"),
Children())));
549 TEST_F(DocumentSymbolsTest, Namespaces) {
550 std::string FilePath =
testPath(
"foo.cpp");
551 addFile(FilePath, R
"cpp( 563 inline namespace nb { 568 // This is still inlined. 575 getSymbols(FilePath), 576 ElementsAreArray<::testing::Matcher<DocumentSymbol>>( 577 {AllOf(WithName("ans1"),
579 AllOf(WithName(
"ans2"),
Children(WithName(
"ai2"))))),
580 AllOf(WithName(
"(anonymous namespace)"),
Children(WithName(
"test"))),
581 AllOf(WithName(
"na"),
583 AllOf(WithName(
"na"),
588 std::string FilePath =
testPath(
"foo.cpp");
589 addFile(FilePath, R
"( 606 getSymbols(FilePath), 608 AllOf(WithName("(anonymous enum)"),
Children(WithName(
"Red"))),
609 AllOf(WithName(
"Color"),
Children(WithName(
"Green"))),
610 AllOf(WithName(
"Color2"),
Children(WithName(
"Yellow"))),
611 AllOf(WithName(
"ns"),
Children(AllOf(WithName(
"(anonymous enum)"),
616 std::string FilePath =
testPath(
"foo.cpp");
619 class name##_Test {}; 621 $expansion[[FF]](abc); 624 class $spelling[[Test]] {}; 628 addFile(FilePath, Main.code()); 630 getSymbols(FilePath), 632 AllOf(WithName("abc_Test"), SymNameRange(Main.
range(
"expansion"))),
633 AllOf(WithName(
"Test"), SymNameRange(Main.
range(
"spelling")))));
636 TEST_F(DocumentSymbolsTest, FuncTemplates) {
637 std::string FilePath =
testPath(
"foo.cpp");
643 auto y = foo<double>() 645 addFile(FilePath, Source.code()); 647 EXPECT_THAT(getSymbols(FilePath),
648 ElementsAre(WithName(
"foo"), WithName(
"x"), WithName(
"y")));
651 TEST_F(DocumentSymbolsTest, UsingDirectives) {
652 std::string FilePath =
testPath(
"foo.cpp");
658 namespace ns_alias = ns; 660 using namespace ::ns; // check we don't loose qualifiers. 661 using namespace ns_alias; // and namespace aliases. 663 addFile(FilePath, Source.code()); 664 EXPECT_THAT(getSymbols(FilePath), 665 ElementsAre(WithName("ns"), WithName(
"ns_alias"),
666 WithName(
"using namespace ::ns"),
667 WithName(
"using namespace ns_alias")));
671 addFile(
"foo.cpp", R
"cpp( 672 template <typename T, typename U, int X = 5> class Foo {}; 673 template <typename T> class Foo<int, T> {}; 674 template <> class Foo<bool, int> {}; 675 template <> class Foo<bool, int, 3> {}; 679 getSymbols(
"foo.cpp"),
680 UnorderedElementsAre(
void addDocument(PathRef File, StringRef Contents, WantDiagnostics WD=WantDiagnostics::Auto)
Add a File to the list of tracked C++ files or update the contents if File is already tracked...
clangd::Range range(llvm::StringRef Name="") const
llvm::StringMap< std::string > Files
llvm::Expected< std::vector< DocumentSymbol > > runDocumentSymbols(ClangdServer &Server, PathRef File)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
LLVM_NODISCARD bool blockUntilIdleForTest(llvm::Optional< double > TimeoutSeconds=10)
static Options optsForTest()
MockFSProvider FSProvider
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
std::string testPath(PathRef File)
std::string Path
A typedef to represent a file path.
virtual void onDiagnosticsReady(PathRef File, std::vector< Diag > Diagnostics)=0
Called by ClangdServer when Diagnostics for File are ready.
static constexpr llvm::StringLiteral Name
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Expected< std::vector< SymbolInformation > > runWorkspaceSymbols(ClangdServer &Server, llvm::StringRef Query, int Limit)
MockCompilationDatabase CDB
CharSourceRange Range
SourceRange for the file name.
std::vector< DefinedMacro > Macros
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges...
IgnoreDiagnostics DiagConsumer
Manages a collection of source files and derived data (ASTs, indexes), and provides language-aware fe...