[Mlir-commits] [mlir] 469c589 - [mlir][PDLL] Add signature help to the PDLL language server

River Riddle llvmlistbot at llvm.org
Sat Mar 19 13:29:37 PDT 2022


Author: River Riddle
Date: 2022-03-19T13:28:24-07:00
New Revision: 469c58944d4f0f990ca8ee88ebcc37624801a36c

URL: https://github.com/llvm/llvm-project/commit/469c58944d4f0f990ca8ee88ebcc37624801a36c
DIFF: https://github.com/llvm/llvm-project/commit/469c58944d4f0f990ca8ee88ebcc37624801a36c.diff

LOG: [mlir][PDLL] Add signature help to the PDLL language server

This commit adds signature support to the language server,
and initially supports providing help for: operation operands and results,
and constraint/rewrite calls.

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

Added: 
    mlir/test/mlir-pdll-lsp-server/signature-help.test

Modified: 
    mlir/include/mlir/Tools/PDLL/Parser/CodeComplete.h
    mlir/lib/Tools/PDLL/Parser/Parser.cpp
    mlir/lib/Tools/lsp-server-support/Protocol.cpp
    mlir/lib/Tools/lsp-server-support/Protocol.h
    mlir/lib/Tools/mlir-pdll-lsp-server/LSPServer.cpp
    mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
    mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
    mlir/test/mlir-pdll-lsp-server/initialize-params.test

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Tools/PDLL/Parser/CodeComplete.h b/mlir/include/mlir/Tools/PDLL/Parser/CodeComplete.h
index f97310b3ecbeb..7867bda9a3a3a 100644
--- a/mlir/include/mlir/Tools/PDLL/Parser/CodeComplete.h
+++ b/mlir/include/mlir/Tools/PDLL/Parser/CodeComplete.h
@@ -66,6 +66,24 @@ class CodeCompleteContext {
   /// Signal code completion for Pattern metadata.
   virtual void codeCompletePatternMetadata() {}
 
+  //===--------------------------------------------------------------------===//
+  // Signature Hooks
+  //===--------------------------------------------------------------------===//
+
+  /// Signal code completion for the signature of a callable.
+  virtual void codeCompleteCallSignature(const ast::CallableDecl *callable,
+                                         unsigned currentNumArgs) {}
+
+  /// Signal code completion for the signature of an operation's operands.
+  virtual void
+  codeCompleteOperationOperandsSignature(Optional<StringRef> opName,
+                                         unsigned currentNumOperands) {}
+
+  /// Signal code completion for the signature of an operation's results.
+  virtual void
+  codeCompleteOperationResultsSignature(Optional<StringRef> opName,
+                                        unsigned currentNumResults) {}
+
 protected:
   /// Create a new code completion context with the given code complete
   /// location.

diff  --git a/mlir/lib/Tools/PDLL/Parser/Parser.cpp b/mlir/lib/Tools/PDLL/Parser/Parser.cpp
index 3d1f2dc3ce6fe..1bb23da08b4ad 100644
--- a/mlir/lib/Tools/PDLL/Parser/Parser.cpp
+++ b/mlir/lib/Tools/PDLL/Parser/Parser.cpp
@@ -425,6 +425,12 @@ class Parser {
   LogicalResult codeCompleteOperationName(StringRef dialectName);
   LogicalResult codeCompletePatternMetadata();
 
+  void codeCompleteCallSignature(ast::Node *parent, unsigned currentNumArgs);
+  void codeCompleteOperationOperandsSignature(Optional<StringRef> opName,
+                                              unsigned currentNumOperands);
+  void codeCompleteOperationResultsSignature(Optional<StringRef> opName,
+                                             unsigned currentNumResults);
+
   //===--------------------------------------------------------------------===//
   // Lexer Utilities
   //===--------------------------------------------------------------------===//
@@ -1762,6 +1768,12 @@ FailureOr<ast::Expr *> Parser::parseCallExpr(ast::Expr *parentExpr) {
   SmallVector<ast::Expr *> arguments;
   if (curToken.isNot(Token::r_paren)) {
     do {
+      // Handle code completion for the call arguments.
+      if (curToken.is(Token::code_complete)) {
+        codeCompleteCallSignature(parentExpr, arguments.size());
+        return failure();
+      }
+
       FailureOr<ast::Expr *> argument = parseExpr();
       if (failed(argument))
         return failure();
@@ -1933,6 +1945,12 @@ FailureOr<ast::Expr *> Parser::parseOperationExpr() {
           ast::ValueRangeConstraintDecl::create(ctx, loc), valueRangeTy));
     }
   } else if (!consumeIf(Token::r_paren)) {
+    // Check for operand signature code completion.
+    if (curToken.is(Token::code_complete)) {
+      codeCompleteOperationOperandsSignature(opName, operands.size());
+      return failure();
+    }
+
     // If the operand list was specified and non-empty, parse the operands.
     do {
       FailureOr<ast::Expr *> operand = parseExpr();
@@ -1972,6 +1990,12 @@ FailureOr<ast::Expr *> Parser::parseOperationExpr() {
     // Handle the case of an empty result list.
     if (!consumeIf(Token::r_paren)) {
       do {
+        // Check for result signature code completion.
+        if (curToken.is(Token::code_complete)) {
+          codeCompleteOperationResultsSignature(opName, resultTypes.size());
+          return failure();
+        }
+
         FailureOr<ast::Expr *> resultTypeExpr = parseExpr();
         if (failed(resultTypeExpr))
           return failure();
@@ -2899,6 +2923,27 @@ LogicalResult Parser::codeCompletePatternMetadata() {
   return failure();
 }
 
+void Parser::codeCompleteCallSignature(ast::Node *parent,
+                                       unsigned currentNumArgs) {
+  ast::CallableDecl *callableDecl = tryExtractCallableDecl(parent);
+  if (!callableDecl)
+    return;
+
+  codeCompleteContext->codeCompleteCallSignature(callableDecl, currentNumArgs);
+}
+
+void Parser::codeCompleteOperationOperandsSignature(
+    Optional<StringRef> opName, unsigned currentNumOperands) {
+  codeCompleteContext->codeCompleteOperationOperandsSignature(
+      opName, currentNumOperands);
+}
+
+void Parser::codeCompleteOperationResultsSignature(Optional<StringRef> opName,
+                                                   unsigned currentNumResults) {
+  codeCompleteContext->codeCompleteOperationResultsSignature(opName,
+                                                             currentNumResults);
+}
+
 //===----------------------------------------------------------------------===//
 // Parser
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/lib/Tools/lsp-server-support/Protocol.cpp b/mlir/lib/Tools/lsp-server-support/Protocol.cpp
index 2b9ba3b853f7f..74b270530687d 100644
--- a/mlir/lib/Tools/lsp-server-support/Protocol.cpp
+++ b/mlir/lib/Tools/lsp-server-support/Protocol.cpp
@@ -742,3 +742,57 @@ bool mlir::lsp::fromJSON(const llvm::json::Value &value,
     return fromJSON(*context, result.context, path.field("context"));
   return true;
 }
+
+//===----------------------------------------------------------------------===//
+// ParameterInformation
+//===----------------------------------------------------------------------===//
+
+llvm::json::Value mlir::lsp::toJSON(const ParameterInformation &value) {
+  assert((value.labelOffsets.hasValue() || !value.labelString.empty()) &&
+         "parameter information label is required");
+  llvm::json::Object result;
+  if (value.labelOffsets)
+    result["label"] = llvm::json::Array(
+        {value.labelOffsets->first, value.labelOffsets->second});
+  else
+    result["label"] = value.labelString;
+  if (!value.documentation.empty())
+    result["documentation"] = value.documentation;
+  return std::move(result);
+}
+
+//===----------------------------------------------------------------------===//
+// SignatureInformation
+//===----------------------------------------------------------------------===//
+
+llvm::json::Value mlir::lsp::toJSON(const SignatureInformation &value) {
+  assert(!value.label.empty() && "signature information label is required");
+  llvm::json::Object result{
+      {"label", value.label},
+      {"parameters", llvm::json::Array(value.parameters)},
+  };
+  if (!value.documentation.empty())
+    result["documentation"] = value.documentation;
+  return std::move(result);
+}
+
+raw_ostream &mlir::lsp::operator<<(raw_ostream &os,
+                                   const SignatureInformation &value) {
+  return os << value.label << " - " << toJSON(value);
+}
+
+//===----------------------------------------------------------------------===//
+// SignatureHelp
+//===----------------------------------------------------------------------===//
+
+llvm::json::Value mlir::lsp::toJSON(const SignatureHelp &value) {
+  assert(value.activeSignature >= 0 &&
+         "Unexpected negative value for number of active signatures.");
+  assert(value.activeParameter >= 0 &&
+         "Unexpected negative value for active parameter index");
+  return llvm::json::Object{
+      {"activeSignature", value.activeSignature},
+      {"activeParameter", value.activeParameter},
+      {"signatures", llvm::json::Array(value.signatures)},
+  };
+}

diff  --git a/mlir/lib/Tools/lsp-server-support/Protocol.h b/mlir/lib/Tools/lsp-server-support/Protocol.h
index cc8c52abb104e..61eff181bf465 100644
--- a/mlir/lib/Tools/lsp-server-support/Protocol.h
+++ b/mlir/lib/Tools/lsp-server-support/Protocol.h
@@ -871,6 +871,65 @@ struct CompletionParams : TextDocumentPositionParams {
 bool fromJSON(const llvm::json::Value &value, CompletionParams &result,
               llvm::json::Path path);
 
+//===----------------------------------------------------------------------===//
+// ParameterInformation
+//===----------------------------------------------------------------------===//
+
+/// A single parameter of a particular signature.
+struct ParameterInformation {
+  /// The label of this parameter. Ignored when labelOffsets is set.
+  std::string labelString;
+
+  /// Inclusive start and exclusive end offsets withing the containing signature
+  /// label.
+  Optional<std::pair<unsigned, unsigned>> labelOffsets;
+
+  /// The documentation of this parameter. Optional.
+  std::string documentation;
+};
+
+/// Add support for JSON serialization.
+llvm::json::Value toJSON(const ParameterInformation &value);
+
+//===----------------------------------------------------------------------===//
+// SignatureInformation
+//===----------------------------------------------------------------------===//
+
+/// Represents the signature of something callable.
+struct SignatureInformation {
+  /// The label of this signature. Mandatory.
+  std::string label;
+
+  /// The documentation of this signature. Optional.
+  std::string documentation;
+
+  /// The parameters of this signature.
+  std::vector<ParameterInformation> parameters;
+};
+
+/// Add support for JSON serialization.
+llvm::json::Value toJSON(const SignatureInformation &value);
+raw_ostream &operator<<(raw_ostream &os, const SignatureInformation &value);
+
+//===----------------------------------------------------------------------===//
+// SignatureHelp
+//===----------------------------------------------------------------------===//
+
+/// Represents the signature of a callable.
+struct SignatureHelp {
+  /// The resulting signatures.
+  std::vector<SignatureInformation> signatures;
+
+  /// The active signature.
+  int activeSignature = 0;
+
+  /// The active parameter of the active signature.
+  int activeParameter = 0;
+};
+
+/// Add support for JSON serialization.
+llvm::json::Value toJSON(const SignatureHelp &value);
+
 } // namespace lsp
 } // namespace mlir
 

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/LSPServer.cpp b/mlir/lib/Tools/mlir-pdll-lsp-server/LSPServer.cpp
index 57280e0bdd171..041ad7ad9ab05 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/LSPServer.cpp
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/LSPServer.cpp
@@ -70,6 +70,12 @@ struct LSPServer {
   void onCompletion(const CompletionParams &params,
                     Callback<CompletionList> reply);
 
+  //===--------------------------------------------------------------------===//
+  // Signature Help
+
+  void onSignatureHelp(const TextDocumentPositionParams &params,
+                       Callback<SignatureHelp> reply);
+
   //===--------------------------------------------------------------------===//
   // Fields
   //===--------------------------------------------------------------------===//
@@ -109,6 +115,10 @@ void LSPServer::onInitialize(const InitializeParams &params,
            {"resolveProvider", false},
            {"triggerCharacters", {".", ">", "(", "{", ",", "<", ":", "[", " "}},
        }},
+      {"signatureHelpProvider",
+       llvm::json::Object{
+           {"triggerCharacters", {"(", ","}},
+       }},
       {"definitionProvider", true},
       {"referencesProvider", true},
       {"hoverProvider", true},
@@ -209,6 +219,14 @@ void LSPServer::onCompletion(const CompletionParams &params,
   reply(server.getCodeCompletion(params.textDocument.uri, params.position));
 }
 
+//===----------------------------------------------------------------------===//
+// Signature Help
+
+void LSPServer::onSignatureHelp(const TextDocumentPositionParams &params,
+                                Callback<SignatureHelp> reply) {
+  reply(server.getSignatureHelp(params.textDocument.uri, params.position));
+}
+
 //===----------------------------------------------------------------------===//
 // Entry Point
 //===----------------------------------------------------------------------===//
@@ -249,6 +267,10 @@ LogicalResult mlir::lsp::runPdllLSPServer(PDLLServer &server,
   messageHandler.method("textDocument/completion", &lspServer,
                         &LSPServer::onCompletion);
 
+  // Signature Help
+  messageHandler.method("textDocument/signatureHelp", &lspServer,
+                        &LSPServer::onSignatureHelp);
+
   // Diagnostics
   lspServer.publishDiagnostics =
       messageHandler.outgoingNotification<PublishDiagnosticsParams>(

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
index 495df9019a174..4a8f85a6e02f2 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
@@ -285,6 +285,13 @@ struct PDLDocument {
   lsp::CompletionList getCodeCompletion(const lsp::URIForFile &uri,
                                         const lsp::Position &completePos);
 
+  //===--------------------------------------------------------------------===//
+  // Signature Help
+  //===--------------------------------------------------------------------===//
+
+  lsp::SignatureHelp getSignatureHelp(const lsp::URIForFile &uri,
+                                      const lsp::Position &helpPos);
+
   //===--------------------------------------------------------------------===//
   // Fields
   //===--------------------------------------------------------------------===//
@@ -827,6 +834,154 @@ PDLDocument::getCodeCompletion(const lsp::URIForFile &uri,
   return completionList;
 }
 
+//===----------------------------------------------------------------------===//
+// PDLDocument: Signature Help
+//===----------------------------------------------------------------------===//
+
+namespace {
+class LSPSignatureHelpContext : public CodeCompleteContext {
+public:
+  LSPSignatureHelpContext(SMLoc completeLoc, lsp::SignatureHelp &signatureHelp,
+                          ods::Context &odsContext)
+      : CodeCompleteContext(completeLoc), signatureHelp(signatureHelp),
+        odsContext(odsContext) {}
+
+  void codeCompleteCallSignature(const ast::CallableDecl *callable,
+                                 unsigned currentNumArgs) final {
+    signatureHelp.activeParameter = currentNumArgs;
+
+    lsp::SignatureInformation signatureInfo;
+    {
+      llvm::raw_string_ostream strOS(signatureInfo.label);
+      strOS << callable->getName()->getName() << "(";
+      auto formatParamFn = [&](const ast::VariableDecl *var) {
+        unsigned paramStart = strOS.str().size();
+        strOS << var->getName().getName() << ": " << var->getType();
+        unsigned paramEnd = strOS.str().size();
+        signatureInfo.parameters.emplace_back(lsp::ParameterInformation{
+            StringRef(strOS.str()).slice(paramStart, paramEnd).str(),
+            std::make_pair(paramStart, paramEnd), /*paramDoc*/ std::string()});
+      };
+      llvm::interleaveComma(callable->getInputs(), strOS, formatParamFn);
+      strOS << ") -> " << callable->getResultType();
+    }
+    signatureHelp.signatures.emplace_back(std::move(signatureInfo));
+  }
+
+  void
+  codeCompleteOperationOperandsSignature(Optional<StringRef> opName,
+                                         unsigned currentNumOperands) final {
+    const ods::Operation *odsOp =
+        opName ? odsContext.lookupOperation(*opName) : nullptr;
+    codeCompleteOperationOperandOrResultSignature(
+        opName, odsOp, odsOp ? odsOp->getOperands() : llvm::None,
+        currentNumOperands, "operand", "Value");
+  }
+
+  void codeCompleteOperationResultsSignature(Optional<StringRef> opName,
+                                             unsigned currentNumResults) final {
+    const ods::Operation *odsOp =
+        opName ? odsContext.lookupOperation(*opName) : nullptr;
+    codeCompleteOperationOperandOrResultSignature(
+        opName, odsOp, odsOp ? odsOp->getResults() : llvm::None,
+        currentNumResults, "result", "Type");
+  }
+
+  void codeCompleteOperationOperandOrResultSignature(
+      Optional<StringRef> opName, const ods::Operation *odsOp,
+      ArrayRef<ods::OperandOrResult> values, unsigned currentValue,
+      StringRef label, StringRef dataType) {
+    signatureHelp.activeParameter = currentValue;
+
+    // If we have ODS information for the operation, add in the ODS signature
+    // for the operation. We also verify that the current number of values is
+    // not more than what is defined in ODS, as this will result in an error
+    // anyways.
+    if (odsOp && currentValue < values.size()) {
+      lsp::SignatureInformation signatureInfo;
+
+      // Build the signature label.
+      {
+        llvm::raw_string_ostream strOS(signatureInfo.label);
+        strOS << "(";
+        auto formatFn = [&](const ods::OperandOrResult &value) {
+          unsigned paramStart = strOS.str().size();
+
+          strOS << value.getName() << ": ";
+
+          StringRef constraintDoc = value.getConstraint().getSummary();
+          std::string paramDoc;
+          switch (value.getVariableLengthKind()) {
+          case ods::VariableLengthKind::Single:
+            strOS << dataType;
+            paramDoc = constraintDoc.str();
+            break;
+          case ods::VariableLengthKind::Optional:
+            strOS << dataType << "?";
+            paramDoc = ("optional: " + constraintDoc).str();
+            break;
+          case ods::VariableLengthKind::Variadic:
+            strOS << dataType << "Range";
+            paramDoc = ("variadic: " + constraintDoc).str();
+            break;
+          }
+
+          unsigned paramEnd = strOS.str().size();
+          signatureInfo.parameters.emplace_back(lsp::ParameterInformation{
+              StringRef(strOS.str()).slice(paramStart, paramEnd).str(),
+              std::make_pair(paramStart, paramEnd), paramDoc});
+        };
+        llvm::interleaveComma(values, strOS, formatFn);
+        strOS << ")";
+      }
+      signatureInfo.documentation =
+          llvm::formatv("`op<{0}>` ODS {1} specification", *opName, label)
+              .str();
+      signatureHelp.signatures.emplace_back(std::move(signatureInfo));
+    }
+
+    // If there aren't any arguments yet, we also add the generic signature.
+    if (currentValue == 0 && (!odsOp || !values.empty())) {
+      lsp::SignatureInformation signatureInfo;
+      signatureInfo.label =
+          llvm::formatv("(<{0}s>: {1}Range)", label, dataType).str();
+      signatureInfo.documentation =
+          ("Generic operation " + label + " specification").str();
+      signatureInfo.parameters.emplace_back(lsp::ParameterInformation{
+          StringRef(signatureInfo.label).drop_front().drop_back().str(),
+          std::pair<unsigned, unsigned>(1, signatureInfo.label.size() - 1),
+          ("All of the " + label + "s of the operation.").str()});
+      signatureHelp.signatures.emplace_back(std::move(signatureInfo));
+    }
+  }
+
+private:
+  lsp::SignatureHelp &signatureHelp;
+  ods::Context &odsContext;
+};
+} // namespace
+
+lsp::SignatureHelp PDLDocument::getSignatureHelp(const lsp::URIForFile &uri,
+                                                 const lsp::Position &helpPos) {
+  SMLoc posLoc = helpPos.getAsSMLoc(sourceMgr);
+  if (!posLoc.isValid())
+    return lsp::SignatureHelp();
+
+  // Adjust the position one further to after the completion trigger token.
+  posLoc = SMLoc::getFromPointer(posLoc.getPointer() + 1);
+
+  // To perform code completion, we run another parse of the module with the
+  // code completion context provided.
+  ods::Context tmpODSContext;
+  lsp::SignatureHelp signatureHelp;
+  LSPSignatureHelpContext completeContext(posLoc, signatureHelp, tmpODSContext);
+
+  ast::Context tmpContext(tmpODSContext);
+  (void)parsePDLAST(tmpContext, sourceMgr, &completeContext);
+
+  return signatureHelp;
+}
+
 //===----------------------------------------------------------------------===//
 // PDLTextFileChunk
 //===----------------------------------------------------------------------===//
@@ -883,6 +1038,8 @@ class PDLTextFile {
   void findDocumentSymbols(std::vector<lsp::DocumentSymbol> &symbols);
   lsp::CompletionList getCodeCompletion(const lsp::URIForFile &uri,
                                         lsp::Position completePos);
+  lsp::SignatureHelp getSignatureHelp(const lsp::URIForFile &uri,
+                                      lsp::Position helpPos);
 
 private:
   /// Find the PDL document that contains the given position, and update the
@@ -1036,6 +1193,11 @@ lsp::CompletionList PDLTextFile::getCodeCompletion(const lsp::URIForFile &uri,
   return completionList;
 }
 
+lsp::SignatureHelp PDLTextFile::getSignatureHelp(const lsp::URIForFile &uri,
+                                                 lsp::Position helpPos) {
+  return getChunkFor(helpPos).document.getSignatureHelp(uri, helpPos);
+}
+
 PDLTextFileChunk &PDLTextFile::getChunkFor(lsp::Position &pos) {
   if (chunks.size() == 1)
     return *chunks.front();
@@ -1123,3 +1285,11 @@ lsp::PDLLServer::getCodeCompletion(const URIForFile &uri,
     return fileIt->second->getCodeCompletion(uri, completePos);
   return CompletionList();
 }
+
+lsp::SignatureHelp lsp::PDLLServer::getSignatureHelp(const URIForFile &uri,
+                                                     const Position &helpPos) {
+  auto fileIt = impl->files.find(uri.file());
+  if (fileIt != impl->files.end())
+    return fileIt->second->getSignatureHelp(uri, helpPos);
+  return SignatureHelp();
+}

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
index 5f593204bab24..ab0ad48615eb1 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
@@ -20,6 +20,7 @@ struct DocumentSymbol;
 struct Hover;
 struct Location;
 struct Position;
+struct SignatureHelp;
 class URIForFile;
 
 /// This class implements all of the PDLL related functionality necessary for a
@@ -62,6 +63,10 @@ class PDLLServer {
   CompletionList getCodeCompletion(const URIForFile &uri,
                                    const Position &completePos);
 
+  /// Get the signature help for the position within the given file.
+  SignatureHelp getSignatureHelp(const URIForFile &uri,
+                                 const Position &helpPos);
+
 private:
   struct Impl;
 

diff  --git a/mlir/test/mlir-pdll-lsp-server/initialize-params.test b/mlir/test/mlir-pdll-lsp-server/initialize-params.test
index 2d40edfaa7bc5..3a5c59140b78b 100644
--- a/mlir/test/mlir-pdll-lsp-server/initialize-params.test
+++ b/mlir/test/mlir-pdll-lsp-server/initialize-params.test
@@ -16,6 +16,12 @@
 // CHECK-NEXT:      "documentSymbolProvider": true,
 // CHECK-NEXT:      "hoverProvider": true,
 // CHECK-NEXT:      "referencesProvider": true,
+// CHECK-NEXT:      "signatureHelpProvider": {
+// CHECK-NEXT:        "triggerCharacters": [
+// CHECK-NEXT:          "(",
+// CHECK-NEXT:          ","
+// CHECK-NEXT:        ]
+// CHECK-NEXT:      },
 // CHECK-NEXT:      "textDocumentSync": {
 // CHECK-NEXT:        "change": 1,
 // CHECK-NEXT:        "openClose": true,

diff  --git a/mlir/test/mlir-pdll-lsp-server/signature-help.test b/mlir/test/mlir-pdll-lsp-server/signature-help.test
new file mode 100644
index 0000000000000..30423ea4b6eb8
--- /dev/null
+++ b/mlir/test/mlir-pdll-lsp-server/signature-help.test
@@ -0,0 +1,89 @@
+// RUN: mlir-pdll-lsp-server -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"pdll","capabilities":{},"trace":"off"}}
+// -----
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
+  "uri":"test:///foo.pdll",
+  "languageId":"pdll",
+  "version":1,
+  "text":"Constraint ValueCst(value: Value);\nPattern {\nlet root = op<test.op>() -> ();\nValueCst(root);\nerase root;\n}"
+}}}
+// -----
+{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{
+  "textDocument":{"uri":"test:///foo.pdll"},
+  "position":{"line":2,"character":23}
+}}
+//      CHECK:  "id": 1
+// CHECK-NEXT:  "jsonrpc": "2.0",
+// CHECK-NEXT:  "result": {
+// CHECK-NEXT:    "activeParameter": 0,
+// CHECK-NEXT:    "activeSignature": 0,
+// CHECK-NEXT:    "signatures": [
+// CHECK-NEXT:      {
+// CHECK-NEXT:        "documentation": "Generic operation operand specification",
+// CHECK-NEXT:        "label": "(<operands>: ValueRange)",
+// CHECK-NEXT:        "parameters": [
+// CHECK-NEXT:          {
+// CHECK-NEXT:            "documentation": "All of the operands of the operation.",
+// CHECK-NEXT:            "label": [
+// CHECK-NEXT:              1,
+// CHECK-NEXT:              23
+// CHECK-NEXT:            ]
+// CHECK-NEXT:          }
+// CHECK-NEXT:        ]
+// CHECK-NEXT:      }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:  }
+// -----
+{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{
+  "textDocument":{"uri":"test:///foo.pdll"},
+  "position":{"line":2,"character":29}
+}}
+//      CHECK:  "id": 1
+// CHECK-NEXT:  "jsonrpc": "2.0",
+// CHECK-NEXT:  "result": {
+// CHECK-NEXT:    "activeParameter": 0,
+// CHECK-NEXT:    "activeSignature": 0,
+// CHECK-NEXT:    "signatures": [
+// CHECK-NEXT:      {
+// CHECK-NEXT:        "documentation": "Generic operation result specification",
+// CHECK-NEXT:        "label": "(<results>: TypeRange)",
+// CHECK-NEXT:        "parameters": [
+// CHECK-NEXT:          {
+// CHECK-NEXT:            "documentation": "All of the results of the operation.",
+// CHECK-NEXT:            "label": [
+// CHECK-NEXT:              1,
+// CHECK-NEXT:              21
+// CHECK-NEXT:            ]
+// CHECK-NEXT:          }
+// CHECK-NEXT:        ]
+// CHECK-NEXT:      }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:  }
+// -----
+{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{
+  "textDocument":{"uri":"test:///foo.pdll"},
+  "position":{"line":3,"character":9}
+}}
+//      CHECK:  "id": 1
+// CHECK-NEXT:  "jsonrpc": "2.0",
+// CHECK-NEXT:  "result": {
+// CHECK-NEXT:    "activeParameter": 0,
+// CHECK-NEXT:    "activeSignature": 0,
+// CHECK-NEXT:    "signatures": [
+// CHECK-NEXT:      {
+// CHECK-NEXT:        "label": "ValueCst(value: Value) -> Tuple<>",
+// CHECK-NEXT:        "parameters": [
+// CHECK-NEXT:          {
+// CHECK-NEXT:            "label": [
+// CHECK-NEXT:              9,
+// CHECK-NEXT:              21
+// CHECK-NEXT:            ]
+// CHECK-NEXT:          }
+// CHECK-NEXT:        ]
+// CHECK-NEXT:      }
+// CHECK-NEXT:    ]
+// CHECK-NEXT:  }
+// -----
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+// -----
+{"jsonrpc":"2.0","method":"exit"}


        


More information about the Mlir-commits mailing list