#include "mlir/Tools/lsp-server-support/SourceMgrUtils.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Path.h"
#include <optional>
using namespace mlir;
using namespace mlir::lsp;
static const char *lexLocStringTok(const char *curPtr) {
while (char c = *curPtr++) {
if (StringRef("\"\n\v\f").contains(c))
return curPtr;
if (c == '\\') {
if (*curPtr == '"' || *curPtr == '\\' || *curPtr == 'n' || *curPtr == 't')
++curPtr;
else if (llvm::isHexDigit(*curPtr) && llvm::isHexDigit(curPtr[1]))
curPtr += 2;
else
return curPtr;
}
}
return curPtr - 1;
}
SMRange lsp::convertTokenLocToRange(SMLoc loc, StringRef identifierChars) {
if (!loc.isValid())
return SMRange();
const char *curPtr = loc.getPointer();
if (*curPtr == '"') {
curPtr = lexLocStringTok(curPtr + 1);
} else {
auto isIdentifierChar = [=](char c) {
return isalnum(c) || c == '_' || identifierChars.contains(c);
};
while (*curPtr && isIdentifierChar(*(++curPtr)))
continue;
}
return SMRange(loc, SMLoc::getFromPointer(curPtr));
}
std::optional<std::string>
lsp::extractSourceDocComment(llvm::SourceMgr &sourceMgr, SMLoc loc) {
if (!loc.isValid())
return std::nullopt;
int bufferId = sourceMgr.FindBufferContainingLoc(loc);
if (bufferId == 0)
return std::nullopt;
const char *bufferStart =
sourceMgr.getMemoryBuffer(bufferId)->getBufferStart();
StringRef buffer(bufferStart, loc.getPointer() - bufferStart);
auto popLastLine = [&]() -> std::optional<StringRef> {
size_t newlineOffset = buffer.find_last_of('\n');
if (newlineOffset == StringRef::npos)
return std::nullopt;
StringRef lastLine = buffer.drop_front(newlineOffset).trim();
buffer = buffer.take_front(newlineOffset);
return lastLine;
};
if (!popLastLine())
return std::nullopt;
SmallVector<StringRef> commentLines;
while (std::optional<StringRef> line = popLastLine()) {
if (!line->starts_with("//"))
break;
commentLines.push_back(line->ltrim('/'));
}
if (commentLines.empty())
return std::nullopt;
return llvm::join(llvm::reverse(commentLines), "\n");
}
bool lsp::contains(SMRange range, SMLoc loc) {
return range.Start.getPointer() <= loc.getPointer() &&
loc.getPointer() < range.End.getPointer();
}
Hover SourceMgrInclude::buildHover() const {
Hover hover(range);
{
llvm::raw_string_ostream hoverOS(hover.contents.value);
hoverOS << "`" << llvm::sys::path::filename(uri.file()) << "`\n***\n"
<< uri.file();
}
return hover;
}
void lsp::gatherIncludeFiles(llvm::SourceMgr &sourceMgr,
SmallVectorImpl<SourceMgrInclude> &includes) {
for (unsigned i = 1, e = sourceMgr.getNumBuffers(); i < e; ++i) {
SMLoc includeLoc = sourceMgr.getBufferInfo(i + 1).IncludeLoc;
if (!includeLoc.isValid() || sourceMgr.FindBufferContainingLoc(
includeLoc) != sourceMgr.getMainFileID())
continue;
auto *buffer = sourceMgr.getMemoryBuffer(i + 1);
llvm::SmallString<256> path(buffer->getBufferIdentifier());
llvm::sys::path::remove_dots(path, true);
llvm::Expected<URIForFile> includedFileURI = URIForFile::fromFile(path);
if (!includedFileURI)
continue;
const char *includeStart = includeLoc.getPointer() - 2;
while (*(--includeStart) != '\"')
continue;
SMRange includeRange(SMLoc::getFromPointer(includeStart), includeLoc);
includes.emplace_back(*includedFileURI, Range(sourceMgr, includeRange));
}
}