[mlir-lsp-server] Add support for hover on region operations

This revision adds support for hover on region operations, by temporarily removing the regions during printing. This revision also tweaks the hover format for operations to include symbol information, now that FuncOp can be shown in the hover.

Differential Revision: https://reviews.llvm.org/D103727
This commit is contained in:
River Riddle 2021-06-07 13:59:39 -07:00
parent 17c43c4045
commit f492c35965
4 changed files with 67 additions and 16 deletions

View File

@ -212,6 +212,8 @@ private:
unsigned uniquingCounter = 0;
};
raw_ostream &operator<<(raw_ostream &os, SymbolTable::Visibility visibility);
//===----------------------------------------------------------------------===//
// SymbolTableCollection
//===----------------------------------------------------------------------===//

View File

@ -375,6 +375,18 @@ Operation *SymbolTable::lookupNearestSymbolFrom(Operation *from,
return symbolTableOp ? lookupSymbolIn(symbolTableOp, symbol) : nullptr;
}
raw_ostream &mlir::operator<<(raw_ostream &os,
SymbolTable::Visibility visibility) {
switch (visibility) {
case SymbolTable::Visibility::Public:
return os << "public";
case SymbolTable::Visibility::Private:
return os << "private";
case SymbolTable::Visibility::Nested:
return os << "nested";
}
}
//===----------------------------------------------------------------------===//
// SymbolTable Trait Types
//===----------------------------------------------------------------------===//

View File

@ -474,21 +474,34 @@ Optional<lsp::Hover> MLIRDocument::findHover(const lsp::URIForFile &uri,
Optional<lsp::Hover> MLIRDocument::buildHoverForOperation(
const AsmParserState::OperationDefinition &op) {
// Don't show hovers for operations with regions to avoid huge hover blocks.
// TODO: Should we add support for printing an op without its regions?
if (llvm::any_of(op.op->getRegions(),
[](Region &region) { return !region.empty(); }))
return llvm::None;
lsp::Hover hover(getRangeFromLoc(sourceMgr, op.loc));
llvm::raw_string_ostream os(hover.contents.value);
// For hovers on an operation, show the generic form.
os << "```mlir\n";
// Add the operation name to the hover.
os << "\"" << op.op->getName() << "\"";
if (SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(op.op))
os << " : " << symbol.getVisibility() << " @" << symbol.getName() << "";
os << "\n\n";
os << "Generic Form:\n\n```mlir\n";
// Temporary drop the regions of this operation so that they don't get
// printed in the output. This helps keeps the size of the output hover
// small.
SmallVector<std::unique_ptr<Region>> regions;
for (Region &region : op.op->getRegions()) {
regions.emplace_back(std::make_unique<Region>());
regions.back()->takeBody(region);
}
op.op->print(
os, OpPrintingFlags().printGenericOpForm().elideLargeElementsAttrs());
os << "\n```\n";
// Move the regions back to the current operation.
for (Region &region : op.op->getRegions())
region.takeBody(*regions.back());
return hover;
}

View File

@ -18,7 +18,7 @@
// CHECK-NEXT: "result": {
// CHECK-NEXT: "contents": {
// CHECK-NEXT: "kind": "markdown",
// CHECK-NEXT: "value": "```mlir\n%true = \"std.constant\"() {value = true} : () -> i1\n```\n"
// CHECK-NEXT: "value": "\"std.constant\"\n\nGeneric Form:\n\n```mlir\n%true = \"std.constant\"() {value = true} : () -> i1\n```\n"
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "end": {
@ -33,11 +33,11 @@
// CHECK-NEXT: }
// -----
// Hover on an operation result.
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{
{"jsonrpc":"2.0","id":2,"method":"textDocument/hover","params":{
"textDocument":{"uri":"test:///foo.mlir"},
"position":{"line":1,"character":2}
}}
// CHECK: "id": 1,
// CHECK: "id": 2,
// CHECK-NEXT: "jsonrpc": "2.0",
// CHECK-NEXT: "result": {
// CHECK-NEXT: "contents": {
@ -57,11 +57,11 @@
// CHECK-NEXT: }
// -----
// Hover on a Block.
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{
{"jsonrpc":"2.0","id":3,"method":"textDocument/hover","params":{
"textDocument":{"uri":"test:///foo.mlir"},
"position":{"line":3,"character":2}
}}
// CHECK: "id": 1,
// CHECK: "id": 3,
// CHECK-NEXT: "jsonrpc": "2.0",
// CHECK-NEXT: "result": {
// CHECK-NEXT: "contents": {
@ -81,11 +81,11 @@
// CHECK-NEXT: }
// -----
// Hover on a Block argument.
{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{
{"jsonrpc":"2.0","id":4,"method":"textDocument/hover","params":{
"textDocument":{"uri":"test:///foo.mlir"},
"position":{"line":0,"character":12}
}}
// CHECK: "id": 1,
// CHECK: "id": 4,
// CHECK-NEXT: "jsonrpc": "2.0",
// CHECK-NEXT: "result": {
// CHECK-NEXT: "contents": {
@ -104,6 +104,30 @@
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
// Hover on a region operation.
{"jsonrpc":"2.0","id":5,"method":"textDocument/hover","params":{
"textDocument":{"uri":"test:///foo.mlir"},
"position":{"line":0,"character":1}
}}
// CHECK: "id": 5,
// CHECK-NEXT: "jsonrpc": "2.0",
// CHECK-NEXT: "result": {
// CHECK-NEXT: "contents": {
// CHECK-NEXT: "kind": "markdown",
// CHECK-NEXT: "value": "\"func\" : public @foo\n\nGeneric Form:\n\n```mlir\n\"func\"() ( {\n}) {sym_name = \"foo\", type = (i1) -> ()} : () -> ()\n```\n"
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
// CHECK-NEXT: "end": {
// CHECK-NEXT: "character": 4,
// CHECK-NEXT: "line": 0
// CHECK-NEXT: },
// CHECK-NEXT: "start": {
// CHECK-NEXT: "character": 0,
// CHECK-NEXT: "line": 0
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----
{"jsonrpc":"2.0","id":6,"method":"shutdown"}
// -----
{"jsonrpc":"2.0","method":"exit"}