jkorous updated this revision to Diff 175229.
jkorous marked an inline comment as done.
jkorous added a comment.

Addressed comments from the reivew.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D54799/new/

https://reviews.llvm.org/D54799

Files:
  clangd/CMakeLists.txt
  clangd/ClangdLSPServer.cpp
  clangd/ClangdLSPServer.h
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/Protocol.cpp
  clangd/Protocol.h
  clangd/XRefs.cpp
  clangd/XRefs.h
  clangd/index/Index.cpp
  clangd/index/Index.h
  clangd/index/SymbolID.cpp
  clangd/index/SymbolID.h
  test/clangd/symbol-info.test

Index: test/clangd/symbol-info.test
===================================================================
--- /dev/null
+++ test/clangd/symbol-info.test
@@ -0,0 +1,46 @@
+# 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": "CA2EBE44A1D76D2A1547D47BC6D51EBF",
+# CHECK-NEXT:    "name": "foo",
+# CHECK-NEXT:    "usr": "c:@F@foo#"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///nested-decl.cpp","languageId":"cpp","version":1,"text":"namespace nnn { struct aaa {}; void foo() { aaa a; }; }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///nested-decl.cpp"},"position":{"line":0,"character":46}}}
+#      CHECK:    "containerName": "nnn::",
+# CHECK-NEXT:    "id": "20237FF18EB405D842456DC5D578426D",
+# CHECK-NEXT:    "name": "aaa",
+# CHECK-NEXT:    "usr": "c:@N@nnn@S@aaa"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///reference.cpp","languageId":"cpp","version":1,"text":"int value; void foo(int) {} void bar() { foo(value); }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///reference.cpp"},"position":{"line":0,"character":48}}}
+#      CHECK:    "containerName": null,
+# CHECK-NEXT:    "id": "844613FB2393C9D40A2AFF25D5D316A1",
+# CHECK-NEXT:    "name": "value",
+# CHECK-NEXT:    "usr": "c:@value"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///local.cpp","languageId":"cpp","version":1,"text":"void foo() { int aaa; int bbb = aaa; }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///local.cpp"},"position":{"line":0,"character":33}}}
+#      CHECK:    "containerName": "foo",
+# CHECK-NEXT:    "id": "C05589F2664B06F392C2C438568E55E0",
+# CHECK-NEXT:    "name": "aaa",
+# CHECK-NEXT:    "usr": "c:local.cpp@13@F@foo#@aaa"
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///macro.cpp","languageId":"cpp","version":1,"text":"#define MACRO 5\nint i = MACRO;"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///macro.cpp"},"position":{"line":1,"character":11}}}
+#      CHECK:    "containerName": null,
+# CHECK-NEXT:    "id": "29EB506CBDF1BA6D1B6EC203FF03B384",
+# CHECK-NEXT:    "name": "MACRO",
+# CHECK-NEXT:    "usr": "c:macro.cpp@24@macro@MACRO"
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
Index: clangd/index/SymbolID.h
===================================================================
--- /dev/null
+++ clangd/index/SymbolID.h
@@ -0,0 +1,67 @@
+//===--- SymbolID.h ----------------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLID_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLID_H
+
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <array>
+#include <string>
+
+namespace clang {
+namespace clangd {
+
+// The class identifies a particular C++ symbol (class, function, method, etc).
+//
+// As USRs (Unified Symbol Resolution) could be large, especially for functions
+// with long type arguments, SymbolID is using truncated SHA1(USR) values to
+// guarantee the uniqueness of symbols while using a relatively small amount of
+// memory (vs storing USRs directly).
+//
+// SymbolID can be used as key in the symbol indexes to lookup the symbol.
+class SymbolID {
+public:
+  SymbolID() = default;
+  explicit SymbolID(llvm::StringRef USR);
+
+  bool operator==(const SymbolID &Sym) const {
+    return HashValue == Sym.HashValue;
+  }
+  bool operator<(const SymbolID &Sym) const {
+    return HashValue < Sym.HashValue;
+  }
+
+  // The stored hash is truncated to RawSize bytes.
+  // This trades off memory against the number of symbols we can handle.
+  // FIXME: can we reduce this further to 8 bytes?
+  constexpr static size_t RawSize = 16;
+  llvm::StringRef raw() const;
+
+  static SymbolID fromRaw(llvm::StringRef);
+
+  // Returns a hex encoded string.
+  std::string str() const;
+  static llvm::Expected<SymbolID> fromStr(llvm::StringRef);
+
+private:
+  std::array<uint8_t, RawSize> HashValue;
+};
+
+llvm::hash_code hash_value(const SymbolID &ID);
+
+// Write SymbolID into the given stream. SymbolID is encoded as ID.str().
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolID &ID);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLID_H
Index: clangd/index/SymbolID.cpp
===================================================================
--- /dev/null
+++ clangd/index/SymbolID.cpp
@@ -0,0 +1,58 @@
+//===--- SymbolID.cpp --------------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolID.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+namespace clang {
+namespace clangd {
+
+SymbolID::SymbolID(StringRef USR) {
+  auto Hash = llvm::SHA1::hash(arrayRefFromStringRef(USR));
+  static_assert(sizeof(Hash) >= RawSize, "RawSize larger than SHA1");
+  memcpy(HashValue.data(), Hash.data(), RawSize);
+}
+
+llvm::StringRef SymbolID::raw() const {
+  return StringRef(reinterpret_cast<const char *>(HashValue.data()), RawSize);
+}
+
+SymbolID SymbolID::fromRaw(StringRef Raw) {
+  SymbolID ID;
+  assert(Raw.size() == RawSize);
+  memcpy(ID.HashValue.data(), Raw.data(), RawSize);
+  return ID;
+}
+
+std::string SymbolID::str() const { return toHex(raw()); }
+
+Expected<SymbolID> SymbolID::fromStr(StringRef Str) {
+  if (Str.size() != RawSize * 2)
+    return createStringError(inconvertibleErrorCode(), "Bad ID length");
+  for (char C : Str)
+    if (!isHexDigit(C))
+      return createStringError(inconvertibleErrorCode(), "Bad hex ID");
+  return fromRaw(fromHex(Str));
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolID &ID) {
+  return OS << toHex(ID.raw());
+}
+
+llvm::hash_code hash_value(const SymbolID &ID) {
+  // We already have a good hash, just return the first bytes.
+  assert(sizeof(size_t) <= SymbolID::RawSize && "size_t longer than SHA1!");
+  size_t Result;
+  memcpy(&Result, ID.raw().data(), sizeof(size_t));
+  return llvm::hash_code(Result);
+}
+
+} // namespace clangd
+} // namespace clang
Index: clangd/index/Index.h
===================================================================
--- clangd/index/Index.h
+++ clangd/index/Index.h
@@ -10,11 +10,11 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
 
