//===-- HoverTests.cpp ----------------------------------------------------===// // // 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 "AST.h" #include "Annotations.h" #include "Hover.h" #include "TestIndex.h" #include "TestTU.h" #include "index/MemIndex.h" #include "clang/Basic/Specifiers.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/None.h" #include "llvm/ADT/StringRef.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include #include namespace clang { namespace clangd { namespace { using PassMode = HoverInfo::PassType::PassMode; TEST(Hover, Structured) { struct { const char *const Code; const std::function ExpectedBuilder; } Cases[] = { // Global scope. {R"cpp( // Best foo ever. void [[fo^o]]() {} )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "foo"; HI.Kind = index::SymbolKind::Function; HI.Documentation = "Best foo ever."; HI.Definition = "void foo()"; HI.ReturnType = "void"; HI.Type = "void ()"; HI.Parameters.emplace(); }}, // Inside namespace {R"cpp( namespace ns1 { namespace ns2 { /// Best foo ever. void [[fo^o]]() {} }} )cpp", [](HoverInfo &HI) { HI.NamespaceScope = "ns1::ns2::"; HI.Name = "foo"; HI.Kind = index::SymbolKind::Function; HI.Documentation = "Best foo ever."; HI.Definition = "void foo()"; HI.ReturnType = "void"; HI.Type = "void ()"; HI.Parameters.emplace(); }}, // Field {R"cpp( namespace ns1 { namespace ns2 { struct Foo { char [[b^ar]]; }; }} )cpp", [](HoverInfo &HI) { HI.NamespaceScope = "ns1::ns2::"; HI.LocalScope = "Foo::"; HI.Name = "bar"; HI.Kind = index::SymbolKind::Field; HI.Definition = "char bar"; HI.Type = "char"; HI.Offset = 0; HI.Size = 1; HI.AccessSpecifier = "public"; }}, // Local to class method. {R"cpp( namespace ns1 { namespace ns2 { struct Foo { void foo() { int [[b^ar]]; } }; }} )cpp", [](HoverInfo &HI) { HI.NamespaceScope = "ns1::ns2::"; HI.LocalScope = "Foo::foo::"; HI.Name = "bar"; HI.Kind = index::SymbolKind::Variable; HI.Definition = "int bar"; HI.Type = "int"; }}, // Anon namespace and local scope. {R"cpp( namespace ns1 { namespace { struct { char [[b^ar]]; } T; }} )cpp", [](HoverInfo &HI) { HI.NamespaceScope = "ns1::"; HI.LocalScope = "(anonymous struct)::"; HI.Name = "bar"; HI.Kind = index::SymbolKind::Field; HI.Definition = "char bar"; HI.Type = "char"; HI.Offset = 0; HI.Size = 1; HI.AccessSpecifier = "public"; }}, // Struct definition shows size. {R"cpp( struct [[^X]]{}; )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "X"; HI.Kind = index::SymbolKind::Struct; HI.Definition = "struct X {}"; HI.Size = 1; }}, // Variable with template type {R"cpp( template class Foo { public: Foo(int); }; Foo [[fo^o]] = Foo(5); )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "foo"; HI.Kind = index::SymbolKind::Variable; HI.Definition = "Foo foo = Foo(5)"; HI.Type = "Foo"; }}, // Implicit template instantiation {R"cpp( template class vector{}; [[vec^tor]] foo; )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "vector"; HI.Kind = index::SymbolKind::Class; HI.Definition = "template <> class vector {}"; }}, // Class template {R"cpp( template class C, typename = char, int = 0, bool Q = false, class... Ts> class Foo {}; template class T> [[F^oo]] foo; )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "Foo"; HI.Kind = index::SymbolKind::Class; HI.Definition = R"cpp(template