[clang-tools-extra] r321073 - [clangd] Expose offset <-> LSP position functions, and fix bugs

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 19 04:23:48 PST 2017


Author: sammccall
Date: Tue Dec 19 04:23:48 2017
New Revision: 321073

URL: http://llvm.org/viewvc/llvm-project?rev=321073&view=rev
Log:
[clangd] Expose offset <-> LSP position functions, and fix bugs

Summary:
- Moved these functions to SourceCode.h
- added unit tests
- fix off by one in positionToOffset: Offset - 1 in final calculation was wrong
- fixed formatOnType which had an equal and opposite off-by-one
- positionToOffset and offsetToPosition both consistently clamp to beginning/end
  of file when input is out of range
- gave variables more descriptive names
- removed windows line ending fixmes where there is nothing to fix
- elaborated on UTF-8 fixmes

This will conflict with Eric's D41281, but in a pretty easy-to-resolve way.

Reviewers: ioeric

Subscribers: klimek, mgorny, ilya-biryukov, cfe-commits

Differential Revision: https://reviews.llvm.org/D41351

Added:
    clang-tools-extra/trunk/clangd/SourceCode.cpp
    clang-tools-extra/trunk/clangd/SourceCode.h
    clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp
Modified:
    clang-tools-extra/trunk/clangd/CMakeLists.txt
    clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
    clang-tools-extra/trunk/clangd/ClangdServer.cpp
    clang-tools-extra/trunk/clangd/ClangdServer.h
    clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
    clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp

Modified: clang-tools-extra/trunk/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=321073&r1=321072&r2=321073&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/CMakeLists.txt Tue Dec 19 04:23:48 2017
@@ -18,6 +18,7 @@ add_clang_library(clangDaemon
   Logger.cpp
   Protocol.cpp
   ProtocolHandlers.cpp
+  SourceCode.cpp
   Trace.cpp
   index/FileIndex.cpp
   index/Index.cpp

Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=321073&r1=321072&r2=321073&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Tue Dec 19 04:23:48 2017
@@ -9,6 +9,7 @@
 
 #include "ClangdLSPServer.h"
 #include "JSONRPCDispatcher.h"
+#include "SourceCode.h"
 #include "llvm/Support/FormatVariadic.h"
 
 using namespace clang::clangd;

Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=321073&r1=321072&r2=321073&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Tue Dec 19 04:23:48 2017
@@ -8,6 +8,7 @@
 //===-------------------------------------------------------------------===//
 
 #include "ClangdServer.h"
+#include "SourceCode.h"
 #include "clang/Format/Format.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -57,29 +58,6 @@ public:
 
 } // namespace
 
-size_t clangd::positionToOffset(StringRef Code, Position P) {
-  size_t Offset = 0;
-  for (int I = 0; I != P.line; ++I) {
-    // FIXME: \r\n
-    // FIXME: UTF-8
-    size_t F = Code.find('\n', Offset);
-    if (F == StringRef::npos)
-      return 0; // FIXME: Is this reasonable?
-    Offset = F + 1;
-  }
-  return (Offset == 0 ? 0 : (Offset - 1)) + P.character;
-}
-
-/// Turn an offset in Code into a [line, column] pair.
-Position clangd::offsetToPosition(StringRef Code, size_t Offset) {
-  StringRef JustBefore = Code.substr(0, Offset);
-  // FIXME: \r\n
-  // FIXME: UTF-8
-  int Lines = JustBefore.count('\n');
-  int Cols = JustBefore.size() - JustBefore.rfind('\n') - 1;
-  return {Lines, Cols};
-}
-
 Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
 RealFileSystemProvider::getTaggedFileSystem(PathRef File) {
   return make_tagged(vfs::getRealFileSystem(), VFSTag());
@@ -337,7 +315,7 @@ ClangdServer::formatOnType(StringRef Cod
   size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos);
   if (PreviousLBracePos == StringRef::npos)
     PreviousLBracePos = CursorPos;
-  size_t Len = 1 + CursorPos - PreviousLBracePos;
+  size_t Len = CursorPos - PreviousLBracePos;
 
   return formatCode(Code, File, {tooling::Range(PreviousLBracePos, Len)});
 }

Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=321073&r1=321072&r2=321073&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Tue Dec 19 04:23:48 2017
@@ -35,12 +35,6 @@ class PCHContainerOperations;
 
 namespace clangd {
 
-/// Turn a [line, column] pair into an offset in Code.
-size_t positionToOffset(StringRef Code, Position P);
-
-/// Turn an offset in Code into a [line, column] pair.
-Position offsetToPosition(StringRef Code, size_t Offset);
-
 /// A tag supplied by the FileSytemProvider.
 typedef std::string VFSTag;
 

Added: clang-tools-extra/trunk/clangd/SourceCode.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SourceCode.cpp?rev=321073&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/SourceCode.cpp (added)
+++ clang-tools-extra/trunk/clangd/SourceCode.cpp Tue Dec 19 04:23:48 2017
@@ -0,0 +1,41 @@
+//===--- SourceCode.h - Manipulating source code as strings -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "SourceCode.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+size_t positionToOffset(StringRef Code, Position P) {
+  if (P.line < 0)
+    return 0;
+  size_t StartOfLine = 0;
+  for (int I = 0; I != P.line; ++I) {
+    size_t NextNL = Code.find('\n', StartOfLine);
+    if (NextNL == StringRef::npos)
+      return Code.size();
+    StartOfLine = NextNL + 1;
+  }
+  // FIXME: officially P.character counts UTF-16 code units, not UTF-8 bytes!
+  return std::min(Code.size(), StartOfLine + std::max(0, P.character));
+}
+
+Position offsetToPosition(StringRef Code, size_t Offset) {
+  Offset = std::min(Code.size(), Offset);
+  StringRef Before = Code.substr(0, Offset);
+  int Lines = Before.count('\n');
+  size_t PrevNL = Before.rfind('\n');
+  size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
+  // FIXME: officially character counts UTF-16 code units, not UTF-8 bytes!
+  return {Lines, static_cast<int>(Offset - StartOfLine)};
+}
+
+} // namespace clangd
+} // namespace clang
+

