Files
clang-p2996/mlir/lib/Tools/lsp-server-support/SourceMgrUtils.cpp
River Riddle 682ca00e21 [mlir][Tablegen-LSP] Add support for include file link and hover
This allows for following links to include files. This support is effectively
identical to the logic in the PDLL language server, and code is shared as
much as possible.

Differential Revision: https://reviews.llvm.org/D125442
2022-05-27 02:39:49 -07:00

110 lines
3.7 KiB
C++

//===--- SourceMgrUtils.cpp - SourceMgr LSP Utils -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "SourceMgrUtils.h"
#include "llvm/Support/Path.h"
using namespace mlir;
using namespace mlir::lsp;
//===----------------------------------------------------------------------===//
// Utils
//===----------------------------------------------------------------------===//
/// Find the end of a string 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`).
static const char *lexLocStringTok(const char *curPtr) {
while (char c = *curPtr++) {
// Check for various terminal characters.
if (StringRef("\"\n\v\f").contains(c))
return curPtr;
// Check for escape sequences.
if (c == '\\') {
// Check a few known escapes and \xx hex digits.
if (*curPtr == '"' || *curPtr == '\\' || *curPtr == 'n' || *curPtr == 't')
++curPtr;
else if (llvm::isHexDigit(*curPtr) && llvm::isHexDigit(curPtr[1]))
curPtr += 2;
else
return curPtr;
}
}
// If we hit this point, we've reached the end of the buffer. Update the end
// pointer to not point past the buffer.
return curPtr - 1;
}
SMRange lsp::convertTokenLocToRange(SMLoc loc) {
if (!loc.isValid())
return SMRange();
const char *curPtr = loc.getPointer();
// Check if this is a string token.
if (*curPtr == '"') {
curPtr = lexLocStringTok(curPtr + 1);
// Otherwise, default to handling an identifier.
} else {
// Return if the given character is a valid identifier character.
auto isIdentifierChar = [](char c) {
return isalnum(c) || c == '$' || c == '.' || c == '_' || c == '-';
};
while (*curPtr && isIdentifierChar(*(++curPtr)))
continue;
}
return SMRange(loc, SMLoc::getFromPointer(curPtr));
}
//===----------------------------------------------------------------------===//
// SourceMgrInclude
//===----------------------------------------------------------------------===//
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) {
// Check to see if this file was included by the main file.
SMLoc includeLoc = sourceMgr.getBufferInfo(i + 1).IncludeLoc;
if (!includeLoc.isValid() || sourceMgr.FindBufferContainingLoc(
includeLoc) != sourceMgr.getMainFileID())
continue;
// Try to build a URI for this file path.
auto *buffer = sourceMgr.getMemoryBuffer(i + 1);
llvm::SmallString<256> path(buffer->getBufferIdentifier());
llvm::sys::path::remove_dots(path, /*remove_dot_dot=*/true);
llvm::Expected<URIForFile> includedFileURI = URIForFile::fromFile(path);
if (!includedFileURI)
continue;
// Find the end of the include token.
const char *includeStart = includeLoc.getPointer() - 2;
while (*(--includeStart) != '\"')
continue;
// Push this include.
SMRange includeRange(SMLoc::getFromPointer(includeStart), includeLoc);
includes.emplace_back(*includedFileURI, Range(sourceMgr, includeRange));
}
}