diff --git a/mlir/include/mlir/IR/SymbolTable.h b/mlir/include/mlir/IR/SymbolTable.h --- a/mlir/include/mlir/IR/SymbolTable.h +++ b/mlir/include/mlir/IR/SymbolTable.h @@ -212,6 +212,8 @@ unsigned uniquingCounter = 0; }; +raw_ostream &operator<<(raw_ostream &os, SymbolTable::Visibility visibility); + //===----------------------------------------------------------------------===// // SymbolTableCollection //===----------------------------------------------------------------------===// diff --git a/mlir/lib/IR/SymbolTable.cpp b/mlir/lib/IR/SymbolTable.cpp --- a/mlir/lib/IR/SymbolTable.cpp +++ b/mlir/lib/IR/SymbolTable.cpp @@ -375,6 +375,18 @@ 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 //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp --- a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp +++ b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp @@ -474,21 +474,34 @@ Optional 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 ®ion) { 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(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> regions; + for (Region ®ion : op.op->getRegions()) { + regions.emplace_back(std::make_unique()); + regions.back()->takeBody(region); + } + op.op->print( os, OpPrintingFlags().printGenericOpForm().elideLargeElementsAttrs()); os << "\n```\n"; + // Move the regions back to the current operation. + for (Region ®ion : op.op->getRegions()) + region.takeBody(*regions.back()); + return hover; } diff --git a/mlir/test/mlir-lsp-server/hover.test b/mlir/test/mlir-lsp-server/hover.test --- a/mlir/test/mlir-lsp-server/hover.test +++ b/mlir/test/mlir-lsp-server/hover.test @@ -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"}