//===-- 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 "Config.h" #include "Hover.h" #include "TestFS.h" #include "TestIndex.h" #include "TestTU.h" #include "index/MemIndex.h" #include "clang/AST/Attr.h" #include "clang/Format/Format.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "gtest/gtest.h" #include #include #include #include namespace clang { namespace clangd { namespace { using PassMode = HoverInfo::PassType::PassMode; std::string guard(llvm::StringRef Code) { return "#pragma once\n" + Code.str(); } 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 { class Foo { char [[b^ar]]; double y[2]; }; }} )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 = 8; HI.Padding = 56; HI.Align = 8; HI.AccessSpecifier = "private"; }}, // Union field {R"cpp( union Foo { char [[b^ar]]; double y[2]; }; )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.LocalScope = "Foo::"; HI.Name = "bar"; HI.Kind = index::SymbolKind::Field; HI.Definition = "char bar"; HI.Type = "char"; HI.Size = 8; HI.Padding = 120; HI.Align = 8; HI.AccessSpecifier = "public"; }}, // Bitfield {R"cpp( struct Foo { int [[^x]] : 1; int y : 1; }; )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.LocalScope = "Foo::"; HI.Name = "x"; HI.Kind = index::SymbolKind::Field; HI.Definition = "int x : 1"; HI.Type = "int"; HI.Offset = 0; HI.Size = 1; HI.Align = 32; 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"; }}, // Predefined variable {R"cpp( void foo() { [[__f^unc__]]; } )cpp", [](HoverInfo &HI) { HI.Name = "__func__"; HI.Kind = index::SymbolKind::Variable; HI.Documentation = "Name of the current function (predefined variable)"; HI.Value = "\"foo\""; HI.Type = "const char[4]"; }}, // Predefined variable (dependent) {R"cpp( template void foo() { [[__f^unc__]]; } )cpp", [](HoverInfo &HI) { HI.Name = "__func__"; HI.Kind = index::SymbolKind::Variable; HI.Documentation = "Name of the current function (predefined variable)"; HI.Type = "const char[]"; }}, // 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 = 8; HI.Align = 8; 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 = 8; HI.Align = 8; }}, // 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 final {}; template class T> [[F^oo]] foo; )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "Foo"; HI.Kind = index::SymbolKind::Class; HI.Definition = R"cpp(template