sammccall created this revision.
sammccall added a reviewer: kadircet.
Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay, ioeric, 
ilya-biryukov.

Instead of parsing into structs that mirror LSP, simply parse into a flat struct
that contains the info we need.
This is an exception to our strategy with Protocol.h, which seems justified:

- the structure here is very large and deeply nested
- we care about almost none of it
- we should never have to serialize client capabilities


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D53266

Files:
  clangd/ClangdLSPServer.cpp
  clangd/Protocol.cpp
  clangd/Protocol.h

Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -221,18 +221,6 @@
   Incremental = 2,
 };
 
-struct CompletionItemClientCapabilities {
-  /// Client supports snippets as insert text.
-  bool snippetSupport = false;
-  /// Client supports commit characters on a completion item.
-  bool commitCharacterSupport = false;
-  // Client supports the follow content formats for the documentation property.
-  // The order describes the preferred format of the client.
-  // NOTE: not used by clangd at the moment.
-  // std::vector<MarkupKind> documentationFormat;
-};
-bool fromJSON(const llvm::json::Value &, CompletionItemClientCapabilities &);
-
 /// The kind of a completion entry.
 enum class CompletionItemKind {
   Missing = 0,
@@ -263,58 +251,16 @@
   TypeParameter = 25,
 };
 bool fromJSON(const llvm::json::Value &, CompletionItemKind &);
-
-struct CompletionItemKindCapabilities {
-  /// The CompletionItemKinds that the client supports. If not set, the client
-  /// only supports <= CompletionItemKind::Reference and will not fall back to a
-  /// valid default value.
-  llvm::Optional<std::vector<CompletionItemKind>> valueSet;
-};
-// Discards unknown CompletionItemKinds.
-bool fromJSON(const llvm::json::Value &, std::vector<CompletionItemKind> &);
-bool fromJSON(const llvm::json::Value &, CompletionItemKindCapabilities &);
-
 constexpr auto CompletionItemKindMin =
     static_cast<size_t>(CompletionItemKind::Text);
 constexpr auto CompletionItemKindMax =
     static_cast<size_t>(CompletionItemKind::TypeParameter);
 using CompletionItemKindBitset = std::bitset<CompletionItemKindMax + 1>;
+bool fromJSON(const llvm::json::Value &, CompletionItemKindBitset &);
 CompletionItemKind
 adjustKindToCapability(CompletionItemKind Kind,
                        CompletionItemKindBitset &supportedCompletionItemKinds);
 
-struct CompletionClientCapabilities {
-  /// Whether completion supports dynamic registration.
-  bool dynamicRegistration = false;
-  /// The client supports the following `CompletionItem` specific capabilities.
-  CompletionItemClientCapabilities completionItem;
-  /// The CompletionItemKinds that the client supports. If not set, the client
-  /// only supports <= CompletionItemKind::Reference and will not fall back to a
-  /// valid default value.
-  llvm::Optional<CompletionItemKindCapabilities> completionItemKind;
-
-  /// The client supports to send additional context information for a
-  /// `textDocument/completion` request.
-  bool contextSupport = false;
-};
-bool fromJSON(const llvm::json::Value &, CompletionClientCapabilities &);
-
-struct PublishDiagnosticsClientCapabilities {
-  // Whether the client accepts diagnostics with related information.
-  // NOTE: not used by clangd at the moment.
-  // bool relatedInformation;
-
-  /// Whether the client accepts diagnostics with fixes attached using the
-  /// "clangd_fixes" extension.
-  bool clangdFixSupport = false;
-
-  /// Whether the client accepts diagnostics with category attached to it
-  /// using the "category" extension.
-  bool categorySupport = false;
-};
-bool fromJSON(const llvm::json::Value &,
-              PublishDiagnosticsClientCapabilities &);
-
 /// A symbol kind.
 enum class SymbolKind {
   File = 1,
@@ -344,58 +290,40 @@
   Operator = 25,
   TypeParameter = 26
 };
-
+bool fromJSON(const llvm::json::Value &, SymbolKind &);
 constexpr auto SymbolKindMin = static_cast<size_t>(SymbolKind::File);
 constexpr auto SymbolKindMax = static_cast<size_t>(SymbolKind::TypeParameter);
 using SymbolKindBitset = std::bitset<SymbolKindMax + 1>;
-
-bool fromJSON(const llvm::json::Value &, SymbolKind &);
-
-struct SymbolKindCapabilities {
-  /// The SymbolKinds that the client supports. If not set, the client only
-  /// supports <= SymbolKind::Array and will not fall back to a valid default
-  /// value.
-  llvm::Optional<std::vector<SymbolKind>> valueSet;
-};
-// Discards unknown SymbolKinds.
-bool fromJSON(const llvm::json::Value &, std::vector<SymbolKind> &);
-bool fromJSON(const llvm::json::Value &, SymbolKindCapabilities &);
+bool fromJSON(const llvm::json::Value &, SymbolKindBitset &);
 SymbolKind adjustKindToCapability(SymbolKind Kind,
                                   SymbolKindBitset &supportedSymbolKinds);
 
