10 #include "../lsp-server-support/Logging.h" 11 #include "../lsp-server-support/Protocol.h" 12 #include "../lsp-server-support/SourceMgrUtils.h" 17 #include "llvm/Support/SourceMgr.h" 33 position.
line = loc.getLine() - 1;
34 position.
character = loc.getColumn() ? loc.getColumn() - 1 : 0;
46 FileLineColLoc fileLoc = nestedLoc.
dyn_cast<FileLineColLoc>();
51 if (sourceLoc && (!uri || sourceLoc->uri == *uri)) {
52 location = *sourceLoc;
53 SMLoc loc = sourceMgr.FindLocForLineAndColumn(
54 sourceMgr.getMainFileID(), fileLoc.getLine(), fileLoc.getColumn());
58 location->range.end.character += 1;
60 auto lineCol = sourceMgr.getLineAndColumn(range->End);
61 location->range.end.character =
62 std::max(fileLoc.getColumn() + 1, lineCol.second - 1);
74 std::vector<lsp::Location> &locations,
78 FileLineColLoc fileLoc = nestedLoc.
dyn_cast<FileLineColLoc>();
79 if (!fileLoc || !visitedLocs.insert(nestedLoc))
83 if (sourceLoc && sourceLoc->uri != uri)
84 locations.push_back(*sourceLoc);
92 static bool contains(SMRange range, SMLoc loc) {
93 return range.Start.getPointer() <= loc.getPointer() &&
94 loc.getPointer() <= range.End.getPointer();
101 SMRange *overlappedRange =
nullptr) {
105 *overlappedRange = def.
loc;
110 const auto *useIt = llvm::find_if(
111 def.
uses, [&](
const SMRange &range) { return contains(range, loc); });
112 if (useIt != def.
uses.end()) {
114 *overlappedRange = *useIt;
124 auto isIdentifierChar = [](
char c) {
125 return isalnum(c) || c ==
'%' || c ==
'$' || c ==
'.' || c ==
'_' ||
128 const char *curPtr = loc.getPointer();
129 while (isIdentifierChar(*curPtr))
138 const char *numberStart = ++curPtr;
139 while (llvm::isDigit(*curPtr))
141 StringRef numberStr(numberStart, curPtr - numberStart);
142 unsigned resultNumber = 0;
150 if (!range.isValid())
152 const char *startPtr = range.Start.getPointer();
153 return StringRef(startPtr, range.End.getPointer() - startPtr);
158 return std::distance(block->
getParent()->
begin(), block->getIterator());
166 if (text && text->startswith(
"^")) {
196 lspDiag.
range = lspLocation->range;
201 llvm_unreachable(
"expected notes to be handled separately");
215 std::vector<lsp::DiagnosticRelatedInformation> relatedDiags;
223 relatedDiags.emplace_back(noteLoc, note.str());
225 if (!relatedDiags.empty())
238 struct MLIRDocument {
240 StringRef contents, std::vector<lsp::Diagnostic> &diagnostics);
241 MLIRDocument(
const MLIRDocument &) =
delete;
242 MLIRDocument &operator=(
const MLIRDocument &) =
delete;
249 std::vector<lsp::Location> &locations);
251 std::vector<lsp::Location> &references);
260 buildHoverForOperation(SMRange hoverRange,
263 unsigned resultStart,
264 unsigned resultEnd, SMLoc posLoc);
265 lsp::Hover buildHoverForBlock(SMRange hoverRange,
268 buildHoverForBlockArgument(SMRange hoverRange,
BlockArgument arg,
275 void findDocumentSymbols(std::vector<lsp::DocumentSymbol> &symbols);
277 std::vector<lsp::DocumentSymbol> &symbols);
291 llvm::SourceMgr sourceMgr;
297 std::vector<lsp::Diagnostic> &diagnostics) {
303 auto memBuffer = llvm::MemoryBuffer::getMemBufferCopy(contents, uri.
file());
309 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
325 std::vector<lsp::Location> &locations) {
332 locations.emplace_back(uri, sourceMgr, def.loc);
340 for (
const auto &result : op.resultGroups)
341 if (containsPosition(result.definition))
343 for (
const auto &symUse : op.symbolUses) {
345 locations.emplace_back(uri, sourceMgr, op.loc);
353 if (containsPosition(block.definition))
356 if (containsPosition(arg))
363 std::vector<lsp::Location> &references) {
367 references.emplace_back(uri, sourceMgr, def.loc);
368 for (
const SMRange &use : def.uses)
369 references.emplace_back(uri, sourceMgr, use);
377 for (
const auto &result : op.resultGroups)
378 appendSMDef(result.definition);
379 for (
const auto &symUse : op.symbolUses)
381 references.emplace_back(uri, sourceMgr, symUse);
384 for (
const auto &result : op.resultGroups)
386 return appendSMDef(result.definition);
387 for (
const auto &symUse : op.symbolUses) {
390 for (
const auto &symUse : op.symbolUses)
391 references.emplace_back(uri, sourceMgr, symUse);
399 return appendSMDef(block.definition);
403 return appendSMDef(arg);
413 SMLoc posLoc = hoverPos.
getAsSMLoc(sourceMgr);
420 return buildHoverForOperation(op.loc, op);
423 for (
auto &use : op.symbolUses)
425 return buildHoverForOperation(use, op);
428 for (
unsigned i = 0, e = op.resultGroups.size(); i < e; ++i) {
429 const auto &result = op.resultGroups[i];
430 if (!
isDefOrUse(result.definition, posLoc, &hoverRange))
434 unsigned resultStart = result.startIndex;
435 unsigned resultEnd = (i == e - 1) ? op.op->getNumResults()
436 : op.resultGroups[i + 1].startIndex;
437 return buildHoverForOperationResult(hoverRange, op.op, resultStart,
444 if (
isDefOrUse(block.definition, posLoc, &hoverRange))
445 return buildHoverForBlock(hoverRange, block);
448 if (!
isDefOrUse(arg.value(), posLoc, &hoverRange))
451 return buildHoverForBlockArgument(
452 hoverRange, block.block->
getArgument(arg.index()), block);
465 if (SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(op.
op))
466 os <<
" : " << symbol.getVisibility() <<
" @" << symbol.getName() <<
"";
469 os <<
"Generic Form:\n\n```mlir\n";
476 regions.emplace_back(std::make_unique<Region>());
477 regions.back()->takeBody(region);
486 region.takeBody(*regions.back());
491 lsp::Hover MLIRDocument::buildHoverForOperationResult(SMRange hoverRange,
493 unsigned resultStart,
500 os <<
"Operation: \"" << op->
getName() <<
"\"\n\n";
505 if ((resultStart + *resultNumber) < resultEnd) {
506 resultStart += *resultNumber;
507 resultEnd = resultStart + 1;
512 if ((resultStart + 1) == resultEnd) {
513 os <<
"Result #" << resultStart <<
"\n\n" 516 os <<
"Result #[" << resultStart <<
", " << (resultEnd - 1) <<
"]\n\n" 518 llvm::interleaveComma(
519 op->
getResults().slice(resultStart, resultEnd), os,
520 [&](
Value result) { os <<
"`" << result.
getType() <<
"`"; });
527 MLIRDocument::buildHoverForBlock(SMRange hoverRange,
533 auto printBlockToHover = [&](
Block *newBlock) {
534 if (
const auto *def = asmState.getBlockDef(newBlock))
544 os <<
"Predecessors: ";
550 os <<
"Successors: ";
558 lsp::Hover MLIRDocument::buildHoverForBlockArgument(
569 <<
"Type: `" << arg.
getType() <<
"`\n\n";
578 void MLIRDocument::findDocumentSymbols(
579 std::vector<lsp::DocumentSymbol> &symbols) {
581 findDocumentSymbols(&op, symbols);
584 void MLIRDocument::findDocumentSymbols(
585 Operation *op, std::vector<lsp::DocumentSymbol> &symbols) {
586 std::vector<lsp::DocumentSymbol> *childSymbols = &symbols;
591 if (SymbolOpInterface symbol = dyn_cast<SymbolOpInterface>(op)) {
592 symbols.emplace_back(symbol.getName(),
593 isa<FunctionOpInterface>(op)
598 childSymbols = &symbols.back().children;
606 childSymbols = &symbols.back().children;
614 for (
Operation &childOp : region.getOps())
615 findDocumentSymbols(&childOp, *childSymbols);
624 struct MLIRTextFileChunk {
625 MLIRTextFileChunk(
MLIRContext &context, uint64_t lineOffset,
627 std::vector<lsp::Diagnostic> &diagnostics)
628 : lineOffset(lineOffset), document(context, uri, contents, diagnostics) {}
632 void adjustLocForChunkOffset(
lsp::Range &range) {
633 adjustLocForChunkOffset(range.
start);
634 adjustLocForChunkOffset(range.
end);
643 MLIRDocument document;
657 std::vector<lsp::Diagnostic> &diagnostics);
660 int64_t getVersion()
const {
return version; }
667 std::vector<lsp::Location> &locations);
669 std::vector<lsp::Location> &references);
672 void findDocumentSymbols(std::vector<lsp::DocumentSymbol> &symbols);
684 std::string contents;
690 int64_t totalNumLines = 0;
694 std::vector<std::unique_ptr<MLIRTextFileChunk>> chunks;
698 MLIRTextFile::MLIRTextFile(
const lsp::URIForFile &uri, StringRef fileContents,
700 std::vector<lsp::Diagnostic> &diagnostics)
702 contents(fileContents.str()), version(version) {
710 StringRef(contents).split(subContents,
"// -----");
711 chunks.emplace_back(std::make_unique<MLIRTextFileChunk>(
712 context, 0, uri, subContents.front(), diagnostics));
714 uint64_t lineOffset = subContents.front().count(
'\n');
715 for (StringRef docContents : llvm::drop_begin(subContents)) {
716 unsigned currentNumDiags = diagnostics.size();
717 auto chunk = std::make_unique<MLIRTextFileChunk>(context, lineOffset, uri,
718 docContents, diagnostics);
719 lineOffset += docContents.count(
'\n');
724 llvm::drop_begin(diagnostics, currentNumDiags)) {
725 chunk->adjustLocForChunkOffset(
diag.range);
727 if (!
diag.relatedInformation)
729 for (
auto &it : *
diag.relatedInformation)
730 if (it.location.uri == uri)
731 chunk->adjustLocForChunkOffset(it.location.range);
733 chunks.emplace_back(std::move(chunk));
735 totalNumLines = lineOffset;
740 std::vector<lsp::Location> &locations) {
741 MLIRTextFileChunk &chunk = getChunkFor(defPos);
742 chunk.document.getLocationsOf(uri, defPos, locations);
745 if (chunk.lineOffset == 0)
749 chunk.adjustLocForChunkOffset(loc.range);
754 std::vector<lsp::Location> &references) {
755 MLIRTextFileChunk &chunk = getChunkFor(pos);
756 chunk.document.findReferencesOf(uri, pos, references);
759 if (chunk.lineOffset == 0)
763 chunk.adjustLocForChunkOffset(loc.range);
768 MLIRTextFileChunk &chunk = getChunkFor(hoverPos);
772 if (chunk.lineOffset != 0 && hoverInfo && hoverInfo->range)
773 chunk.adjustLocForChunkOffset(*hoverInfo->range);
777 void MLIRTextFile::findDocumentSymbols(
778 std::vector<lsp::DocumentSymbol> &symbols) {
779 if (chunks.size() == 1)
780 return chunks.front()->document.findDocumentSymbols(symbols);
784 for (
unsigned i = 0, e = chunks.size(); i < e; ++i) {
785 MLIRTextFileChunk &chunk = *chunks[i];
788 : chunks[i + 1]->lineOffset);
793 chunk.document.findDocumentSymbols(symbol.
children);
799 symbolsToFix.push_back(&childSymbol);
801 while (!symbolsToFix.empty()) {
803 chunk.adjustLocForChunkOffset(symbol->
range);
807 symbolsToFix.push_back(&childSymbol);
812 symbols.emplace_back(std::move(symbol));
816 MLIRTextFileChunk &MLIRTextFile::getChunkFor(
lsp::Position &pos) {
817 if (chunks.size() == 1)
818 return *chunks.front();
822 auto it = llvm::upper_bound(
823 chunks, pos, [](
const lsp::Position &pos,
const auto &chunk) {
824 return static_cast<uint64_t
>(pos.
line) < chunk->lineOffset;
826 MLIRTextFileChunk &chunk = it == chunks.end() ? *chunks.back() : **(--it);
827 pos.
line -= chunk.lineOffset;
843 llvm::StringMap<std::unique_ptr<MLIRTextFile>>
files;
851 :
impl(std::make_unique<
Impl>(registry)) {}
855 const URIForFile &uri, StringRef contents, int64_t version,
856 std::vector<Diagnostic> &diagnostics) {
857 impl->files[uri.
file()] = std::make_unique<MLIRTextFile>(
858 uri, contents, version,
impl->registry, diagnostics);
862 auto it =
impl->files.find(uri.
file());
863 if (it ==
impl->files.end())
866 int64_t version = it->second->getVersion();
867 impl->files.erase(it);
873 std::vector<Location> &locations) {
874 auto fileIt =
impl->files.find(uri.
file());
875 if (fileIt !=
impl->files.end())
876 fileIt->second->getLocationsOf(uri, defPos, locations);
881 std::vector<Location> &references) {
882 auto fileIt =
impl->files.find(uri.
file());
883 if (fileIt !=
impl->files.end())
884 fileIt->second->findReferencesOf(uri, pos, references);
889 auto fileIt =
impl->files.find(uri.
file());
890 if (fileIt !=
impl->files.end())
891 return fileIt->second->findHover(uri, hoverPos);
896 const URIForFile &uri, std::vector<DocumentSymbol> &symbols) {
897 auto fileIt =
impl->files.find(uri.
file());
898 if (fileIt !=
impl->files.end())
899 fileIt->second->findDocumentSymbols(symbols);
StringRef file() const
Returns the absolute path to the file.
TODO: Remove this file when SCCP and integer range analysis have been ported to the new framework...
Documents should not be synced at all.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
static std::string diag(llvm::Value &v)
Optional< int64_t > removeDocument(const URIForFile &uri)
Remove the document with the given uri.
SMRange loc
The source location of the definition.
This class represents a definition within the source manager, containing it's defining location and l...
void getLocationsOf(const URIForFile &uri, const Position &defPos, std::vector< Location > &locations)
Return the locations of the object pointed at by the given position.
This class represents state from a parsed MLIR textual format string.
Operation is a basic unit of execution within MLIR.
static void error(const char *fmt, Ts &&...vals)
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
unsigned getNumRegions()
Returns the number of regions held by this operation.
static Optional< StringRef > getTextFromRange(SMRange range)
Given a source location range, return the text covered by the given range.
Block represents an ordered list of Operations.
static unsigned getBlockNumber(Block *block)
Given a block, return its position in its parent region.
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Location getLocation() const
Returns the source location for this diagnostic.
DiagnosticSeverity severity
The diagnostic's severity.
Optional< std::string > category
The diagnostic's category.
iterator_range< pred_iterator > getPredecessors()
static void printDefBlockName(raw_ostream &os, Block *block, SMRange loc={})
Given a block and source location, print the source name of the block to the given output stream...
SmallVector< SMRange > uses
The source location of all uses of the definition.
URI in "file" scheme for a file.
Range range
The range enclosing this symbol not including leading/trailing whitespace but everything else like co...
DiagnosticSeverity getSeverity() const
Returns the severity of this diagnostic.
unsigned getArgNumber() const
Returns the number of this argument.
BlockArgument getArgument(unsigned i)
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
static void collectLocationsFromLoc(Location loc, std::vector< lsp::Location > &locations, const lsp::URIForFile &uri)
Collect all of the locations from the given MLIR location that are not contained within the given URI...
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
static lsp::Diagnostic getLspDiagnoticFromDiag(llvm::SourceMgr &sourceMgr, Diagnostic &diag, const lsp::URIForFile &uri)
Convert the given MLIR diagnostic to the LSP form.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRServer(DialectRegistry ®istry)
Construct a new server with the given dialect regitstry.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
std::string source
A human-readable string describing the source of this diagnostic, e.g.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine...
int character
Character offset on a line in a document (zero-based).
Block * block
The block representing this definition.
Optional< Hover > findHover(const URIForFile &uri, const Position &hoverPos)
Find a hover description for the given hover position, or None if one couldn't be found...
int line
Line position in a document (zero-based).
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
A trait used to provide symbol table functionalities to a region operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
static WalkResult advance()
Impl(DialectRegistry ®istry)
Position end
The range's end position.
SMRange convertTokenLocToRange(SMLoc loc)
Returns the range of a lexical token given a SMLoc corresponding to the start of an token location...
static WalkResult interrupt()
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
This class represents an argument of a Block.
void addOrUpdateDocument(const URIForFile &uri, StringRef contents, int64_t version, std::vector< Diagnostic > &diagnostics)
Add or update the document, with the provided version, at the given URI.
MarkupContent contents
The hover's content.
This class represents the information for an operation definition within an input file...
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
std::string message
The diagnostic's message.
void print(raw_ostream &os, const OpPrintingFlags &flags=llvm::None)
void findDocumentSymbols(const URIForFile &uri, std::vector< DocumentSymbol > &symbols)
Find all of the document symbols within the given file.
static Optional< lsp::Location > getLocationFromLoc(FileLineColLoc loc)
Returns a language server location from the given MLIR file location.
This class represents the information for a block definition within the input file.
DialectRegistry & registry
The registry containing dialects that can be recognized in parsed .mlir files.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Position start
The range's start position.
llvm::StringMap< std::unique_ptr< MLIRTextFile > > files
The files held by the server, mapped by their URI file name.
Optional< std::vector< DiagnosticRelatedInformation > > relatedInformation
An array of related diagnostic information, e.g.
URIForFile uri
The text document's URI.
Set of flags used to control the behavior of the various IR print methods (e.g.
iterator_range< note_iterator > getNotes()
Returns the notes held by this diagnostic.
Type getType() const
Return the type of this value.
Range range
The source range where the message applies.
SMDefinition definition
The source location for the block, i.e.
Range selectionRange
The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
static Optional< unsigned > getResultNumberFromLoc(SMLoc loc)
Given a location pointing to a result, return the result number it refers to or None if it refers to ...
bool hasNoSuccessors()
Returns true if this blocks has no successors.
bool hasNoPredecessors()
Return true if this block has no predecessors.
MLIRContext is the top-level object for a collection of MLIR operations.
static bool isDefOrUse(const AsmParserState::SMDefinition &def, SMLoc loc, SMRange *overlappedRange=nullptr)
Returns true if the given location is contained by the definition or one of the uses of the given SMD...
StringRef toString(IteratorType t)
Operation * op
The operation representing this definition.
void findReferencesOf(const URIForFile &uri, const Position &pos, std::vector< Location > &references)
Find all references of the object pointed at by the given position.
static llvm::Expected< URIForFile > fromFile(StringRef absoluteFilepath)
Try to build a URIForFile from the given absolute file path.
SuccessorRange getSuccessors()
Represents programming constructs like variables, classes, interfaces etc.
OperationName getName()
The name of an operation is the key identifier for it.
SMLoc getAsSMLoc(llvm::SourceMgr &mgr) const
Convert this position into a source location in the main file of the given source manager...
result_range getResults()
WalkResult walk(function_ref< WalkResult(Location)> walkFn)
Walk all of the locations nested under, and including, the current.
std::string str() const
Converts the diagnostic to a string.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
LogicalResult parseSourceFile(const llvm::SourceMgr &sourceMgr, Block *block, const ParserConfig &config, LocationAttr *sourceFileLoc=nullptr, AsmParserState *asmState=nullptr)
This parses the file specified by the indicated SourceMgr and appends parsed operations to the given ...