brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.5 KiB · 5cd1c85 Raw
165 lines · cpp
1//===--- SourceMgrUtils.cpp - SourceMgr LSP Utils -------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/Tools/lsp-server-support/SourceMgrUtils.h"10#include "llvm/ADT/StringExtras.h"11#include "llvm/Support/Path.h"12#include <optional>13 14using namespace mlir;15using namespace mlir::lsp;16 17using llvm::lsp::Hover;18using llvm::lsp::Range;19using llvm::lsp::URIForFile;20 21//===----------------------------------------------------------------------===//22// Utils23//===----------------------------------------------------------------------===//24 25/// Find the end of a string whose contents start at the given `curPtr`. Returns26/// the position at the end of the string, after a terminal or invalid character27/// (e.g. `"` or `\0`).28static const char *lexLocStringTok(const char *curPtr) {29  while (char c = *curPtr++) {30    // Check for various terminal characters.31    if (StringRef("\"\n\v\f").contains(c))32      return curPtr;33 34    // Check for escape sequences.35    if (c == '\\') {36      // Check a few known escapes and \xx hex digits.37      if (*curPtr == '"' || *curPtr == '\\' || *curPtr == 'n' || *curPtr == 't')38        ++curPtr;39      else if (llvm::isHexDigit(*curPtr) && llvm::isHexDigit(curPtr[1]))40        curPtr += 2;41      else42        return curPtr;43    }44  }45 46  // If we hit this point, we've reached the end of the buffer. Update the end47  // pointer to not point past the buffer.48  return curPtr - 1;49}50 51SMRange lsp::convertTokenLocToRange(SMLoc loc, StringRef identifierChars) {52  if (!loc.isValid())53    return SMRange();54  const char *curPtr = loc.getPointer();55 56  // Check if this is a string token.57  if (*curPtr == '"') {58    curPtr = lexLocStringTok(curPtr + 1);59 60    // Otherwise, default to handling an identifier.61  } else {62    // Return if the given character is a valid identifier character.63    auto isIdentifierChar = [=](char c) {64      return isalnum(c) || c == '_' || identifierChars.contains(c);65    };66 67    while (*curPtr && isIdentifierChar(*(++curPtr)))68      continue;69  }70 71  return SMRange(loc, SMLoc::getFromPointer(curPtr));72}73 74std::optional<std::string>75lsp::extractSourceDocComment(llvm::SourceMgr &sourceMgr, SMLoc loc) {76  // This is a heuristic, and isn't intended to cover every case, but should77  // cover the most common. We essentially look for a comment preceding the78  // line, and if we find one, use that as the documentation.79  if (!loc.isValid())80    return std::nullopt;81  int bufferId = sourceMgr.FindBufferContainingLoc(loc);82  if (bufferId == 0)83    return std::nullopt;84  const char *bufferStart =85      sourceMgr.getMemoryBuffer(bufferId)->getBufferStart();86  StringRef buffer(bufferStart, loc.getPointer() - bufferStart);87 88  // Pop the last line from the buffer string.89  auto popLastLine = [&]() -> std::optional<StringRef> {90    size_t newlineOffset = buffer.find_last_of('\n');91    if (newlineOffset == StringRef::npos)92      return std::nullopt;93    StringRef lastLine = buffer.drop_front(newlineOffset).trim();94    buffer = buffer.take_front(newlineOffset);95    return lastLine;96  };97 98  // Try to pop the current line.99  if (!popLastLine())100    return std::nullopt;101 102  // Try to parse a comment string from the source file.103  SmallVector<StringRef> commentLines;104  while (std::optional<StringRef> line = popLastLine()) {105    // Check for a comment at the beginning of the line.106    if (!line->starts_with("//"))107      break;108 109    // Extract the document string from the comment.110    commentLines.push_back(line->ltrim('/'));111  }112 113  if (commentLines.empty())114    return std::nullopt;115  return llvm::join(llvm::reverse(commentLines), "\n");116}117 118bool lsp::contains(SMRange range, SMLoc loc) {119  return range.Start.getPointer() <= loc.getPointer() &&120         loc.getPointer() < range.End.getPointer();121}122 123//===----------------------------------------------------------------------===//124// SourceMgrInclude125//===----------------------------------------------------------------------===//126 127Hover SourceMgrInclude::buildHover() const {128  Hover hover(range);129  {130    llvm::raw_string_ostream hoverOS(hover.contents.value);131    hoverOS << "`" << llvm::sys::path::filename(uri.file()) << "`\n***\n"132            << uri.file();133  }134  return hover;135}136 137void lsp::gatherIncludeFiles(llvm::SourceMgr &sourceMgr,138                             SmallVectorImpl<SourceMgrInclude> &includes) {139  for (unsigned i = 1, e = sourceMgr.getNumBuffers(); i < e; ++i) {140    // Check to see if this file was included by the main file.141    SMLoc includeLoc = sourceMgr.getBufferInfo(i + 1).IncludeLoc;142    if (!includeLoc.isValid() || sourceMgr.FindBufferContainingLoc(143                                     includeLoc) != sourceMgr.getMainFileID())144      continue;145 146    // Try to build a URI for this file path.147    auto *buffer = sourceMgr.getMemoryBuffer(i + 1);148    llvm::SmallString<256> path(buffer->getBufferIdentifier());149    llvm::sys::path::remove_dots(path, /*remove_dot_dot=*/true);150 151    llvm::Expected<URIForFile> includedFileURI = URIForFile::fromFile(path);152    if (!includedFileURI)153      continue;154 155    // Find the end of the include token.156    const char *includeStart = includeLoc.getPointer() - 2;157    while (*(--includeStart) != '\"')158      continue;159 160    // Push this include.161    SMRange includeRange(SMLoc::getFromPointer(includeStart), includeLoc);162    includes.emplace_back(*includedFileURI, Range(sourceMgr, includeRange));163  }164}165