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