[clang-tools-extra] r347675 - [clangd] textDocument/SymbolInfo extension

Jan Korous via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 27 08:40:46 PST 2018


Author: jkorous
Date: Tue Nov 27 08:40:46 2018
New Revision: 347675

URL: http://llvm.org/viewvc/llvm-project?rev=347675&view=rev
Log:
[clangd] textDocument/SymbolInfo extension

New method returning symbol info for given source position.

Differential Revision: https://reviews.llvm.org/D54799

rdar://problem/46050281

Added:
    clang-tools-extra/trunk/test/clangd/symbol-info.test
    clang-tools-extra/trunk/unittests/clangd/SymbolInfoTests.cpp
Modified:
    clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
    clang-tools-extra/trunk/clangd/ClangdLSPServer.h
    clang-tools-extra/trunk/clangd/ClangdServer.cpp
    clang-tools-extra/trunk/clangd/ClangdServer.h
    clang-tools-extra/trunk/clangd/Protocol.cpp
    clang-tools-extra/trunk/clangd/Protocol.h
    clang-tools-extra/trunk/clangd/XRefs.cpp
    clang-tools-extra/trunk/clangd/XRefs.h
    clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt

Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Tue Nov 27 08:40:46 2018
@@ -698,6 +698,12 @@ void ClangdLSPServer::onReference(const
                          std::move(Reply));
 }
 