+#include "SymbolID.h"
 #include "clang/Index/IndexSymbol.h"
 #include "clang/Lex/Lexer.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -94,54 +94,6 @@
 }
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolLocation &);
 
-// The class identifies a particular C++ symbol (class, function, method, etc).
-//
-// As USRs (Unified Symbol Resolution) could be large, especially for functions
-// with long type arguments, SymbolID is using truncated SHA1(USR) values to
-// guarantee the uniqueness of symbols while using a relatively small amount of
-// memory (vs storing USRs directly).
-//
-// SymbolID can be used as key in the symbol indexes to lookup the symbol.
-class SymbolID {
-public:
-  SymbolID() = default;
-  explicit SymbolID(llvm::StringRef USR);
-
-  bool operator==(const SymbolID &Sym) const {
-    return HashValue == Sym.HashValue;
-  }
-  bool operator<(const SymbolID &Sym) const {
-    return HashValue < Sym.HashValue;
-  }
-
-  // The stored hash is truncated to RawSize bytes.
-  // This trades off memory against the number of symbols we can handle.
-  // FIXME: can we reduce this further to 8 bytes?
-  constexpr static size_t RawSize = 16;
-  llvm::StringRef raw() const {
-    return StringRef(reinterpret_cast<const char *>(HashValue.data()), RawSize);
-  }
-  static SymbolID fromRaw(llvm::StringRef);
-
-  // Returns a hex encoded string.
-  std::string str() const;
-  static llvm::Expected<SymbolID> fromStr(llvm::StringRef);
-
-private:
-  std::array<uint8_t, RawSize> HashValue;
-};
-
-inline llvm::hash_code hash_value(const SymbolID &ID) {
-  // We already have a good hash, just return the first bytes.
-  assert(sizeof(size_t) <= SymbolID::RawSize && "size_t longer than SHA1!");
-  size_t Result;
-  memcpy(&Result, ID.raw().data(), sizeof(size_t));
-  return llvm::hash_code(Result);
-}
-
-// Write SymbolID into the given stream. SymbolID is encoded as ID.str().
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolID &ID);
-
 } // namespace clangd
 } // namespace clang
 namespace llvm {
Index: clangd/index/Index.cpp
===================================================================
--- clangd/index/Index.cpp
+++ clangd/index/Index.cpp
@@ -12,7 +12,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
-#include "llvm/Support/SHA1.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
@@ -43,34 +42,6 @@
             << "-" << L.End.line() << ":" << L.End.column() << ")";
 }
 
