diff --git a/mlir/include/mlir/AsmParser/AsmParserState.h b/mlir/include/mlir/AsmParser/AsmParserState.h --- a/mlir/include/mlir/AsmParser/AsmParserState.h +++ b/mlir/include/mlir/AsmParser/AsmParserState.h @@ -9,10 +9,8 @@ #ifndef MLIR_ASMPARSER_ASMPARSERSTATE_H #define MLIR_ASMPARSER_ASMPARSERSTATE_H -#include "mlir/Support/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" +#include "mlir/IR/Attributes.h" +#include "mlir/IR/Types.h" #include "llvm/Support/SMLoc.h" #include @@ -98,27 +96,34 @@ /// This class represents the information for an attribute alias definition /// within the input file. struct AttributeAliasDefinition { - AttributeAliasDefinition(StringRef name, SMRange loc = {}) - : name(name), definition(loc) {} + AttributeAliasDefinition(StringRef name, SMRange loc = {}, + Attribute value = {}) + : name(name), definition(loc), value(value) {} /// The name of the attribute alias. StringRef name; /// The source location for the alias. SMDefinition definition; + + /// The value of the alias. + Attribute value; }; /// This class represents the information for type definition within the input /// file. struct TypeAliasDefinition { - TypeAliasDefinition(StringRef name, SMRange loc) - : name(name), definition(loc) {} + TypeAliasDefinition(StringRef name, SMRange loc, Type value) + : name(name), definition(loc), value(value) {} /// The name of the attribute alias. StringRef name; /// The source location for the alias. SMDefinition definition; + + /// The value of the alias. + Type value; }; AsmParserState(); @@ -133,6 +138,10 @@ ArrayRef>::iterator>; using OperationDefIterator = llvm::pointee_iterator< ArrayRef>::iterator>; + using AttributeDefIterator = llvm::pointee_iterator< + ArrayRef>::iterator>; + using TypeDefIterator = llvm::pointee_iterator< + ArrayRef>::iterator>; /// Return a range of the BlockDefinitions held by the current parser state. iterator_range getBlockDefs() const; @@ -149,6 +158,22 @@ /// operation does not have a definition. const OperationDefinition *getOpDef(Operation *op) const; + /// Return a range of the AttributeAliasDefinitions held by the current parser + /// state. + iterator_range getAttributeAliasDefs() const; + + /// Return the definition for the given attribute alias, or nullptr if the + /// given alias does not have a definition. + const AttributeAliasDefinition *getAttributeAliasDef(StringRef name) const; + + /// Return a range of the TypeAliasDefinitions held by the current parser + /// state. + iterator_range getTypeAliasDefs() const; + + /// Return the definition for the given type alias, or nullptr if the given + /// alias does not have a definition. + const TypeAliasDefinition *getTypeAliasDef(StringRef name) const; + /// Returns (heuristically) the range of an identifier given a SMLoc /// corresponding to the start of an identifier location. static SMRange convertIdLocToRange(SMLoc loc); @@ -181,8 +206,9 @@ /// Add a definition of the given entity. void addDefinition(Block *block, SMLoc location); void addDefinition(BlockArgument blockArg, SMLoc location); - void addAttrAliasDefinition(StringRef name, SMRange location); - void addTypeAliasDefinition(StringRef name, SMRange location); + void addAttrAliasDefinition(StringRef name, SMRange location, + Attribute value); + void addTypeAliasDefinition(StringRef name, SMRange location, Type value); /// Add a source uses of the given value. void addUses(Value value, ArrayRef locations); diff --git a/mlir/lib/AsmParser/AsmParserState.cpp b/mlir/lib/AsmParser/AsmParserState.cpp --- a/mlir/lib/AsmParser/AsmParserState.cpp +++ b/mlir/lib/AsmParser/AsmParserState.cpp @@ -128,6 +128,30 @@ : &*impl->operations[it->second]; } +auto AsmParserState::getAttributeAliasDefs() const + -> iterator_range { + return llvm::make_pointee_range(ArrayRef(impl->attrAliases)); +} + +auto AsmParserState::getAttributeAliasDef(StringRef name) const + -> const AttributeAliasDefinition * { + auto it = impl->attrAliasToIdx.find(name); + return it == impl->attrAliasToIdx.end() ? nullptr + : &*impl->attrAliases[it->second]; +} + +auto AsmParserState::getTypeAliasDefs() const + -> iterator_range { + return llvm::make_pointee_range(ArrayRef(impl->typeAliases)); +} + +auto AsmParserState::getTypeAliasDef(StringRef name) const + -> const TypeAliasDefinition * { + auto it = impl->typeAliasToIdx.find(name); + return it == impl->typeAliasToIdx.end() ? nullptr + : &*impl->typeAliases[it->second]; +} + /// Lex a string token whose contents start at the given `curPtr`. Returns the /// position at the end of the string, after a terminal or invalid character /// (e.g. `"` or `\0`). @@ -277,24 +301,28 @@ def.arguments[argIdx] = SMDefinition(convertIdLocToRange(location)); } -void AsmParserState::addAttrAliasDefinition(StringRef name, SMRange location) { +void AsmParserState::addAttrAliasDefinition(StringRef name, SMRange location, + Attribute value) { auto [it, inserted] = impl->attrAliasToIdx.try_emplace(name, impl->attrAliases.size()); // Location aliases may be referenced before they are defined. if (inserted) { impl->attrAliases.push_back( - std::make_unique(name, location)); + std::make_unique(name, location, value)); } else { - impl->attrAliases[it->second]->definition.loc = location; + AttributeAliasDefinition &attr = *impl->attrAliases[it->second]; + attr.definition.loc = location; + attr.value = value; } } -void AsmParserState::addTypeAliasDefinition(StringRef name, SMRange location) { +void AsmParserState::addTypeAliasDefinition(StringRef name, SMRange location, + Type value) { [[maybe_unused]] auto [it, inserted] = impl->typeAliasToIdx.try_emplace(name, impl->typeAliases.size()); assert(inserted && "unexpected attribute alias redefinition"); impl->typeAliases.push_back( - std::make_unique(name, location)); + std::make_unique(name, location, value)); } void AsmParserState::addUses(Value value, ArrayRef locations) { diff --git a/mlir/lib/AsmParser/Parser.cpp b/mlir/lib/AsmParser/Parser.cpp --- a/mlir/lib/AsmParser/Parser.cpp +++ b/mlir/lib/AsmParser/Parser.cpp @@ -2543,7 +2543,7 @@ // Register this alias with the parser state. if (state.asmState) - state.asmState->addAttrAliasDefinition(aliasName, location); + state.asmState->addAttrAliasDefinition(aliasName, location, attr); state.symbols.attributeAliasDefinitions[aliasName] = attr; return success(); } @@ -2575,7 +2575,7 @@ // Register this alias with the parser state. if (state.asmState) - state.asmState->addTypeAliasDefinition(aliasName, location); + state.asmState->addTypeAliasDefinition(aliasName, location, aliasedType); state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType); return success(); } 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 @@ -287,6 +287,12 @@ buildHoverForBlockArgument(SMRange hoverRange, BlockArgument arg, const AsmParserState::BlockDefinition &block); + lsp::Hover buildHoverForAttributeAlias( + SMRange hoverRange, const AsmParserState::AttributeAliasDefinition &attr); + lsp::Hover + buildHoverForTypeAlias(SMRange hoverRange, + const AsmParserState::TypeAliasDefinition &type); + //===--------------------------------------------------------------------===// // Document Symbols //===--------------------------------------------------------------------===// @@ -404,6 +410,18 @@ if (containsPosition(arg)) return; } + + // Check all alias definitions. + for (const AsmParserState::AttributeAliasDefinition &attr : + asmState.getAttributeAliasDefs()) { + if (containsPosition(attr.definition)) + return; + } + for (const AsmParserState::TypeAliasDefinition &type : + asmState.getTypeAliasDefs()) { + if (containsPosition(type.definition)) + return; + } } void MLIRDocument::findReferencesOf(const lsp::URIForFile &uri, @@ -450,6 +468,18 @@ if (isDefOrUse(arg, posLoc)) return appendSMDef(arg); } + + // Check all alias definitions. + for (const AsmParserState::AttributeAliasDefinition &attr : + asmState.getAttributeAliasDefs()) { + if (isDefOrUse(attr.definition, posLoc)) + return appendSMDef(attr.definition); + } + for (const AsmParserState::TypeAliasDefinition &type : + asmState.getTypeAliasDefs()) { + if (isDefOrUse(type.definition, posLoc)) + return appendSMDef(type.definition); + } } //===----------------------------------------------------------------------===// @@ -501,6 +531,19 @@ hoverRange, block.block->getArgument(arg.index()), block); } } + + // Check to see if the hover is over an alias. + for (const AsmParserState::AttributeAliasDefinition &attr : + asmState.getAttributeAliasDefs()) { + if (isDefOrUse(attr.definition, posLoc, &hoverRange)) + return buildHoverForAttributeAlias(hoverRange, attr); + } + for (const AsmParserState::TypeAliasDefinition &type : + asmState.getTypeAliasDefs()) { + if (isDefOrUse(type.definition, posLoc, &hoverRange)) + return buildHoverForTypeAlias(hoverRange, type); + } + return std::nullopt; } @@ -609,6 +652,28 @@ return hover; } +lsp::Hover MLIRDocument::buildHoverForAttributeAlias( + SMRange hoverRange, const AsmParserState::AttributeAliasDefinition &attr) { + lsp::Hover hover(lsp::Range(sourceMgr, hoverRange)); + llvm::raw_string_ostream os(hover.contents.value); + + os << "Attribute Alias: \"" << attr.name << "\n\n"; + os << "Value: ```mlir\n" << attr.value << "\n```\n\n"; + + return hover; +} + +lsp::Hover MLIRDocument::buildHoverForTypeAlias( + SMRange hoverRange, const AsmParserState::TypeAliasDefinition &type) { + lsp::Hover hover(lsp::Range(sourceMgr, hoverRange)); + llvm::raw_string_ostream os(hover.contents.value); + + os << "Type Alias: \"" << type.name << "\n\n"; + os << "Value: ```mlir\n" << type.value << "\n```\n\n"; + + return hover; +} + //===----------------------------------------------------------------------===// // MLIRDocument: Document Symbols //===----------------------------------------------------------------------===// diff --git a/mlir/test/mlir-lsp-server/definition.test b/mlir/test/mlir-lsp-server/definition.test --- a/mlir/test/mlir-lsp-server/definition.test +++ b/mlir/test/mlir-lsp-server/definition.test @@ -5,12 +5,12 @@ "uri":"test:///foo.mlir", "languageId":"mlir", "version":1, - "text":"func.func @foo() -> i1 {\n%value = arith.constant true\nreturn %value : i1\n}" + "text":"#attr = 1 : index\n!type = index\nfunc.func @foo(%arg0: !type) -> i1 attributes {attr = #attr} {\n%value = arith.constant true loc(#loc)\nreturn %value : i1\n}\n#loc = loc(\"foo.mlir\":1:2)" }}} // ----- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{ "textDocument":{"uri":"test:///foo.mlir"}, - "position":{"line":2,"character":12} + "position":{"line":4,"character":12} }} // CHECK: "id": 1 // CHECK-NEXT: "jsonrpc": "2.0", @@ -19,6 +19,48 @@ // CHECK-NEXT: "range": { // CHECK-NEXT: "end": { // CHECK-NEXT: "character": 6, +// CHECK-NEXT: "line": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 0, +// CHECK-NEXT: "line": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: } +// ----- +{"jsonrpc":"2.0","id":2,"method":"textDocument/definition","params":{ + "textDocument":{"uri":"test:///foo.mlir"}, + "position":{"line":2,"character":12} +}} +// CHECK: "id": 2 +// CHECK-NEXT: "jsonrpc": "2.0", +// CHECK-NEXT: "result": [ +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 9, +// CHECK-NEXT: "line": 2 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 0, +// CHECK-NEXT: "line": 2 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: } +// ----- +{"jsonrpc":"2.0","id":2,"method":"textDocument/definition","params":{ + "textDocument":{"uri":"test:///foo.mlir"}, + "position":{"line":2,"character":25} +}} +// CHECK: "id": 2 +// CHECK-NEXT: "jsonrpc": "2.0", +// CHECK-NEXT: "result": [ +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 5, // CHECK-NEXT: "line": 1 // CHECK-NEXT: }, // CHECK-NEXT: "start": { @@ -31,7 +73,7 @@ // ----- {"jsonrpc":"2.0","id":2,"method":"textDocument/definition","params":{ "textDocument":{"uri":"test:///foo.mlir"}, - "position":{"line":0,"character":12} + "position":{"line":2,"character":57} }} // CHECK: "id": 2 // CHECK-NEXT: "jsonrpc": "2.0", @@ -39,7 +81,7 @@ // CHECK-NEXT: { // CHECK-NEXT: "range": { // CHECK-NEXT: "end": { -// CHECK-NEXT: "character": 9, +// CHECK-NEXT: "character": 5, // CHECK-NEXT: "line": 0 // CHECK-NEXT: }, // CHECK-NEXT: "start": { @@ -50,6 +92,27 @@ // CHECK-NEXT: "uri": "{{.*}}/foo.mlir" // CHECK-NEXT: } // ----- +{"jsonrpc":"2.0","id":2,"method":"textDocument/definition","params":{ + "textDocument":{"uri":"test:///foo.mlir"}, + "position":{"line":3,"character":37} +}} +// CHECK: "id": 2 +// CHECK-NEXT: "jsonrpc": "2.0", +// CHECK-NEXT: "result": [ +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 4, +// CHECK-NEXT: "line": 6 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 0, +// CHECK-NEXT: "line": 6 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: } +// ----- {"jsonrpc":"2.0","id":3,"method":"shutdown"} // ----- {"jsonrpc":"2.0","method":"exit"} diff --git a/mlir/test/mlir-lsp-server/references.test b/mlir/test/mlir-lsp-server/references.test --- a/mlir/test/mlir-lsp-server/references.test +++ b/mlir/test/mlir-lsp-server/references.test @@ -5,12 +5,12 @@ "uri":"test:///foo.mlir", "languageId":"mlir", "version":1, - "text":"func.func @foo() -> i1 {\n%value = arith.constant true\n%result = call @foo() : () -> i1\nreturn %value : i1\n}" + "text":"#attr = 1 : index\n!type = index\nfunc.func @foo(%arg0: !type) -> i1 attributes {attr = #attr} {\n%value = arith.constant true\n%result = call @foo(%arg0) : (!type) -> i1\nreturn %value : i1 loc(#loc)\n}\n#loc = loc(\"foo.mlir\":1:2)" }}} // ----- {"jsonrpc":"2.0","id":1,"method":"textDocument/references","params":{ "textDocument":{"uri":"test:///foo.mlir"}, - "position":{"line":1,"character":2}, + "position":{"line":3,"character":2}, "context":{"includeDeclaration": false} }} // CHECK: "id": 1 @@ -20,11 +20,11 @@ // CHECK-NEXT: "range": { // CHECK-NEXT: "end": { // CHECK-NEXT: "character": 6, -// CHECK-NEXT: "line": 1 +// CHECK-NEXT: "line": 3 // CHECK-NEXT: }, // CHECK-NEXT: "start": { // CHECK-NEXT: "character": 0, -// CHECK-NEXT: "line": 1 +// CHECK-NEXT: "line": 3 // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "uri": "{{.*}}/foo.mlir" @@ -33,11 +33,11 @@ // CHECK-NEXT: "range": { // CHECK-NEXT: "end": { // CHECK-NEXT: "character": 13, -// CHECK-NEXT: "line": 3 +// CHECK-NEXT: "line": 5 // CHECK-NEXT: }, // CHECK-NEXT: "start": { // CHECK-NEXT: "character": 7, -// CHECK-NEXT: "line": 3 +// CHECK-NEXT: "line": 5 // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "uri": "{{.*}}/foo.mlir" @@ -46,7 +46,7 @@ // ----- {"jsonrpc":"2.0","id":2,"method":"textDocument/references","params":{ "textDocument":{"uri":"test:///foo.mlir"}, - "position":{"line":0,"character":12}, + "position":{"line":2,"character":12}, "context":{"includeDeclaration": false} }} // CHECK: "id": 2 @@ -56,11 +56,11 @@ // CHECK-NEXT: "range": { // CHECK-NEXT: "end": { // CHECK-NEXT: "character": 14, -// CHECK-NEXT: "line": 0 +// CHECK-NEXT: "line": 2 // CHECK-NEXT: }, // CHECK-NEXT: "start": { // CHECK-NEXT: "character": 10, -// CHECK-NEXT: "line": 0 +// CHECK-NEXT: "line": 2 // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "uri": "{{.*}}/foo.mlir" @@ -69,10 +69,46 @@ // CHECK-NEXT: "range": { // CHECK-NEXT: "end": { // CHECK-NEXT: "character": 19, -// CHECK-NEXT: "line": 2 +// CHECK-NEXT: "line": 4 // CHECK-NEXT: }, // CHECK-NEXT: "start": { // CHECK-NEXT: "character": 15, +// CHECK-NEXT: "line": 4 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// ----- +{"jsonrpc":"2.0","id":2,"method":"textDocument/references","params":{ + "textDocument":{"uri":"test:///foo.mlir"}, + "position":{"line":0,"character":3}, + "context":{"includeDeclaration": false} +}} +// CHECK: "id": 2 +// CHECK-NEXT: "jsonrpc": "2.0", +// CHECK-NEXT: "result": [ +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 5, +// CHECK-NEXT: "line": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 0, +// CHECK-NEXT: "line": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 59, +// CHECK-NEXT: "line": 2 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 54, // CHECK-NEXT: "line": 2 // CHECK-NEXT: } // CHECK-NEXT: }, @@ -80,6 +116,91 @@ // CHECK-NEXT: } // CHECK-NEXT: ] // ----- +{"jsonrpc":"2.0","id":2,"method":"textDocument/references","params":{ + "textDocument":{"uri":"test:///foo.mlir"}, + "position":{"line":1,"character":3}, + "context":{"includeDeclaration": false} +}} +// CHECK: "id": 2 +// CHECK-NEXT: "jsonrpc": "2.0", +// CHECK-NEXT: "result": [ +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 5, +// CHECK-NEXT: "line": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 0, +// CHECK-NEXT: "line": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 27, +// CHECK-NEXT: "line": 2 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 22, +// CHECK-NEXT: "line": 2 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 35, +// CHECK-NEXT: "line": 4 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 30, +// CHECK-NEXT: "line": 4 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// ----- +{"jsonrpc":"2.0","id":2,"method":"textDocument/references","params":{ + "textDocument":{"uri":"test:///foo.mlir"}, + "position":{"line":7,"character":3}, + "context":{"includeDeclaration": false} +}} +// CHECK: "id": 2 +// CHECK-NEXT: "jsonrpc": "2.0", +// CHECK-NEXT: "result": [ +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 4, +// CHECK-NEXT: "line": 7 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 0, +// CHECK-NEXT: "line": 7 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "range": { +// CHECK-NEXT: "end": { +// CHECK-NEXT: "character": 27, +// CHECK-NEXT: "line": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "start": { +// CHECK-NEXT: "character": 23, +// CHECK-NEXT: "line": 5 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "uri": "{{.*}}/foo.mlir" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// ----- {"jsonrpc":"2.0","id":3,"method":"shutdown"} // ----- {"jsonrpc":"2.0","method":"exit"}