Added: clang-tools-extra/trunk/clangd/SourceCode.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/SourceCode.h?rev=321073&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/SourceCode.h (added)
+++ clang-tools-extra/trunk/clangd/SourceCode.h Tue Dec 19 04:23:48 2017
@@ -0,0 +1,29 @@
+//===--- SourceCode.h - Manipulating source code as strings -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various code that examines C++ source code without using heavy AST machinery
+// (and often not even the lexer). To be used sparingly!
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SOURCECODE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SOURCECODE_H
+#include "Protocol.h"
+
+namespace clang {
+namespace clangd {
+
+/// Turn a [line, column] pair into an offset in Code.
+size_t positionToOffset(llvm::StringRef Code, Position P);
+
+/// Turn an offset in Code into a [line, column] pair.
+Position offsetToPosition(llvm::StringRef Code, size_t Offset);
+
+} // namespace clangd
+} // namespace clang
+#endif

Modified: clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt?rev=321073&r1=321072&r2=321073&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt Tue Dec 19 04:23:48 2017
@@ -18,6 +18,7 @@ add_extra_unittest(ClangdTests
   JSONExprTests.cpp
   TestFS.cpp
   TraceTests.cpp
+  SourceCodeTests.cpp
   SymbolCollectorTests.cpp
   )
 

Modified: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp?rev=321073&r1=321072&r2=321073&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Tue Dec 19 04:23:48 2017
@@ -11,6 +11,7 @@
 #include "Context.h"
 #include "Matchers.h"
 #include "Protocol.h"
+#include "SourceCode.h"
 #include "TestFS.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"

Added: clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp?rev=321073&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp (added)
+++ clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp Tue Dec 19 04:23:48 2017
@@ -0,0 +1,76 @@
+//===-- SourceCodeTests.cpp  ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "SourceCode.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang{
+namespace clangd {
+void PrintTo(const Position &P, std::ostream *O) {
+  llvm::raw_os_ostream OS(*O);
+  OS << toJSON(P);
+}
+namespace {
+
+MATCHER_P2(Pos, Line, Col, "") {
+  return arg.line == Line && arg.character == Col;
+}
+
+const char File[] = R"(0:0 = 0
+1:0 = 8
+2:0 = 16)";
+
+TEST(SourceCodeTests, PositionToOffset) {
+  // line out of bounds
+  EXPECT_EQ(0u, positionToOffset(File, Position{-1, 2}));
+  // first line
+  EXPECT_EQ(0u, positionToOffset(File, Position{0, -1})); // out of range
+  EXPECT_EQ(0u, positionToOffset(File, Position{0, 0})); // first character
+  EXPECT_EQ(3u, positionToOffset(File, Position{0, 3})); // middle character
+  EXPECT_EQ(6u, positionToOffset(File, Position{0, 6})); // last character
+  EXPECT_EQ(7u, positionToOffset(File, Position{0, 7})); // the newline itself
+  EXPECT_EQ(8u, positionToOffset(File, Position{0, 8})); // out of range
+  // middle line
+  EXPECT_EQ(8u, positionToOffset(File, Position{1, -1})); // out of range
+  EXPECT_EQ(8u, positionToOffset(File, Position{1, 0})); // first character
+  EXPECT_EQ(11u, positionToOffset(File, Position{1, 3})); // middle character
+  EXPECT_EQ(14u, positionToOffset(File, Position{1, 6})); // last character
+  EXPECT_EQ(15u, positionToOffset(File, Position{1, 7})); // the newline itself
+  EXPECT_EQ(16u, positionToOffset(File, Position{1, 8})); // out of range
+  // last line
+  EXPECT_EQ(16u, positionToOffset(File, Position{2, -1})); // out of range
+  EXPECT_EQ(16u, positionToOffset(File, Position{2, 0})); // first character
+  EXPECT_EQ(19u, positionToOffset(File, Position{2, 3})); // middle character
+  EXPECT_EQ(23u, positionToOffset(File, Position{2, 7})); // last character
+  EXPECT_EQ(24u, positionToOffset(File, Position{2, 8})); // EOF
+  EXPECT_EQ(24u, positionToOffset(File, Position{2, 9})); // out of range
+  // line out of bounds
+  EXPECT_EQ(24u, positionToOffset(File, Position{3, 1}));
+}
+
+TEST(SourceCodeTests, OffsetToPosition) {
+  EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file";
+  EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line";
+  EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line";
+  EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline";
+  EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line";
+  EXPECT_THAT(offsetToPosition(File, 11), Pos(1, 3)) << "in second line";
+  EXPECT_THAT(offsetToPosition(File, 14), Pos(1, 6)) << "end of second line";
+  EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 7)) << "second newline";
+  EXPECT_THAT(offsetToPosition(File, 16), Pos(2, 0)) << "start of last line";
+  EXPECT_THAT(offsetToPosition(File, 19), Pos(2, 3)) << "in last line";
+  EXPECT_THAT(offsetToPosition(File, 23), Pos(2, 7)) << "end of last line";
+  EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 8)) << "EOF";
+  EXPECT_THAT(offsetToPosition(File, 25), Pos(2, 8)) << "out of bounds";
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang




More information about the cfe-commits mailing list