+void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params,
+                                   Callback<std::vector<SymbolDetails>> Reply) {
+  Server->symbolInfo(Params.textDocument.uri.file(), Params.position,
+                     std::move(Reply));
+}
+
 ClangdLSPServer::ClangdLSPServer(class Transport &Transp,
                                  const clangd::CodeCompleteOptions &CCOpts,
                                  Optional<Path> CompileCommandsDir,
@@ -733,6 +739,7 @@ ClangdLSPServer::ClangdLSPServer(class T
   MsgHandler->bind("textDocument/didChange", &ClangdLSPServer::onDocumentDidChange);
   MsgHandler->bind("workspace/didChangeWatchedFiles", &ClangdLSPServer::onFileEvent);
   MsgHandler->bind("workspace/didChangeConfiguration", &ClangdLSPServer::onChangeConfiguration);
+  MsgHandler->bind("textDocument/symbolInfo", &ClangdLSPServer::onSymbolInfo);
   // clang-format on
 }
 

Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.h Tue Nov 27 08:40:46 2018
@@ -92,6 +92,8 @@ private:
   void onHover(const TextDocumentPositionParams &,
                Callback<llvm::Optional<Hover>>);
   void onChangeConfiguration(const DidChangeConfigurationParams &);
+  void onSymbolInfo(const TextDocumentPositionParams &,
+                    Callback<std::vector<SymbolDetails>>);
 
   std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
 

Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Tue Nov 27 08:40:46 2018
@@ -503,6 +503,18 @@ void ClangdServer::findReferences(PathRe
   WorkScheduler.runWithAST("References", File, Bind(Action, std::move(CB)));
 }
 
+void ClangdServer::symbolInfo(PathRef File, Position Pos,
+                              Callback<std::vector<SymbolDetails>> CB) {
+  auto Action = [Pos](Callback<std::vector<SymbolDetails>> CB,
+                      Expected<InputsAndAST> InpAST) {
+    if (!InpAST)
+      return CB(InpAST.takeError());
+    CB(clangd::getSymbolInfo(InpAST->AST, Pos));
+  };
+
+  WorkScheduler.runWithAST("SymbolInfo", File, Bind(Action, std::move(CB)));
+}
+
 std::vector<std::pair<Path, std::size_t>>
 ClangdServer::getUsedBytesPerFile() const {
   return WorkScheduler.getUsedBytesPerFile();

Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Tue Nov 27 08:40:46 2018
@@ -202,6 +202,11 @@ public:
   /// Called when an event occurs for a watched file in the workspace.
   void onFileEvent(const DidChangeWatchedFilesParams &Params);
 
+  /// Get symbol info for given position.
+  /// Clangd extension - not part of official LSP.
+  void symbolInfo(PathRef File, Position Pos,
+                  Callback<std::vector<SymbolDetails>> CB);
+
   /// Returns estimated memory usage for each of the currently open files.
   /// The order of results is unspecified.
   /// Overall memory usage of clangd may be significantly more than reported

Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Tue Nov 27 08:40:46 2018
@@ -14,7 +14,9 @@
 #include "Protocol.h"
 #include "Logger.h"
 #include "URI.h"
+#include "index/Index.h"
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -428,6 +430,44 @@ raw_ostream &operator<<(raw_ostream &O,
   return O;
 }
 
+bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) {
+  return LHS.name == RHS.name && LHS.containerName == RHS.containerName &&
+         LHS.USR == RHS.USR && LHS.ID == RHS.ID;
+}
+
+llvm::json::Value toJSON(const SymbolDetails &P) {
+  json::Object result{{"name", llvm::json::Value(nullptr)},
+                      {"containerName", llvm::json::Value(nullptr)},
+                      {"usr", llvm::json::Value(nullptr)},
+                      {"id", llvm::json::Value(nullptr)}};
+
+  if (!P.name.empty())
+    result["name"] = P.name;
+
+  if (!P.containerName.empty())
+    result["containerName"] = P.containerName;
+
+  if (!P.USR.empty())
+    result["usr"] = P.USR;
+
+  if (P.ID.hasValue())
+    result["id"] = P.ID.getValue().str();
+
+  return result;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {
+  if (!S.containerName.empty()) {
+    O << S.containerName;
+    StringRef ContNameRef;
+    if (!ContNameRef.endswith("::")) {
+      O << " ";
+    }
+  }
+  O << S.name << " - " << toJSON(S);
+  return O;
+}
+
 bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
   json::ObjectMapper O(Params);
   return O && O.map("query", R.query);

Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Tue Nov 27 08:40:46 2018
@@ -713,6 +713,26 @@ struct SymbolInformation {
 llvm::json::Value toJSON(const SymbolInformation &);
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolInformation &);
 
+/// Represents information about identifier.
+/// This is returned from textDocument/symbolInfo, which is a clangd extension.
+struct SymbolDetails {
+  std::string name;
+
+  std::string containerName;
+
+  /// Unified Symbol Resolution identifier
+  /// This is an opaque string uniquely identifying a symbol.
+  /// Unlike SymbolID, it is variable-length and somewhat human-readable.
+  /// It is a common representation across several clang tools.
+  /// (See USRGeneration.h)
+  std::string USR;
+
+  llvm::Optional<SymbolID> ID;
+};
+llvm::json::Value toJSON(const SymbolDetails &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolDetails &);
+bool operator==(const SymbolDetails &, const SymbolDetails &);
+
 /// The parameters of a Workspace Symbol Request.
 struct WorkspaceSymbolParams {
   /// A non-empty query string

Modified: clang-tools-extra/trunk/clangd/XRefs.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/XRefs.cpp?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/XRefs.cpp (original)
+++ clang-tools-extra/trunk/clangd/XRefs.cpp Tue Nov 27 08:40:46 2018
@@ -750,5 +750,48 @@ std::vector<Location> findReferences(Par
   return Results;
 }
 
+std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {
+  const SourceManager &SM = AST.getASTContext().getSourceManager();
+
+  auto Loc = getBeginningOfIdentifier(AST, Pos, SM.getMainFileID());
+  auto Symbols = getSymbolAtPosition(AST, Loc);
+
+  std::vector<SymbolDetails> Results;
+
+  for (const auto &Sym : Symbols.Decls) {
+    SymbolDetails NewSymbol;
+    if (const NamedDecl *ND = dyn_cast<NamedDecl>(Sym.D)) {
+      std::string QName = printQualifiedName(*ND);
+      std::tie(NewSymbol.containerName, NewSymbol.name) =
+          splitQualifiedName(QName);
+
+      if (NewSymbol.containerName.empty()) {
+        if (const auto *ParentND =
+                dyn_cast_or_null<NamedDecl>(ND->getDeclContext()))
+          NewSymbol.containerName = printQualifiedName(*ParentND);
+      }
+    }
+    llvm::SmallString<32> USR;
+    if (!index::generateUSRForDecl(Sym.D, USR)) {
+      NewSymbol.USR = USR.str();
+      NewSymbol.ID = SymbolID(NewSymbol.USR);
+    }
+    Results.push_back(std::move(NewSymbol));
+  }
+
+  for (const auto &Macro : Symbols.Macros) {
+    SymbolDetails NewMacro;
+    NewMacro.name = Macro.Name;
+    llvm::SmallString<32> USR;
+    if (!index::generateUSRForMacro(NewMacro.name, Loc, SM, USR)) {
+      NewMacro.USR = USR.str();
+      NewMacro.ID = SymbolID(NewMacro.USR);
+    }
+    Results.push_back(std::move(NewMacro));
+  }
+
+  return Results;
+}
+
 } // namespace clangd
 } // namespace clang

Modified: clang-tools-extra/trunk/clangd/XRefs.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/XRefs.h?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/XRefs.h (original)
+++ clang-tools-extra/trunk/clangd/XRefs.h Tue Nov 27 08:40:46 2018
@@ -38,6 +38,9 @@ llvm::Optional<Hover> getHover(ParsedAST
 std::vector<Location> findReferences(ParsedAST &AST, Position Pos,
                                      const SymbolIndex *Index = nullptr);
 
+/// Get info about symbols at \p Pos.
+std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos);
+
 } // namespace clangd
 } // namespace clang
 

