blob: 65a7ca987c136b11f57d4decd267b1d694afc6e1 [file] [log] [blame]
Sam McCallb536a2a2017-12-19 12:23:48 +00001//===--- 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
Marc-Andre Laperle63a10982018-02-21 02:39:08 +000011#include "clang/Basic/SourceManager.h"
Simon Marchi766338a2018-03-21 14:36:46 +000012#include "llvm/Support/Errc.h"
13#include "llvm/Support/Error.h"
Marc-Andre Laperle63a10982018-02-21 02:39:08 +000014
Sam McCallb536a2a2017-12-19 12:23:48 +000015namespace clang {
16namespace clangd {
17using namespace llvm;
18
Simon Marchi766338a2018-03-21 14:36:46 +000019llvm::Expected<size_t> positionToOffset(StringRef Code, Position P,
20 bool AllowColumnsBeyondLineLength) {
Sam McCallb536a2a2017-12-19 12:23:48 +000021 if (P.line < 0)
Simon Marchi766338a2018-03-21 14:36:46 +000022 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);
Sam McCallb536a2a2017-12-19 12:23:48 +000029 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)
Simon Marchi766338a2018-03-21 14:36:46 +000033 return llvm::make_error<llvm::StringError>(
34 llvm::formatv("Line value is out of range ({0})", P.line),
35 llvm::errc::invalid_argument);
Sam McCallb536a2a2017-12-19 12:23:48 +000036 StartOfLine = NextNL + 1;
37 }
Simon Marchi766338a2018-03-21 14:36:46 +000038
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);
Sam McCallb536a2a2017-12-19 12:23:48 +000047 // FIXME: officially P.character counts UTF-16 code units, not UTF-8 bytes!
Simon Marchi766338a2018-03-21 14:36:46 +000048 return std::min(NextNL, StartOfLine + P.character);
Sam McCallb536a2a2017-12-19 12:23:48 +000049}
50
51Position 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!
Ilya Biryukov7beea3a2018-02-14 10:52:04 +000058 Position Pos;
59 Pos.line = Lines;
60 Pos.character = static_cast<int>(Offset - StartOfLine);
61 return Pos;
Sam McCallb536a2a2017-12-19 12:23:48 +000062}
63
Marc-Andre Laperle63a10982018-02-21 02:39:08 +000064Position 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
Ilya Biryukov71028b82018-03-12 15:28:22 +000071Range 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
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +000079std::pair<llvm::StringRef, llvm::StringRef>
80splitQualifiedName(llvm::StringRef QName) {
81 size_t Pos = QName.rfind("::");
82 if (Pos == llvm::StringRef::npos)
83 return {StringRef(), QName};
84 return {QName.substr(0, Pos + 2), QName.substr(Pos + 2)};
85}
86
Sam McCallb536a2a2017-12-19 12:23:48 +000087} // namespace clangd
88} // namespace clang