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-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "SourceMgrUtils.h"
10 #include "llvm/Support/Path.h"
11
12 using namespace mlir;
13 using namespace mlir::lsp;
14
15 //===----------------------------------------------------------------------===//
16 // Utils
17 //===----------------------------------------------------------------------===//
18
19 /// Find the end of a string whose contents start at the given `curPtr`. Returns
20 /// the position at the end of the string, after a terminal or invalid character
21 /// (e.g. `"` or `\0`).
lexLocStringTok(const char * curPtr)22 static const char *lexLocStringTok(const char *curPtr) {
23 while (char c = *curPtr++) {
24 // Check for various terminal characters.
25 if (StringRef("\"\n\v\f").contains(c))
26 return curPtr;
27
28 // Check for escape sequences.
29 if (c == '\\') {
30 // Check a few known escapes and \xx hex digits.
31 if (*curPtr == '"' || *curPtr == '\\' || *curPtr == 'n' || *curPtr == 't')
32 ++curPtr;
33 else if (llvm::isHexDigit(*curPtr) && llvm::isHexDigit(curPtr[1]))
34 curPtr += 2;
35 else
36 return curPtr;
37 }
38 }
39
40 // If we hit this point, we've reached the end of the buffer. Update the end
41 // pointer to not point past the buffer.
42 return curPtr - 1;
43 }
44
convertTokenLocToRange(SMLoc loc)45 SMRange lsp::convertTokenLocToRange(SMLoc loc) {
46 if (!loc.isValid())
47 return SMRange();
48 const char *curPtr = loc.getPointer();
49
50 // Check if this is a string token.
51 if (*curPtr == '"') {
52 curPtr = lexLocStringTok(curPtr + 1);
53
54 // Otherwise, default to handling an identifier.
55 } else {
56 // Return if the given character is a valid identifier character.
57 auto isIdentifierChar = [](char c) {
58 return isalnum(c) || c == '$' || c == '.' || c == '_' || c == '-';
59 };
60
61 while (*curPtr && isIdentifierChar(*(++curPtr)))
62 continue;
63 }
64
65 return SMRange(loc, SMLoc::getFromPointer(curPtr));
66 }
67
68 //===----------------------------------------------------------------------===//
69 // SourceMgrInclude
70 //===----------------------------------------------------------------------===//
71
buildHover() const72 Hover SourceMgrInclude::buildHover() const {
73 Hover hover(range);
74 {
75 llvm::raw_string_ostream hoverOS(hover.contents.value);
76 hoverOS << "`" << llvm::sys::path::filename(uri.file()) << "`\n***\n"
77 << uri.file();
78 }
79 return hover;
80 }
81
gatherIncludeFiles(llvm::SourceMgr & sourceMgr,SmallVectorImpl<SourceMgrInclude> & includes)82 void lsp::gatherIncludeFiles(llvm::SourceMgr &sourceMgr,
83 SmallVectorImpl<SourceMgrInclude> &includes) {
84 for (unsigned i = 1, e = sourceMgr.getNumBuffers(); i < e; ++i) {
85 // Check to see if this file was included by the main file.
86 SMLoc includeLoc = sourceMgr.getBufferInfo(i + 1).IncludeLoc;
87 if (!includeLoc.isValid() || sourceMgr.FindBufferContainingLoc(
88 includeLoc) != sourceMgr.getMainFileID())
89 continue;
90
91 // Try to build a URI for this file path.
92 auto *buffer = sourceMgr.getMemoryBuffer(i + 1);
93 llvm::SmallString<256> path(buffer->getBufferIdentifier());
94 llvm::sys::path::remove_dots(path, /*remove_dot_dot=*/true);
95
96 llvm::Expected<URIForFile> includedFileURI = URIForFile::fromFile(path);
97 if (!includedFileURI)
98 continue;
99
100 // Find the end of the include token.
101 const char *includeStart = includeLoc.getPointer() - 2;
102 while (*(--includeStart) != '\"')
103 continue;
104
105 // Push this include.
106 SMRange includeRange(SMLoc::getFromPointer(includeStart), includeLoc);
107 includes.emplace_back(*includedFileURI, Range(sourceMgr, includeRange));
108 }
109 }
110