| //===-- SymbolInfoTests.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 "ParsedAST.h" | 
 | #include "TestTU.h" | 
 | #include "XRefs.h" | 
 | #include "gmock/gmock.h" | 
 | #include "gtest/gtest.h" | 
 | #include <optional> | 
 |  | 
 | namespace clang { | 
 | namespace clangd { | 
 | namespace { | 
 |  | 
 | using ::testing::UnorderedElementsAreArray; | 
 |  | 
 | // Partial SymbolDetails with the rest filled in at testing time. | 
 | struct ExpectedSymbolDetails { | 
 |   std::string Name; | 
 |   std::string Container; | 
 |   std::string USR; | 
 |   const char *DeclMarker = nullptr; | 
 |   const char *DefMarker = nullptr; | 
 | }; | 
 |  | 
 | TEST(SymbolInfoTests, All) { | 
 |   std::pair<const char *, std::vector<ExpectedSymbolDetails>> | 
 |       TestInputExpectedOutput[] = { | 
 |           { | 
 |               R"cpp( // Simple function reference - declaration | 
 |           void $decl[[foo]](); | 
 |           int bar() { | 
 |             fo^o(); | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Simple function reference - definition | 
 |           void $def[[foo]]() {} | 
 |           int bar() { | 
 |             fo^o(); | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Simple function reference - decl and def | 
 |           void $decl[[foo]](); | 
 |           void $def[[foo]]() {} | 
 |           int bar() { | 
 |             fo^o(); | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl", "def"}}}, | 
 |           { | 
 |               R"cpp( // Simple class reference - decl and def | 
 |           @interface $decl[[Foo]] | 
 |           @end | 
 |           @implementation $def[[Foo]] | 
 |           @end | 
 |           void doSomething(F^oo *obj) {} | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"Foo", "", "c:objc(cs)Foo", "decl", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Simple method reference - decl and def | 
 |           @interface Foo | 
 |           - (void)$decl[[foo]]; | 
 |           @end | 
 |           @implementation Foo | 
 |           - (void)$def[[fo^o]] {} | 
 |           @end | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "Foo::", "c:objc(cs)Foo(im)foo", | 
 |                                      "decl", "def"}}}, | 
 |           { | 
 |               R"cpp( // Function in namespace reference | 
 |           namespace bar { | 
 |             void $decl[[foo]](); | 
 |             int baz() { | 
 |               fo^o(); | 
 |             } | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@F@foo#", | 
 |                                      "decl"}}}, | 
 |           { | 
 |               R"cpp( // Function in different namespace reference | 
 |           namespace bar { | 
 |             void $decl[[foo]](); | 
 |           } | 
 |           namespace barbar { | 
 |             int baz() { | 
 |               bar::fo^o(); | 
 |             } | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@F@foo#", | 
 |                                      "decl"}}}, | 
 |           { | 
 |               R"cpp( // Function in global namespace reference | 
 |           void $decl[[foo]](); | 
 |           namespace Nbar { | 
 |             namespace Nbaz { | 
 |               int baz() { | 
 |                 ::fo^o(); | 
 |               } | 
 |             } | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Function in anonymous namespace reference | 
 |           namespace { | 
 |             void $decl[[foo]](); | 
 |           } | 
 |           namespace barbar { | 
 |             int baz() { | 
 |               fo^o(); | 
 |             } | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "(anonymous)", | 
 |                                      "c:TestTU.cpp@aN@F@foo#", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Function reference - ADL | 
 |           namespace bar { | 
 |             struct BarType {}; | 
 |             void $decl[[foo]](const BarType&); | 
 |           } | 
 |           namespace barbar { | 
 |             int baz() { | 
 |               bar::BarType b; | 
 |               fo^o(b); | 
 |             } | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{ | 
 |                   "foo", "bar::", "c:@N@bar@F@foo#&1$@N@bar@S@BarType#", | 
 |                   "decl"}}}, | 
 |           { | 
 |               R"cpp( // Global value reference | 
 |           int $def[[value]]; | 
 |           void foo(int) { } | 
 |           void bar() { | 
 |             foo(val^ue); | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"value", "", "c:@value", "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Local value reference | 
 |           void foo() { int $def[[aaa]]; int bbb = aa^a; } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"aaa", "foo", "c:TestTU.cpp@49@F@foo#@aaa", | 
 |                                      "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Function param | 
 |           void bar(int $def[[aaa]]) { | 
 |             int bbb = a^aa; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{ | 
 |                   "aaa", "bar", "c:TestTU.cpp@38@F@bar#I#@aaa", "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Lambda capture | 
 |           void foo() { | 
 |             int $def[[ii]]; | 
 |             auto lam = [ii]() { | 
 |               return i^i; | 
 |             }; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"ii", "foo", "c:TestTU.cpp@54@F@foo#@ii", | 
 |                                      "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Macro reference | 
 |           #define MACRO 5\nint i = MAC^RO; | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"MACRO", "", | 
 |                                      "c:TestTU.cpp@38@macro@MACRO"}}}, | 
 |           { | 
 |               R"cpp( // Macro reference | 
 |           #define MACRO 5\nint i = MACRO^; | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"MACRO", "", | 
 |                                      "c:TestTU.cpp@38@macro@MACRO"}}}, | 
 |           { | 
 |               R"cpp( // Multiple symbols returned - using overloaded function name | 
 |           void $def[[foo]]() {} | 
 |           void $def_bool[[foo]](bool) {} | 
 |           void $def_int[[foo]](int) {} | 
 |           namespace bar { | 
 |             using ::$decl[[fo^o]]; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "def"}, | 
 |                ExpectedSymbolDetails{"foo", "", "c:@F@foo#b#", "def_bool", | 
 |                                      "def_bool"}, | 
 |                ExpectedSymbolDetails{"foo", "", "c:@F@foo#I#", "def_int", | 
 |                                      "def_int"}, | 
 |                ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@UD@foo", | 
 |                                      "decl"}}}, | 
 |           { | 
 |               R"cpp( // Multiple symbols returned - implicit conversion | 
 |           struct foo {}; | 
 |           struct bar { | 
 |             bar(const foo&) {} | 
 |           }; | 
 |           void func_baz1(bar) {} | 
 |           void func_baz2() { | 
 |             foo $def[[ff]]; | 
 |             func_baz1(f^f); | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"ff", "func_baz2", | 
 |                                      "c:TestTU.cpp@218@F@func_baz2#@ff", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Type reference - declaration | 
 |           struct $decl[[foo]]; | 
 |           void bar(fo^o*); | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Type reference - definition | 
 |           struct $def[[foo]] {}; | 
 |           void bar(fo^o*); | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Type Reference - template argument | 
 |           struct $def[[foo]] {}; | 
 |           template<class T> struct bar {}; | 
 |           void baz() { | 
 |             bar<fo^o> b; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Template parameter reference - type param | 
 |           template<class $def[[TT]]> struct bar { | 
 |             T^T t; | 
 |           }; | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"TT", "bar::", "c:TestTU.cpp@65", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Template parameter reference - type param | 
 |           template<int $def[[NN]]> struct bar { | 
 |             int a = N^N; | 
 |           }; | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"NN", "bar::", "c:TestTU.cpp@65", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Class member reference - objec | 
 |           struct foo { | 
 |             int $def[[aa]]; | 
 |           }; | 
 |           void bar() { | 
 |             foo f; | 
 |             f.a^a; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@FI@aa", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Class member reference - pointer | 
 |           struct foo { | 
 |             int $def[[aa]]; | 
 |           }; | 
 |           void bar() { | 
 |             &foo::a^a; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@FI@aa", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Class method reference - objec | 
 |           struct foo { | 
 |             void $def[[aa]]() {} | 
 |           }; | 
 |           void bar() { | 
 |             foo f; | 
 |             f.a^a(); | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@F@aa#", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Class method reference - pointer | 
 |           struct foo { | 
 |             void $def[[aa]]() {} | 
 |           }; | 
 |           void bar() { | 
 |             &foo::a^a; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@F@aa#", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Typedef | 
 |           typedef int $decl[[foo]]; | 
 |           void bar() { | 
 |             fo^o a; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:TestTU.cpp@T@foo", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Type alias | 
 |           using $decl[[foo]] = int; | 
 |           void bar() { | 
 |             fo^o a; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@foo", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Namespace reference | 
 |           namespace $decl[[foo]] {} | 
 |           using namespace fo^o; | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"foo", "", "c:@N@foo", "decl"}}}, | 
 |           { | 
 |               R"cpp( // Enum value reference | 
 |           enum foo { $def[[bar]], baz }; | 
 |           void f() { | 
 |             foo fff = ba^r; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"bar", "foo", "c:@E@foo@bar", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Enum class value reference | 
 |           enum class foo { $def[[bar]], baz }; | 
 |           void f() { | 
 |             foo fff = foo::ba^r; | 
 |           } | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{"bar", "foo::", "c:@E@foo@bar", "def", | 
 |                                      "def"}}}, | 
 |           { | 
 |               R"cpp( // Parameters in declarations | 
 |           void foo(int $def[[ba^r]]); | 
 |         )cpp", | 
 |               {ExpectedSymbolDetails{ | 
 |                   "bar", "foo", "c:TestTU.cpp@50@F@foo#I#@bar", "def", "def"}}}, | 
 |           { | 
 |               R"cpp( // Type inference with auto keyword | 
 |           struct foo {}; | 
 |           foo getfoo() { return foo{}; } | 
 |           void f() { | 
 |             au^to a = getfoo(); | 
 |           } | 
 |         )cpp", | 
 |               {/* not implemented */}}, | 
 |           { | 
 |               R"cpp( // decltype | 
 |           struct foo {}; | 
 |           void f() { | 
 |             foo f; | 
 |             declt^ype(f); | 
 |           } | 
 |         )cpp", | 
 |               {/* not implemented */}}, | 
 |       }; | 
 |  | 
 |   for (const auto &T : TestInputExpectedOutput) { | 
 |     Annotations TestInput(T.first); | 
 |     TestTU TU; | 
 |     TU.Code = std::string(TestInput.code()); | 
 |     TU.ExtraArgs.push_back("-xobjective-c++"); | 
 |     auto AST = TU.build(); | 
 |  | 
 |     std::vector<SymbolDetails> Expected; | 
 |     for (const auto &Sym : T.second) { | 
 |       std::optional<Location> Decl, Def; | 
 |       if (Sym.DeclMarker) | 
 |         Decl = Location{URIForFile::canonicalize(testPath(TU.Filename), ""), | 
 |                         TestInput.range(Sym.DeclMarker)}; | 
 |       if (Sym.DefMarker) | 
 |         Def = Location{URIForFile::canonicalize(testPath(TU.Filename), ""), | 
 |                        TestInput.range(Sym.DefMarker)}; | 
 |       Expected.push_back( | 
 |           {Sym.Name, Sym.Container, Sym.USR, SymbolID(Sym.USR), Decl, Def}); | 
 |     } | 
 |  | 
 |     EXPECT_THAT(getSymbolInfo(AST, TestInput.point()), | 
 |                 UnorderedElementsAreArray(Expected)) | 
 |         << T.first; | 
 |   } | 
 | } | 
 |  | 
 | } // namespace | 
 | } // namespace clangd | 
 | } // namespace clang |