1 //===--- SourceCode.h - Manipulating source code as strings -----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include "SourceCode.h" 10 11 #include "clang/Basic/SourceManager.h" 12 #include "llvm/Support/Errc.h" 13 #include "llvm/Support/Error.h" 14 15 namespace clang { 16 namespace clangd { 17 using namespace llvm; 18 19 llvm::Expected<size_t> positionToOffset(StringRef Code, Position P, 20 bool AllowColumnsBeyondLineLength) { 21 if (P.line < 0) 22 return llvm::make_error<llvm::StringError>( 23 llvm::formatv("Line value can't be negative ({0})", P.line), 24 llvm::errc::invalid_argument); 25 if (P.character < 0) 26 return llvm::make_error<llvm::StringError>( 27 llvm::formatv("Character value can't be negative ({0})", P.character), 28 llvm::errc::invalid_argument); 29 size_t StartOfLine = 0; 30 for (int I = 0; I != P.line; ++I) { 31 size_t NextNL = Code.find('\n', StartOfLine); 32 if (NextNL == StringRef::npos) 33 return llvm::make_error<llvm::StringError>( 34 llvm::formatv("Line value is out of range ({0})", P.line), 35 llvm::errc::invalid_argument); 36 StartOfLine = NextNL + 1; 37 } 38 39 size_t NextNL = Code.find('\n', StartOfLine); 40 if (NextNL == StringRef::npos) 41 NextNL = Code.size(); 42 43 if (StartOfLine + P.character > NextNL && !AllowColumnsBeyondLineLength) 44 return llvm::make_error<llvm::StringError>( 45 llvm::formatv("Character value is out of range ({0})", P.character), 46 llvm::errc::invalid_argument); 47 // FIXME: officially P.character counts UTF-16 code units, not UTF-8 bytes! 48 return std::min(NextNL, StartOfLine + P.character); 49 } 50 51 Position offsetToPosition(StringRef Code, size_t Offset) { 52 Offset = std::min(Code.size(), Offset); 53 StringRef Before = Code.substr(0, Offset); 54 int Lines = Before.count('\n'); 55 size_t PrevNL = Before.rfind('\n'); 56 size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1); 57 // FIXME: officially character counts UTF-16 code units, not UTF-8 bytes! 58 Position Pos; 59 Pos.line = Lines; 60 Pos.character = static_cast<int>(Offset - StartOfLine); 61 return Pos; 62 } 63 64 Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc) { 65 Position P; 66 P.line = static_cast<int>(SM.getSpellingLineNumber(Loc)) - 1; 67 P.character = static_cast<int>(SM.getSpellingColumnNumber(Loc)) - 1; 68 return P; 69 } 70 71 Range halfOpenToRange(const SourceManager &SM, CharSourceRange R) { 72 // Clang is 1-based, LSP uses 0-based indexes. 73 Position Begin = sourceLocToPosition(SM, R.getBegin()); 74 Position End = sourceLocToPosition(SM, R.getEnd()); 75 76 return {Begin, End}; 77 } 78 79 } // namespace clangd 80 } // namespace clang 81