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`). 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 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 72 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 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