-SymbolID::SymbolID(StringRef USR) {
-  auto Hash = SHA1::hash(arrayRefFromStringRef(USR));
-  static_assert(sizeof(Hash) >= RawSize, "RawSize larger than SHA1");
-  memcpy(HashValue.data(), Hash.data(), RawSize);
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const SymbolID &ID) {
-  return OS << toHex(ID.raw());
-}
-
-SymbolID SymbolID::fromRaw(StringRef Raw) {
-  SymbolID ID;
-  assert(Raw.size() == RawSize);
-  memcpy(ID.HashValue.data(), Raw.data(), RawSize);
-  return ID;
-}
-
-std::string SymbolID::str() const { return toHex(raw()); }
-
-Expected<SymbolID> SymbolID::fromStr(StringRef Str) {
-  if (Str.size() != RawSize * 2)
-    return createStringError(inconvertibleErrorCode(), "Bad ID length");
-  for (char C : Str)
-    if (!isHexDigit(C))
-      return createStringError(inconvertibleErrorCode(), "Bad hex ID");
-  return fromRaw(fromHex(Str));
-}
-
 raw_ostream &operator<<(raw_ostream &OS, SymbolOrigin O) {
   if (O == SymbolOrigin::Unknown)
     return OS << "unknown";
Index: clangd/XRefs.h
===================================================================
--- clangd/XRefs.h
+++ clangd/XRefs.h
@@ -38,6 +38,9 @@
 std::vector<Location> findReferences(ParsedAST &AST, Position Pos,
                                      const SymbolIndex *Index = nullptr);
 
+/// Get info about symbols at \p Cursor.
+std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos);
+
 } // namespace clangd
 } // namespace clang
 
Index: clangd/XRefs.cpp
===================================================================
--- clangd/XRefs.cpp
+++ clangd/XRefs.cpp
@@ -153,6 +153,7 @@
       };
 
       bool IsExplicit = !hasImplicitExpr(ASTNode.OrigE);
+
       // Find and add definition declarations (for GoToDefinition).
       // We don't use parameter `D`, as Parameter `D` is the canonical
       // declaration, which is the first declaration of a redeclarable
@@ -749,5 +750,50 @@
   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()) {
+        StringRef ContainerNameRef = NewSymbol.containerName;
+        ContainerNameRef.consume_back("::");
+      } else 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
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -25,6 +25,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOL_H
 
 #include "URI.h"
+#include "index/SymbolID.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/JSON.h"
 #include <bitset>
@@ -673,6 +674,25 @@
 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 &);
+
 /// The parameters of a Workspace Symbol Request.
 struct WorkspaceSymbolParams {
   /// A non-empty query string
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -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"
@@ -422,6 +424,27 @@
   return O;
 }
 
+llvm::json::Value toJSON(const SymbolDetails &P) {
+  return json::Object{
+      {"name", !P.name.empty() ? llvm::json::Value(P.name)
+                               : llvm::json::Value(nullptr)},
+      {"containerName", !P.containerName.empty()
+                            ? llvm::json::Value(P.containerName)
+                            : llvm::json::Value(nullptr)},
+      {"usr",
+       !P.USR.empty() ? llvm::json::Value(P.USR) : llvm::json::Value(nullptr)},
+      {"id", P.ID.hasValue() ? llvm::json::Value(P.ID.getValue().str())
+                             : llvm::json::Value(nullptr)},
+  };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {
+  if (!S.containerName.empty())
+    O << S.containerName << "::";
+  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);
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -201,6 +201,10 @@
   /// Called when an event occurs for a watched file in the workspace.
   void onFileEvent(const DidChangeWatchedFilesParams &Params);
 
+  /// Get symbol info for given position.
+  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
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -517,6 +517,18 @@
   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();
Index: clangd/ClangdLSPServer.h
===================================================================
--- clangd/ClangdLSPServer.h
+++ clangd/ClangdLSPServer.h
@@ -88,6 +88,8 @@
   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);
 
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -685,6 +685,12 @@
                          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,
@@ -719,6 +725,7 @@
   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
 }
 
Index: clangd/CMakeLists.txt
===================================================================
--- clangd/CMakeLists.txt
+++ clangd/CMakeLists.txt
@@ -44,6 +44,7 @@
   index/IndexAction.cpp
   index/MemIndex.cpp
   index/Merge.cpp
+  index/SymbolID.cpp
   index/Serialization.cpp
   index/SymbolCollector.cpp
   index/YAMLSerialization.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to