-struct WorkspaceSymbolCapabilities {
-  /// Capabilities SymbolKind.
-  llvm::Optional<SymbolKindCapabilities> symbolKind;
-};
-bool fromJSON(const llvm::json::Value &, WorkspaceSymbolCapabilities &);
-
-// FIXME: most of the capabilities are missing from this struct. Only the ones
-// used by clangd are currently there.
-struct WorkspaceClientCapabilities {
-  /// Capabilities specific to `workspace/symbol`.
-  llvm::Optional<WorkspaceSymbolCapabilities> symbol;
-};
-bool fromJSON(const llvm::json::Value &, WorkspaceClientCapabilities &);
+// This struct doesn't mirror LSP!
+// The protocol defines deeply nested structures for client capabilities.
+// Instead of mapping them all, this just parses out the bits we care about.
+struct ClientCapabilities {
+  /// The supported set of SymbolKinds for workspace/symbol.
+  /// workspace.symbol.symbolKind.valueSet
+  llvm::Optional<SymbolKindBitset> WorkspaceSymbolKinds;
 
-// FIXME: most of the capabilities are missing from this struct. Only the ones
-// used by clangd are currently there.
-struct TextDocumentClientCapabilities {
-  /// Capabilities specific to the `textDocument/completion`
-  CompletionClientCapabilities completion;
+  /// Whether the client accepts diagnostics with fixes attached using the
+  /// "clangd_fixes" extension.
+  /// textDocument.publishDiagnostics.clangdFixSupport
+  bool DiagnosticFixes = false;
 
-  /// Capabilities specific to the 'textDocument/publishDiagnostics'
-  PublishDiagnosticsClientCapabilities publishDiagnostics;
-};
-bool fromJSON(const llvm::json::Value &, TextDocumentClientCapabilities &);
+  /// Whether the client accepts diagnostics with category attached to it
+  /// using the "category" extension.
+  /// textDocument.publishDiagnostics.categorySupport
+  bool DiagnosticCategory = false;
 
-struct ClientCapabilities {
-  // Workspace specific client capabilities.
-  llvm::Optional<WorkspaceClientCapabilities> workspace;
+  /// Client supports snippets as insert text.
+  /// textDocument.completion.completionItem.snippetSupport
+  bool CompletionSnippets = false;
 
-  // Text document specific client capabilities.
-  TextDocumentClientCapabilities textDocument;
+  /// The supported set of CompletionItemKinds for textDocument/completion.
+  /// textDocument.completion.completionItemKind.valueSet
+  llvm::Optional<CompletionItemKindBitset> CompletionItemKinds;
 };
-
 bool fromJSON(const llvm::json::Value &, ClientCapabilities &);
 
 /// Clangd extension that's used in the 'compilationDatabaseChanges' in
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -159,35 +159,6 @@
   return false;
 }
 
-bool fromJSON(const json::Value &Params, CompletionItemClientCapabilities &R) {
-  json::ObjectMapper O(Params);
-  if (!O)
-    return false;
-  O.map("snippetSupport", R.snippetSupport);
-  O.map("commitCharacterSupport", R.commitCharacterSupport);
-  return true;
-}
-
-bool fromJSON(const json::Value &Params, CompletionClientCapabilities &R) {
-  json::ObjectMapper O(Params);
-  if (!O)
-    return false;
-  O.map("dynamicRegistration", R.dynamicRegistration);
-  O.map("completionItem", R.completionItem);
-  O.map("contextSupport", R.contextSupport);
-  return true;
-}
-
-bool fromJSON(const llvm::json::Value &Params,
-              PublishDiagnosticsClientCapabilities &R) {
-  json::ObjectMapper O(Params);
-  if (!O)
-    return false;
-  O.map("clangdFixSupport", R.clangdFixSupport);
-  O.map("categorySupport", R.categorySupport);
-  return true;
-}
-
 bool fromJSON(const json::Value &E, SymbolKind &Out) {
   if (auto T = E.getAsInteger()) {
     if (*T < static_cast<int>(SymbolKind::File) ||
@@ -199,24 +170,18 @@
   return false;
 }
 
-bool fromJSON(const json::Value &E, std::vector<SymbolKind> &Out) {
+bool fromJSON(const json::Value &E, SymbolKindBitset &Out) {
   if (auto *A = E.getAsArray()) {
-    Out.clear();
     for (size_t I = 0; I < A->size(); ++I) {
       SymbolKind KindOut;
       if (fromJSON((*A)[I], KindOut))
-        Out.push_back(KindOut);
+        Out.set(size_t(KindOut));
     }
     return true;
   }
   return false;
 }
 
-bool fromJSON(const json::Value &Params, SymbolKindCapabilities &R) {
-  json::ObjectMapper O(Params);
-  return O && O.map("valueSet", R.valueSet);
-}
-
 SymbolKind adjustKindToCapability(SymbolKind Kind,
                                   SymbolKindBitset &SupportedSymbolKinds) {
   auto KindVal = static_cast<size_t>(Kind);
@@ -235,31 +200,42 @@
   }
 }
 
-bool fromJSON(const json::Value &Params, WorkspaceSymbolCapabilities &R) {
-  json::ObjectMapper O(Params);
-  return O && O.map("symbolKind", R.symbolKind);
-}
-
-bool fromJSON(const json::Value &Params, WorkspaceClientCapabilities &R) {
-  json::ObjectMapper O(Params);
-  return O && O.map("symbol", R.symbol);
-}
-
-bool fromJSON(const json::Value &Params, TextDocumentClientCapabilities &R) {
-  json::ObjectMapper O(Params);
-  if (!O)
-    return false;
-  O.map("completion", R.completion);
-  O.map("publishDiagnostics", R.publishDiagnostics);
-  return true;
-}
-
 bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
-  json::ObjectMapper O(Params);
+  const json::Object *O = Params.getAsObject();
   if (!O)
     return false;
-  O.map("textDocument", R.textDocument);
-  O.map("workspace", R.workspace);
+  if (auto *TextDocument = O->getObject("textDocument")) {
+    if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
+      if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
+        R.DiagnosticCategory = *CategorySupport;
+      if (auto ClangdFixSupport = Diagnostics->getBoolean("clangdFixSupport"))
+        R.DiagnosticFixes = *ClangdFixSupport;
+    }
+    if (auto *Completion = TextDocument->getObject("completion")) {
+      if (auto *Item = Completion->getObject("completionItem")) {
+        if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
+          R.CompletionSnippets = *SnippetSupport;
+      }
+      if (auto *ItemKind = Completion->getObject("completionItemKind")) {
+        if (auto *ValueSet = ItemKind->get("valueSet")) {
+          R.CompletionItemKinds.emplace();
+          if (!fromJSON(*ValueSet, *R.CompletionItemKinds))
+            return false;
+        }
+      }
+    }
+  }
+  if (auto *Workspace = O->getObject("workspace")) {
+    if (auto *Symbol = Workspace->getObject("symbol")) {
+      if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
+        if (auto *ValueSet = SymbolKind->get("valueSet")) {
+          R.WorkspaceSymbolKinds.emplace();
+          if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds))
+            return false;
+        }
+      }
+    }
+  }
   return true;
 }
 
