408 lines · cpp
1//===-- SymbolInfoTests.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-exception6//7//===----------------------------------------------------------------------===//8#include "Annotations.h"9#include "ParsedAST.h"10#include "TestTU.h"11#include "XRefs.h"12#include "gmock/gmock.h"13#include "gtest/gtest.h"14#include <optional>15 16namespace clang {17namespace clangd {18namespace {19 20using ::testing::UnorderedElementsAreArray;21 22// Partial SymbolDetails with the rest filled in at testing time.23struct ExpectedSymbolDetails {24 std::string Name;25 std::string Container;26 std::string USR;27 const char *DeclMarker = nullptr;28 const char *DefMarker = nullptr;29};30 31TEST(SymbolInfoTests, All) {32 std::pair<const char *, std::vector<ExpectedSymbolDetails>>33 TestInputExpectedOutput[] = {34 {35 R"cpp( // Simple function reference - declaration36 void $decl[[foo]]();37 int bar() {38 fo^o();39 return 0;40 }41 )cpp",42 {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl"}}},43 {44 R"cpp( // Simple function reference - definition45 void $def[[foo]]() {}46 int bar() {47 fo^o();48 return 0;49 }50 )cpp",51 {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "def"}}},52 {53 R"cpp( // Simple function reference - decl and def54 void $decl[[foo]]();55 void $def[[foo]]() {}56 int bar() {57 fo^o();58 return 0;59 }60 )cpp",61 {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl", "def"}}},62 {63 R"cpp( // Simple class reference - decl and def64 @interface $decl[[Foo]]65 @end66 @implementation $def[[Foo]]67 @end68 void doSomething(F^oo *obj) {}69 )cpp",70 {ExpectedSymbolDetails{"Foo", "", "c:objc(cs)Foo", "decl",71 "def"}}},72 {73 R"cpp( // Simple method reference - decl and def74 @interface Foo75 - (void)$decl[[foo]];76 @end77 @implementation Foo78 - (void)$def[[fo^o]] {}79 @end80 )cpp",81 {ExpectedSymbolDetails{"foo", "Foo::", "c:objc(cs)Foo(im)foo",82 "decl", "def"}}},83 {84 R"cpp( // Function in namespace reference85 namespace bar {86 void $decl[[foo]]();87 int baz() {88 fo^o();89 return 0;90 }91 }92 )cpp",93 {ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@F@foo#",94 "decl"}}},95 {96 R"cpp( // Function in different namespace reference97 namespace bar {98 void $decl[[foo]]();99 }100 namespace barbar {101 int baz() {102 bar::fo^o();103 return 0;104 }105 }106 )cpp",107 {ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@F@foo#",108 "decl"}}},109 {110 R"cpp( // Function in global namespace reference111 void $decl[[foo]]();112 namespace Nbar {113 namespace Nbaz {114 int baz() {115 ::fo^o();116 return 0;117 }118 }119 }120 )cpp",121 {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl"}}},122 {123 R"cpp( // Function in anonymous namespace reference124 namespace {125 void $decl[[foo]]();126 }127 namespace barbar {128 int baz() {129 fo^o();130 return 0;131 }132 }133 )cpp",134 {ExpectedSymbolDetails{"foo", "(anonymous)",135 "c:TestTU.cpp@aN@F@foo#", "decl"}}},136 {137 R"cpp( // Function reference - ADL138 namespace bar {139 struct BarType {};140 void $decl[[foo]](const BarType&);141 }142 namespace barbar {143 int baz() {144 bar::BarType b;145 fo^o(b);146 return 0;147 }148 }149 )cpp",150 {ExpectedSymbolDetails{151 "foo", "bar::", "c:@N@bar@F@foo#&1$@N@bar@S@BarType#",152 "decl"}}},153 {154 R"cpp( // Global value reference155 int $def[[value]];156 void foo(int) { }157 void bar() {158 foo(val^ue);159 }160 )cpp",161 {ExpectedSymbolDetails{"value", "", "c:@value", "def", "def"}}},162 {163 R"cpp( // Local value reference164 void foo() { int $def[[aaa]]; int bbb = aa^a; }165 )cpp",166 {ExpectedSymbolDetails{"aaa", "foo", "c:TestTU.cpp@49@F@foo#@aaa",167 "def", "def"}}},168 {169 R"cpp( // Function param170 void bar(int $def[[aaa]]) {171 int bbb = a^aa;172 }173 )cpp",174 {ExpectedSymbolDetails{175 "aaa", "bar", "c:TestTU.cpp@38@F@bar#I#@aaa", "def", "def"}}},176 {177 R"cpp( // Lambda capture178 void foo() {179 int $def[[ii]];180 auto lam = [ii]() {181 return i^i;182 };183 }184 )cpp",185 {ExpectedSymbolDetails{"ii", "foo", "c:TestTU.cpp@54@F@foo#@ii",186 "def", "def"}}},187 {188 R"cpp( // Macro reference189 #define MACRO 5\nint i = MAC^RO;190 )cpp",191 {ExpectedSymbolDetails{"MACRO", "",192 "c:TestTU.cpp@38@macro@MACRO"}}},193 {194 R"cpp( // Macro reference195 #define MACRO 5\nint i = MACRO^;196 )cpp",197 {ExpectedSymbolDetails{"MACRO", "",198 "c:TestTU.cpp@38@macro@MACRO"}}},199 {200 R"cpp( // Multiple symbols returned - using overloaded function name201 void $def[[foo]]() {}202 void $def_bool[[foo]](bool) {}203 void $def_int[[foo]](int) {}204 namespace bar {205 using ::$decl[[fo^o]];206 }207 )cpp",208 {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "def"},209 ExpectedSymbolDetails{"foo", "", "c:@F@foo#b#", "def_bool",210 "def_bool"},211 ExpectedSymbolDetails{"foo", "", "c:@F@foo#I#", "def_int",212 "def_int"},213 ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@UD@foo",214 "decl"}}},215 {216 R"cpp( // Multiple symbols returned - implicit conversion217 struct foo {};218 struct bar {219 bar(const foo&) {}220 };221 void func_baz1(bar) {}222 void func_baz2() {223 foo $def[[ff]];224 func_baz1(f^f);225 }226 )cpp",227 {ExpectedSymbolDetails{"ff", "func_baz2",228 "c:TestTU.cpp@218@F@func_baz2#@ff", "def",229 "def"}}},230 {231 R"cpp( // Type reference - declaration232 struct $decl[[foo]];233 void bar(fo^o*);234 )cpp",235 {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "decl"}}},236 {237 R"cpp( // Type reference - definition238 struct $def[[foo]] {};239 void bar(fo^o*);240 )cpp",241 {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "def"}}},242 {243 R"cpp( // Type Reference - template argument244 struct $def[[foo]] {};245 template<class T> struct bar {};246 void baz() {247 bar<fo^o> b;248 }249 )cpp",250 {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "def"}}},251 {252 R"cpp( // Template parameter reference - type param253 template<class $def[[TT]]> struct bar {254 T^T t;255 };256 )cpp",257 {ExpectedSymbolDetails{"TT", "bar::", "c:TestTU.cpp@65", "def",258 "def"}}},259 {260 R"cpp( // Template parameter reference - type param261 template<int $def[[NN]]> struct bar {262 int a = N^N;263 };264 )cpp",265 {ExpectedSymbolDetails{"NN", "bar::", "c:TestTU.cpp@65", "def",266 "def"}}},267 {268 R"cpp( // Class member reference - objec269 struct foo {270 int $def[[aa]];271 };272 void bar() {273 foo f;274 f.a^a;275 }276 )cpp",277 {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@FI@aa", "def",278 "def"}}},279 {280 R"cpp( // Class member reference - pointer281 struct foo {282 int $def[[aa]];283 };284 void bar() {285 &foo::a^a;286 }287 )cpp",288 {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@FI@aa", "def",289 "def"}}},290 {291 R"cpp( // Class method reference - objec292 struct foo {293 void $def[[aa]]() {}294 };295 void bar() {296 foo f;297 f.a^a();298 }299 )cpp",300 {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@F@aa#", "def",301 "def"}}},302 {303 R"cpp( // Class method reference - pointer304 struct foo {305 void $def[[aa]]() {}306 };307 void bar() {308 &foo::a^a;309 }310 )cpp",311 {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@F@aa#", "def",312 "def"}}},313 {314 R"cpp( // Typedef315 typedef int $decl[[foo]];316 void bar() {317 fo^o a;318 }319 )cpp",320 {ExpectedSymbolDetails{"foo", "", "c:TestTU.cpp@T@foo", "decl"}}},321 {322 R"cpp( // Type alias323 using $decl[[foo]] = int;324 void bar() {325 fo^o a;326 }327 )cpp",328 {ExpectedSymbolDetails{"foo", "", "c:@foo", "decl"}}},329 {330 R"cpp( // Namespace reference331 namespace $decl[[foo]] {}332 using namespace fo^o;333 )cpp",334 {ExpectedSymbolDetails{"foo", "", "c:@N@foo", "decl"}}},335 {336 R"cpp( // Enum value reference337 enum foo { $def[[bar]], baz };338 void f() {339 foo fff = ba^r;340 }341 )cpp",342 {ExpectedSymbolDetails{"bar", "foo", "c:@E@foo@bar", "def",343 "def"}}},344 {345 R"cpp( // Enum class value reference346 enum class foo { $def[[bar]], baz };347 void f() {348 foo fff = foo::ba^r;349 }350 )cpp",351 {ExpectedSymbolDetails{"bar", "foo::", "c:@E@foo@bar", "def",352 "def"}}},353 {354 R"cpp( // Parameters in declarations355 void foo(int $def[[ba^r]]);356 )cpp",357 {ExpectedSymbolDetails{358 "bar", "foo", "c:TestTU.cpp@50@F@foo#I#@bar", "def", "def"}}},359 {360 R"cpp( // Type inference with auto keyword361 struct foo {};362 foo getfoo() { return foo{}; }363 void f() {364 au^to a = getfoo();365 }366 )cpp",367 {/* not implemented */}},368 {369 R"cpp( // decltype370 struct foo {};371 void f() {372 foo f;373 declt^ype(f);374 }375 )cpp",376 {/* not implemented */}},377 };378 379 for (const auto &T : TestInputExpectedOutput) {380 Annotations TestInput(T.first);381 TestTU TU;382 TU.Code = std::string(TestInput.code());383 TU.ExtraArgs.push_back("-xobjective-c++");384 auto AST = TU.build();385 386 std::vector<SymbolDetails> Expected;387 for (const auto &Sym : T.second) {388 std::optional<Location> Decl, Def;389 if (Sym.DeclMarker)390 Decl = Location{URIForFile::canonicalize(testPath(TU.Filename), ""),391 TestInput.range(Sym.DeclMarker)};392 if (Sym.DefMarker)393 Def = Location{URIForFile::canonicalize(testPath(TU.Filename), ""),394 TestInput.range(Sym.DefMarker)};395 Expected.push_back(396 {Sym.Name, Sym.Container, Sym.USR, SymbolID(Sym.USR), Decl, Def});397 }398 399 EXPECT_THAT(getSymbolInfo(AST, TestInput.point()),400 UnorderedElementsAreArray(Expected))401 << T.first;402 }403}404 405} // namespace406} // namespace clangd407} // namespace clang408