Added: clang-tools-extra/trunk/test/clangd/symbol-info.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/symbol-info.test?rev=347675&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/symbol-info.test (added)
+++ clang-tools-extra/trunk/test/clangd/symbol-info.test Tue Nov 27 08:40:46 2018
@@ -0,0 +1,14 @@
+# RUN: clangd -lit-test < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///simple.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///simple.cpp"},"position":{"line":0,"character":27}}}
+#      CHECK:    "containerName": null,
+# CHECK-NEXT:    "id": "CA2EBE44A1D76D2A",
+# CHECK-NEXT:    "name": "foo",
+# CHECK-NEXT:    "usr": "c:@F at foo#"
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}

Modified: clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt?rev=347675&r1=347674&r2=347675&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt Tue Nov 27 08:40:46 2018
@@ -35,6 +35,7 @@ add_extra_unittest(ClangdTests
   SerializationTests.cpp
   SourceCodeTests.cpp
   SymbolCollectorTests.cpp
+  SymbolInfoTests.cpp
   SyncAPI.cpp
   TUSchedulerTests.cpp
   TestFS.cpp

Added: clang-tools-extra/trunk/unittests/clangd/SymbolInfoTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SymbolInfoTests.cpp?rev=347675&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/SymbolInfoTests.cpp (added)
+++ clang-tools-extra/trunk/unittests/clangd/SymbolInfoTests.cpp Tue Nov 27 08:40:46 2018
@@ -0,0 +1,357 @@
+//===-- SymbolInfoTests.cpp  -----------------------*- C++ -*--------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "ClangdUnit.h"
+#include "Compiler.h"
+#include "Matchers.h"
+#include "SyncAPI.h"
+#include "TestFS.h"
+#include "TestTU.h"
+#include "XRefs.h"
+#include "index/FileIndex.h"
+#include "index/SymbolCollector.h"
+#include "clang/Index/IndexingAction.h"
+#include "llvm/Support/Path.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+namespace clang {
+namespace clangd {
+namespace {
+
+using testing::ElementsAreArray;
+
+auto CreateExpectedSymbolDetails = [](const std::string &name,
+                                      const std::string &container,
+                                      const std::string &USR) {
+  return SymbolDetails{name, container, USR, SymbolID(USR)};
+};
+
+TEST(SymbolInfoTests, All) {
+  std::pair<const char *, std::vector<SymbolDetails>>
+      TestInputExpectedOutput[] = {
+      {
+        R"cpp( // Simple function reference - declaration
+          void foo();
+          int bar() {
+            fo^o();
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@F at foo#")}
+      },
+      {
+        R"cpp( // Simple function reference - definition
+          void foo() {}
+          int bar() {
+            fo^o();
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@F at foo#")}
+      },
+      {
+        R"cpp( // Function in namespace reference
+          namespace bar {
+            void foo();
+            int baz() {
+              fo^o();
+            }
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "bar::", "c:@N at bar@F at foo#")}
+      },
+      {
+        R"cpp( // Function in different namespace reference
+          namespace bar {
+            void foo();
+          }
+          namespace barbar {
+            int baz() {
+              bar::fo^o();
+            }
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "bar::", "c:@N at bar@F at foo#")}
+      },
+      {
+        R"cpp( // Function in global namespace reference
+          void foo();
+          namespace Nbar {
+            namespace Nbaz {
+              int baz() {
+                ::fo^o();
+              }
+            }
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@F at foo#")}
+      },
+      {
+        R"cpp( // Function in anonymous namespace reference
+          namespace {
+            void foo();
+          }
+          namespace barbar {
+            int baz() {
+              fo^o();
+            }
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "(anonymous)", "c:TestTU.cpp at aN@F at foo#")}
+      },
+      {
+        R"cpp( // Function reference - ADL
+          namespace bar {
+            struct BarType {};
+            void foo(const BarType&);
+          }
+          namespace barbar {
+            int baz() {
+              bar::BarType b;
+              fo^o(b);
+            }
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "bar::", "c:@N at bar@F at foo#&1$@N at bar@S at BarType#")}
+      },
+      {
+        R"cpp( // Global value reference
+          int value;
+          void foo(int) { }
+          void bar() {
+            foo(val^ue);
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("value", "", "c:@value")}
+      },
+      {
+        R"cpp( // Local value reference
+          void foo() { int aaa; int bbb = aa^a; }
+        )cpp",
+        {CreateExpectedSymbolDetails("aaa", "foo", "c:TestTU.cpp at 49@F at foo#@aaa")}
+      },
+      {
+        R"cpp( // Function param
+          void bar(int aaa) {
+            int bbb = a^aa;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("aaa", "bar", "c:TestTU.cpp at 38@F at bar#I#@aaa")}
+      },
+      {
+        R"cpp( // Lambda capture
+          int ii;
+          auto lam = [ii]() {
+            return i^i;
+          };
+        )cpp",
+        {CreateExpectedSymbolDetails("ii", "", "c:@ii")}
+      },
+      {
+        R"cpp( // Macro reference
+          #define MACRO 5\nint i = MAC^RO;
+        )cpp",
+        {CreateExpectedSymbolDetails("MACRO", "", "c:TestTU.cpp at 55@macro at MACRO")}
+      },
+      {
+        R"cpp( // Multiple symbols returned - using overloaded function name
+          void foo() {}
+          void foo(bool) {}
+          void foo(int) {}
+          namespace bar {
+            using ::fo^o;
+          }
+        )cpp",
+        {
+          CreateExpectedSymbolDetails("foo", "", "c:@F at foo#"),
+          CreateExpectedSymbolDetails("foo", "", "c:@F at foo#b#"),
+          CreateExpectedSymbolDetails("foo", "", "c:@F at foo#I#")
+        }
+      },
+      {
+        R"cpp( // Multiple symbols returned - implicit conversion
+          struct foo {};
+          struct bar {
+            bar(const foo&) {}
+          };
+          void func_baz1(bar) {}
+          void func_baz2() {
+            foo ff;
+            func_baz1(f^f);
+          }
+        )cpp",
+        {
+          CreateExpectedSymbolDetails("ff", "func_baz2", "c:TestTU.cpp at 218@F at func_baz2#@ff"),
+          CreateExpectedSymbolDetails("bar", "bar::", "c:@S at bar@F at bar#&1$@S at foo#"),
+        }
+      },
+      {
+        R"cpp( // Type reference - declaration
+          struct foo;
+          void bar(fo^o*);
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@S at foo")}
+      },
+      {
+        R"cpp( // Type reference - definition
+          struct foo {};
+          void bar(fo^o*);
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@S at foo")}
+      },
+      {
+        R"cpp( // Type Reference - template argumen
+          struct foo {};
+          template<class T> struct bar {};
+          void baz() {
+            bar<fo^o> b;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@S at foo")}
+      },
+      {
+        R"cpp( // Template parameter reference - type param
+          template<class TT> struct bar {
+            T^T t;
+          };
+        )cpp",
+        { /* not implemented */ }
+      },
+      {
+        R"cpp( // Template parameter reference - type param
+          template<int NN> struct bar {
+            int a = N^N;
+          };
+        )cpp",
+        { /* not implemented */ }
+      },
+      {
+        R"cpp( // Class member reference - objec
+          struct foo {
+            int aa;
+          };
+          void bar() {
+            foo f;
+            f.a^a;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("aa", "foo::", "c:@S at foo@FI at aa")}
+      },
+      {
+        R"cpp( // Class member reference - pointer
+          struct foo {
+            int aa;
+          };
+          void bar() {
+            &foo::a^a;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("aa", "foo::", "c:@S at foo@FI at aa")}
+      },
+      {
+        R"cpp( // Class method reference - objec
+          struct foo {
+            void aa() {}
+          };
+          void bar() {
+            foo f;
+            f.a^a();
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("aa", "foo::", "c:@S at foo@F at aa#")}
+      },
+      {
+        R"cpp( // Class method reference - pointer
+          struct foo {
+            void aa() {}
+          };
+          void bar() {
+            &foo::a^a;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("aa", "foo::", "c:@S at foo@F at aa#")}
+      },
+      {
+        R"cpp( // Typedef
+          typedef int foo;
+          void bar() {
+            fo^o a;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:TestTU.cpp at T@foo")}
+      },
+      {
+        R"cpp( // Type alias
+          using foo = int;
+          void bar() {
+            fo^o a;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@foo")}
+      },
+      {
+        R"cpp( // Namespace reference
+          namespace foo {}
+          using namespace fo^o;
+        )cpp",
+        {CreateExpectedSymbolDetails("foo", "", "c:@N at foo")}
+      },
+      {
+        R"cpp( // Enum value reference
+          enum foo { bar, baz };
+          void f() {
+            foo fff = ba^r;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("bar", "foo", "c:@E at foo@bar")}
+      },
+      {
+        R"cpp( // Enum class value reference
+          enum class foo { bar, baz };
+          void f() {
+            foo fff = foo::ba^r;
+          }
+        )cpp",
+        {CreateExpectedSymbolDetails("bar", "foo::", "c:@E at foo@bar")}
+      },
+      {
+        R"cpp( // Type inferrence 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);
+    auto AST = TestTU::withCode(TestInput.code()).build();
+
+    EXPECT_THAT(getSymbolInfo(AST, TestInput.point()),
+                ElementsAreArray(T.second))
+        << T.first;
+  }
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang




More information about the cfe-commits mailing list