@@ -529,24 +505,18 @@
   }
 }
 
-bool fromJSON(const json::Value &E, std::vector<CompletionItemKind> &Out) {
+bool fromJSON(const json::Value &E, CompletionItemKindBitset &Out) {
   if (auto *A = E.getAsArray()) {
-    Out.clear();
     for (size_t I = 0; I < A->size(); ++I) {
       CompletionItemKind KindOut;
       if (fromJSON((*A)[I], KindOut))
-        Out.push_back(KindOut);
+        Out.set(size_t(KindOut));
     }
     return true;
   }
   return false;
 }
 
-bool fromJSON(const json::Value &Params, CompletionItemKindCapabilities &R) {
-  json::ObjectMapper O(Params);
-  return O && O.map("valueSet", R.valueSet);
-}
-
 json::Value toJSON(const CompletionItem &CI) {
   assert(!CI.label.empty() && "completion item label is required");
   json::Object Result{{"label", CI.label}};
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -89,27 +89,13 @@
   else if (Params.rootPath && !Params.rootPath->empty())
     Server->setRootPath(*Params.rootPath);
 
-  CCOpts.EnableSnippets =
-      Params.capabilities.textDocument.completion.completionItem.snippetSupport;
-  DiagOpts.EmbedFixesInDiagnostics =
-      Params.capabilities.textDocument.publishDiagnostics.clangdFixSupport;
-  DiagOpts.SendDiagnosticCategory =
-      Params.capabilities.textDocument.publishDiagnostics.categorySupport;
-
-  if (Params.capabilities.workspace && Params.capabilities.workspace->symbol &&
-      Params.capabilities.workspace->symbol->symbolKind &&
-      Params.capabilities.workspace->symbol->symbolKind->valueSet) {
-    for (SymbolKind Kind :
-         *Params.capabilities.workspace->symbol->symbolKind->valueSet) {
-      SupportedSymbolKinds.set(static_cast<size_t>(Kind));
-    }
-  }
-
-  if (Params.capabilities.textDocument.completion.completionItemKind &&
-      Params.capabilities.textDocument.completion.completionItemKind->valueSet)
-    for (CompletionItemKind Kind : *Params.capabilities.textDocument.completion
-                                        .completionItemKind->valueSet)
-      SupportedCompletionItemKinds.set(static_cast<size_t>(Kind));
+  CCOpts.EnableSnippets = Params.capabilities.CompletionSnippets;
+  DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.DiagnosticFixes;
+  DiagOpts.SendDiagnosticCategory = Params.capabilities.DiagnosticCategory;
+  if (Params.capabilities.WorkspaceSymbolKinds)
+    SupportedSymbolKinds |= *Params.capabilities.WorkspaceSymbolKinds;
+  if (Params.capabilities.CompletionItemKinds)
+    SupportedCompletionItemKinds |= *Params.capabilities.CompletionItemKinds;
 
   reply(json::Object{
       {{"capabilities",
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to