Author: ioeric
Date: Wed Dec 20 09:24:31 2017
New Revision: 321193

URL: http://llvm.org/viewvc/llvm-project?rev=321193&view=rev
Log:
[clangd] Pull CodeCompletionString handling logic into its own file and add 
unit test.

Reviewers: sammccall

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

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

Added:
    clang-tools-extra/trunk/clangd/CodeCompletionStrings.cpp
    clang-tools-extra/trunk/clangd/CodeCompletionStrings.h
    clang-tools-extra/trunk/unittests/clangd/CodeCompletionStringsTests.cpp
Modified:
    clang-tools-extra/trunk/clangd/CMakeLists.txt
    clang-tools-extra/trunk/clangd/CodeComplete.cpp
    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=321193&r1=321192&r2=321193&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/CMakeLists.txt Wed Dec 20 09:24:31 2017
@@ -8,6 +8,7 @@ add_clang_library(clangDaemon
   ClangdUnit.cpp
   ClangdUnitStore.cpp
   CodeComplete.cpp
+  CodeCompletionStrings.cpp
   Context.cpp
   Compiler.cpp
   DraftStore.cpp

Modified: clang-tools-extra/trunk/clangd/CodeComplete.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CodeComplete.cpp?rev=321193&r1=321192&r2=321193&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CodeComplete.cpp (original)
+++ clang-tools-extra/trunk/clangd/CodeComplete.cpp Wed Dec 20 09:24:31 2017
@@ -15,6 +15,7 @@
 //===---------------------------------------------------------------------===//
 
 #include "CodeComplete.h"
+#include "CodeCompletionStrings.h"
 #include "Compiler.h"
 #include "Logger.h"
 #include "index/Index.h"
@@ -144,46 +145,6 @@ CompletionItemKind toCompletionItemKind(
   llvm_unreachable("Unhandled clang::index::SymbolKind.");
 }
 
-std::string escapeSnippet(const llvm::StringRef Text) {
-  std::string Result;
-  Result.reserve(Text.size()); // Assume '$', '}' and '\\' are rare.
-  for (const auto Character : Text) {
-    if (Character == '$' || Character == '}' || Character == '\\')
-      Result.push_back('\\');
-    Result.push_back(Character);
-  }
-  return Result;
-}
-
-std::string getDocumentation(const CodeCompletionString &CCS) {
-  // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
-  // information in the documentation field.
-  std::string Result;
-  const unsigned AnnotationCount = CCS.getAnnotationCount();
-  if (AnnotationCount > 0) {
-    Result += "Annotation";
-    if (AnnotationCount == 1) {
-      Result += ": ";
-    } else /* AnnotationCount > 1 */ {
-      Result += "s: ";
-    }
-    for (unsigned I = 0; I < AnnotationCount; ++I) {
-      Result += CCS.getAnnotation(I);
-      Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
-    }
-  }
-  // Add brief documentation (if there is any).
-  if (CCS.getBriefComment() != nullptr) {
-    if (!Result.empty()) {
-      // This means we previously added annotations. Add an extra newline
-      // character to make the annotations stand out.
-      Result.push_back('\n');
-    }
-    Result += CCS.getBriefComment();
-  }
-  return Result;
-}
-
 /// Get the optional chunk as a string. This function is possibly recursive.
 ///
 /// The parameter info for each parameter is appended to the Parameters.
@@ -320,7 +281,8 @@ public:
                              /*OutputIsBinary=*/false),
         ClangdOpts(CodeCompleteOpts), Items(Items),
         Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
-        CCTUInfo(Allocator), CompletedName(CompletedName) {}
+        CCTUInfo(Allocator), CompletedName(CompletedName),
+        EnableSnippets(CodeCompleteOpts.EnableSnippets) {}
 
   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
                                   CodeCompletionResult *Results,
@@ -402,14 +364,16 @@ private:
     // Adjust this to InsertTextFormat::Snippet iff we encounter a
     // CK_Placeholder chunk in SnippetCompletionItemsCollector.
     CompletionItem Item;
-    Item.insertTextFormat = InsertTextFormat::PlainText;
 
     Item.documentation = getDocumentation(CCS);
     Item.sortText = Candidate.sortText();
 
-    // Fill in the label, detail, insertText and filterText fields of the
-    // CompletionItem.
-    ProcessChunks(CCS, Item);
+    Item.detail = getDetail(CCS);
+    Item.filterText = getFilterText(CCS);
+    getLabelAndInsertText(CCS, &Item.label, &Item.insertText, EnableSnippets);
+
+    Item.insertTextFormat = EnableSnippets ? InsertTextFormat::Snippet
+                                           : InsertTextFormat::PlainText;
 
     // Fill in the kind field of the CompletionItem.
     Item.kind = toCompletionItemKind(Candidate.Result->Kind,
@@ -418,170 +382,14 @@ private:
     return Item;
   }
 
-  virtual void ProcessChunks(const CodeCompletionString &CCS,
-                             CompletionItem &Item) const = 0;
-
   CodeCompleteOptions ClangdOpts;
   CompletionList &Items;
   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
   CodeCompletionTUInfo CCTUInfo;
   NameToComplete &CompletedName;
+  bool EnableSnippets;
 }; // CompletionItemsCollector
 
-bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
-  return Chunk.Kind == CodeCompletionString::CK_Informative &&
-         StringRef(Chunk.Text).endswith("::");
-}
-
-class PlainTextCompletionItemsCollector final
-    : public CompletionItemsCollector {
-
-public:
-  PlainTextCompletionItemsCollector(const CodeCompleteOptions 
&CodeCompleteOpts,
-                                    CompletionList &Items,
-                                    NameToComplete &CompletedName)
-      : CompletionItemsCollector(CodeCompleteOpts, Items, CompletedName) {}
-
-private:
-  void ProcessChunks(const CodeCompletionString &CCS,
-                     CompletionItem &Item) const override {
-    for (const auto &Chunk : CCS) {
-      // Informative qualifier chunks only clutter completion results, skip
-      // them.
-      if (isInformativeQualifierChunk(Chunk))
-        continue;
-
-      switch (Chunk.Kind) {
-      case CodeCompletionString::CK_TypedText:
-        // There's always exactly one CK_TypedText chunk.
-        Item.insertText = Item.filterText = Chunk.Text;
-        Item.label += Chunk.Text;
-        break;
-      case CodeCompletionString::CK_ResultType:
-        assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
-        Item.detail = Chunk.Text;
-        break;
-      case CodeCompletionString::CK_Optional:
-        break;
-      default:
-        Item.label += Chunk.Text;
-        break;
-      }
-    }
-  }
-}; // PlainTextCompletionItemsCollector
-
-class SnippetCompletionItemsCollector final : public CompletionItemsCollector {
-
-public:
-  SnippetCompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
-                                  CompletionList &Items,
-                                  NameToComplete &CompletedName)
-      : CompletionItemsCollector(CodeCompleteOpts, Items, CompletedName) {}
-
-private:
-  void ProcessChunks(const CodeCompletionString &CCS,
-                     CompletionItem &Item) const override {
-    unsigned ArgCount = 0;
-    for (const auto &Chunk : CCS) {
-      // Informative qualifier chunks only clutter completion results, skip
-      // them.
-      if (isInformativeQualifierChunk(Chunk))
-        continue;
-
-      switch (Chunk.Kind) {
-      case CodeCompletionString::CK_TypedText:
-        // The piece of text that the user is expected to type to match
-        // the code-completion string, typically a keyword or the name of
-        // a declarator or macro.
-        Item.filterText = Chunk.Text;
-        LLVM_FALLTHROUGH;
-      case CodeCompletionString::CK_Text:
-        // A piece of text that should be placed in the buffer,
-        // e.g., parentheses or a comma in a function call.
-        Item.label += Chunk.Text;
-        Item.insertText += Chunk.Text;
-        break;
-      case CodeCompletionString::CK_Optional:
-        // A code completion string that is entirely optional.
-        // For example, an optional code completion string that
-        // describes the default arguments in a function call.
-
-        // FIXME: Maybe add an option to allow presenting the optional chunks?
-        break;
-      case CodeCompletionString::CK_Placeholder:
-        // A string that acts as a placeholder for, e.g., a function call
-        // argument.
-        ++ArgCount;
-        Item.insertText += "${" + std::to_string(ArgCount) + ':' +
-                           escapeSnippet(Chunk.Text) + '}';
-        Item.label += Chunk.Text;
-        Item.insertTextFormat = InsertTextFormat::Snippet;
-        break;
-      case CodeCompletionString::CK_Informative:
-        // A piece of text that describes something about the result
-        // but should not be inserted into the buffer.
-        // For example, the word "const" for a const method, or the name of
-        // the base class for methods that are part of the base class.
-        Item.label += Chunk.Text;
-        // Don't put the informative chunks in the insertText.
-        break;
-      case CodeCompletionString::CK_ResultType:
-        // A piece of text that describes the type of an entity or,
-        // for functions and methods, the return type.
-        assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
-        Item.detail = Chunk.Text;
-        break;
-      case CodeCompletionString::CK_CurrentParameter:
-        // A piece of text that describes the parameter that corresponds to
-        // the code-completion location within a function call, message send,
-        // macro invocation, etc.
-        //
-        // This should never be present while collecting completion items,
-        // only while collecting overload candidates.
-        llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
-                         "CompletionItems");
-        break;
-      case CodeCompletionString::CK_LeftParen:
-        // A left parenthesis ('(').
-      case CodeCompletionString::CK_RightParen:
-        // A right parenthesis (')').
-      case CodeCompletionString::CK_LeftBracket:
-        // A left bracket ('[').
-      case CodeCompletionString::CK_RightBracket:
-        // A right bracket (']').
-      case CodeCompletionString::CK_LeftBrace:
-        // A left brace ('{').
-      case CodeCompletionString::CK_RightBrace:
-        // A right brace ('}').
-      case CodeCompletionString::CK_LeftAngle:
-        // A left angle bracket ('<').
-      case CodeCompletionString::CK_RightAngle:
-        // A right angle bracket ('>').
-      case CodeCompletionString::CK_Comma:
-        // A comma separator (',').
-      case CodeCompletionString::CK_Colon:
-        // A colon (':').
-      case CodeCompletionString::CK_SemiColon:
-        // A semicolon (';').
-      case CodeCompletionString::CK_Equal:
-        // An '=' sign.
-      case CodeCompletionString::CK_HorizontalSpace:
-        // Horizontal whitespace (' ').
-        Item.insertText += Chunk.Text;
-        Item.label += Chunk.Text;
-        break;
-      case CodeCompletionString::CK_VerticalSpace:
-        // Vertical whitespace ('\n' or '\r\n', depending on the
-        // platform).
-        Item.insertText += Chunk.Text;
-        // Don't even add a space to the label.
-        break;
-      }
-    }
-  }
-}; // SnippetCompletionItemsCollector
-
 class SignatureHelpCollector final : public CodeCompleteConsumer {
 
 public:
@@ -617,6 +425,8 @@ public:
   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
 
 private:
+  // FIXME(ioeric): consider moving CodeCompletionString logic here to
+  // CompletionString.h.
   SignatureInformation
   ProcessOverloadCandidate(const OverloadCandidate &Candidate,
                            const CodeCompletionString &CCS) const {
@@ -817,15 +627,9 @@ CompletionList codeComplete(const Contex
                             std::shared_ptr<PCHContainerOperations> PCHs,
                             CodeCompleteOptions Opts) {
   CompletionList Results;
-  std::unique_ptr<CodeCompleteConsumer> Consumer;
   NameToComplete CompletedName;
-  if (Opts.EnableSnippets) {
-    Consumer = llvm::make_unique<SnippetCompletionItemsCollector>(
-        Opts, Results, CompletedName);
-  } else {
-    Consumer = llvm::make_unique<PlainTextCompletionItemsCollector>(
-        Opts, Results, CompletedName);
-  }
+  auto Consumer =
+      llvm::make_unique<CompletionItemsCollector>(Opts, Results, 
CompletedName);
   invokeCodeComplete(Ctx, std::move(Consumer), Opts.getClangCompleteOpts(),
                      FileName, Command, Preamble, Contents, Pos, 
std::move(VFS),
                      std::move(PCHs));

Added: clang-tools-extra/trunk/clangd/CodeCompletionStrings.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CodeCompletionStrings.cpp?rev=321193&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/CodeCompletionStrings.cpp (added)
+++ clang-tools-extra/trunk/clangd/CodeCompletionStrings.cpp Wed Dec 20 
09:24:31 2017
@@ -0,0 +1,188 @@
+//===--- CodeCompletionStrings.cpp -------------------------------*- 
C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "CodeCompletionStrings.h"
+#include <utility>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
+  return Chunk.Kind == CodeCompletionString::CK_Informative &&
+         StringRef(Chunk.Text).endswith("::");
+}
+
+void processPlainTextChunks(const CodeCompletionString &CCS,
+                            std::string *LabelOut, std::string *InsertTextOut) 
{
+  std::string &Label = *LabelOut;
+  std::string &InsertText = *InsertTextOut;
+  for (const auto &Chunk : CCS) {
+    // Informative qualifier chunks only clutter completion results, skip
+    // them.
+    if (isInformativeQualifierChunk(Chunk))
+      continue;
+
+    switch (Chunk.Kind) {
+    case CodeCompletionString::CK_ResultType:
+    case CodeCompletionString::CK_Optional:
+      break;
+    case CodeCompletionString::CK_TypedText:
+      InsertText += Chunk.Text;
+      Label += Chunk.Text;
+      break;
+    default:
+      Label += Chunk.Text;
+      break;
+    }
+  }
+}
+
+void appendEscapeSnippet(const llvm::StringRef Text, std::string *Out) {
+  for (const auto Character : Text) {
+    if (Character == '$' || Character == '}' || Character == '\\')
+      Out->push_back('\\');
+    Out->push_back(Character);
+  }
+}
+
+void processSnippetChunks(const CodeCompletionString &CCS,
+                          std::string *LabelOut, std::string *InsertTextOut) {
+  std::string &Label = *LabelOut;
+  std::string &InsertText = *InsertTextOut;
+
+  unsigned ArgCount = 0;
+  for (const auto &Chunk : CCS) {
+    // Informative qualifier chunks only clutter completion results, skip
+    // them.
+    if (isInformativeQualifierChunk(Chunk))
+      continue;
+
+    switch (Chunk.Kind) {
+    case CodeCompletionString::CK_TypedText:
+    case CodeCompletionString::CK_Text:
+      Label += Chunk.Text;
+      InsertText += Chunk.Text;
+      break;
+    case CodeCompletionString::CK_Optional:
+      // FIXME: Maybe add an option to allow presenting the optional chunks?
+      break;
+    case CodeCompletionString::CK_Placeholder:
+      ++ArgCount;
+      InsertText += "${" + std::to_string(ArgCount) + ':';
+      appendEscapeSnippet(Chunk.Text, &InsertText);
+      InsertText += '}';
+      Label += Chunk.Text;
+      break;
+    case CodeCompletionString::CK_Informative:
+      // For example, the word "const" for a const method, or the name of
+      // the base class for methods that are part of the base class.
+      Label += Chunk.Text;
+      // Don't put the informative chunks in the insertText.
+      break;
+    case CodeCompletionString::CK_ResultType:
+      // This is retrieved as detail.
+      break;
+    case CodeCompletionString::CK_CurrentParameter:
+      // This should never be present while collecting completion items,
+      // only while collecting overload candidates.
+      llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
+                       "CompletionItems");
+      break;
+    case CodeCompletionString::CK_LeftParen:
+    case CodeCompletionString::CK_RightParen:
+    case CodeCompletionString::CK_LeftBracket:
+    case CodeCompletionString::CK_RightBracket:
+    case CodeCompletionString::CK_LeftBrace:
+    case CodeCompletionString::CK_RightBrace:
+    case CodeCompletionString::CK_LeftAngle:
+    case CodeCompletionString::CK_RightAngle:
+    case CodeCompletionString::CK_Comma:
+    case CodeCompletionString::CK_Colon:
+    case CodeCompletionString::CK_SemiColon:
+    case CodeCompletionString::CK_Equal:
+    case CodeCompletionString::CK_HorizontalSpace:
+      InsertText += Chunk.Text;
+      Label += Chunk.Text;
+      break;
+    case CodeCompletionString::CK_VerticalSpace:
+      InsertText += Chunk.Text;
+      // Don't even add a space to the label.
+      break;
+    }
+  }
+}
+
+} // namespace
+
+void getLabelAndInsertText(const CodeCompletionString &CCS, std::string *Label,
+                           std::string *InsertText, bool EnableSnippets) {
+  return EnableSnippets ? processSnippetChunks(CCS, Label, InsertText)
+                        : processPlainTextChunks(CCS, Label, InsertText);
+}
+
+std::string getDocumentation(const CodeCompletionString &CCS) {
+  // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
+  // information in the documentation field.
+  std::string Result;
+  const unsigned AnnotationCount = CCS.getAnnotationCount();
+  if (AnnotationCount > 0) {
+    Result += "Annotation";
+    if (AnnotationCount == 1) {
+      Result += ": ";
+    } else /* AnnotationCount > 1 */ {
+      Result += "s: ";
+    }
+    for (unsigned I = 0; I < AnnotationCount; ++I) {
+      Result += CCS.getAnnotation(I);
+      Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
+    }
+  }
+  // Add brief documentation (if there is any).
+  if (CCS.getBriefComment() != nullptr) {
+    if (!Result.empty()) {
+      // This means we previously added annotations. Add an extra newline
+      // character to make the annotations stand out.
+      Result.push_back('\n');
+    }
+    Result += CCS.getBriefComment();
+  }
+  return Result;
+}
+
+std::string getDetail(const CodeCompletionString &CCS) {
+  for (const auto &Chunk : CCS) {
+    // Informative qualifier chunks only clutter completion results, skip
+    // them.
+    switch (Chunk.Kind) {
+    case CodeCompletionString::CK_ResultType:
+      return Chunk.Text;
+    default:
+      break;
+    }
+  }
+  return "";
+}
+
+std::string getFilterText(const CodeCompletionString &CCS) {
+  for (const auto &Chunk : CCS) {
+    switch (Chunk.Kind) {
+    case CodeCompletionString::CK_TypedText:
+      // There's always exactly one CK_TypedText chunk.
+      return Chunk.Text;
+    default:
+      break;
+    }
+  }
+  return "";
+}
+
+} // namespace clangd
+} // namespace clang

Added: clang-tools-extra/trunk/clangd/CodeCompletionStrings.h
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CodeCompletionStrings.h?rev=321193&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/CodeCompletionStrings.h (added)
+++ clang-tools-extra/trunk/clangd/CodeCompletionStrings.h Wed Dec 20 09:24:31 
2017
@@ -0,0 +1,46 @@
+//===--- CodeCompletionStrings.h ---------------------------------*- 
C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Functions for retrieving code completion information from
+// `CodeCompletionString`.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETIONSTRINGS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETIONSTRINGS_H
+
+#include "clang/Sema/CodeCompleteConsumer.h"
+
+namespace clang {
+namespace clangd {
+
+/// Gets label and insert text for a completion item. For example, for function
+/// `Foo`, this returns <"Foo(int x, int y)", "Foo"> without snippts enabled.
+///
+/// If \p EnableSnippets is true, this will try to use snippet for the insert
+/// text. Otherwise, the insert text will always be plain text.
+void getLabelAndInsertText(const CodeCompletionString &CCS, std::string *Label,
+                           std::string *InsertText, bool EnableSnippets);
+
+/// Gets the documentation for a completion item. For example, comment for the
+/// a class declaration.
+std::string getDocumentation(const CodeCompletionString &CCS);
+
+/// Gets detail to be used as the detail field in an LSP completion item. This
+/// is usually the return type of a function.
+std::string getDetail(const CodeCompletionString &CCS);
+
+/// Gets the piece of text that the user is expected to type to match the
+/// code-completion string, typically a keyword or the name of a declarator or
+/// macro.
+std::string getFilterText(const CodeCompletionString &CCS);
+
+} // 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=321193&r1=321192&r2=321193&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt Wed Dec 20 09:24:31 
2017
@@ -12,6 +12,7 @@ add_extra_unittest(ClangdTests
   Annotations.cpp
   ClangdTests.cpp
   CodeCompleteTests.cpp
+  CodeCompletionStringsTests.cpp
   ContextTests.cpp
   FileIndexTests.cpp
   FuzzyMatchTests.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=321193&r1=321192&r2=321193&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Wed Dec 20 
09:24:31 2017
@@ -341,7 +341,7 @@ TEST(CompletionTest, Snippets) {
       )cpp",
       Opts);
   EXPECT_THAT(Results.items,
-              HasSubsequence(PlainText("a"),
+              HasSubsequence(Snippet("a"),
                              Snippet("f(${1:int i}, ${2:const float f})")));
 }
 

Added: clang-tools-extra/trunk/unittests/clangd/CodeCompletionStringsTests.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CodeCompletionStringsTests.cpp?rev=321193&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CodeCompletionStringsTests.cpp 
(added)
+++ clang-tools-extra/trunk/unittests/clangd/CodeCompletionStringsTests.cpp Wed 
Dec 20 09:24:31 2017
@@ -0,0 +1,142 @@
+//===-- CodeCompletionStringsTests.cpp --------------------------*- C++ 
-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeCompletionStrings.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+class CompletionStringTest : public ::testing::Test {
+public:
+  CompletionStringTest()
+      : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+        CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}
+
+protected:
+  void labelAndInsertText(const CodeCompletionString &CCS,
+                          bool EnableSnippets = false) {
+    Label.clear();
+    InsertText.clear();
+    getLabelAndInsertText(CCS, &Label, &InsertText, EnableSnippets);
+  }
+
+  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+  CodeCompletionTUInfo CCTUInfo;
+  CodeCompletionBuilder Builder;
+  std::string Label;
+  std::string InsertText;
+};
+
+TEST_F(CompletionStringTest, Detail) {
+  Builder.AddResultTypeChunk("result");
+  Builder.AddResultTypeChunk("redundant result no no");
+  EXPECT_EQ(getDetail(*Builder.TakeString()), "result");
+}
+
+TEST_F(CompletionStringTest, FilterText) {
+  Builder.AddTypedTextChunk("typed");
+  Builder.AddTypedTextChunk("redundant typed no no");
+  auto *S = Builder.TakeString();
+  EXPECT_EQ(getFilterText(*S), "typed");
+}
+
+TEST_F(CompletionStringTest, Documentation) {
+  Builder.addBriefComment("Is this brief?");
+  EXPECT_EQ(getDocumentation(*Builder.TakeString()), "Is this brief?");
+}
+
+TEST_F(CompletionStringTest, DocumentationWithAnnotation) {
+  Builder.addBriefComment("Is this brief?");
+  Builder.AddAnnotation("Ano");
+  EXPECT_EQ(getDocumentation(*Builder.TakeString()),
+            "Annotation: Ano\n\nIs this brief?");
+}
+
+TEST_F(CompletionStringTest, MultipleAnnotations) {
+  Builder.AddAnnotation("Ano1");
+  Builder.AddAnnotation("Ano2");
+  Builder.AddAnnotation("Ano3");
+
+  EXPECT_EQ(getDocumentation(*Builder.TakeString()),
+            "Annotations: Ano1 Ano2 Ano3\n");
+}
+
+TEST_F(CompletionStringTest, SimpleLabelAndInsert) {
+  Builder.AddTypedTextChunk("X");
+  Builder.AddResultTypeChunk("result no no");
+  labelAndInsertText(*Builder.TakeString());
+  EXPECT_EQ(Label, "X");
+  EXPECT_EQ(InsertText, "X");
+}
+
+TEST_F(CompletionStringTest, FunctionPlainText) {
+  Builder.AddResultTypeChunk("result no no");
+  Builder.AddTypedTextChunk("Foo");
+  Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+  Builder.AddPlaceholderChunk("p1");
+  Builder.AddChunk(CodeCompletionString::CK_Comma);
+  Builder.AddPlaceholderChunk("p2");
+  Builder.AddChunk(CodeCompletionString::CK_RightParen);
+  Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+  Builder.AddInformativeChunk("const");
+
+  labelAndInsertText(*Builder.TakeString());
+  EXPECT_EQ(Label, "Foo(p1, p2) const");
+  EXPECT_EQ(InsertText, "Foo");
+}
+
+TEST_F(CompletionStringTest, FunctionSnippet) {
+  Builder.AddResultTypeChunk("result no no");
+  Builder.addBriefComment("Foo's comment");
+  Builder.AddTypedTextChunk("Foo");
+  Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+  Builder.AddPlaceholderChunk("p1");
+  Builder.AddChunk(CodeCompletionString::CK_Comma);
+  Builder.AddPlaceholderChunk("p2");
+  Builder.AddChunk(CodeCompletionString::CK_RightParen);
+
+  auto *CCS = Builder.TakeString();
+  labelAndInsertText(*CCS);
+  EXPECT_EQ(Label, "Foo(p1, p2)");
+  EXPECT_EQ(InsertText, "Foo");
+
+  labelAndInsertText(*CCS, /*EnableSnippets=*/true);
+  EXPECT_EQ(Label, "Foo(p1, p2)");
+  EXPECT_EQ(InsertText, "Foo(${1:p1}, ${2:p2})");
+  EXPECT_EQ(getDocumentation(*CCS), "Foo's comment");
+  EXPECT_EQ(getFilterText(*CCS), "Foo");
+}
+
+TEST_F(CompletionStringTest, EscapeSnippet) {
+  Builder.AddTypedTextChunk("Foo");
+  Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+  Builder.AddPlaceholderChunk("$p}1\\");
+  Builder.AddChunk(CodeCompletionString::CK_RightParen);
+
+  labelAndInsertText(*Builder.TakeString(), /*EnableSnippets=*/true);
+  EXPECT_EQ(Label, "Foo($p}1\\)");
+  EXPECT_EQ(InsertText, "Foo(${1:\\$p\\}1\\\\})");
+}
+
+TEST_F(CompletionStringTest, IgnoreInformativeQualifier) {
+  Builder.AddTypedTextChunk("X");
+  Builder.AddInformativeChunk("info ok");
+  Builder.AddInformativeChunk("info no no::");
+  labelAndInsertText(*Builder.TakeString());
+  EXPECT_EQ(Label, "Xinfo ok");
+  EXPECT_EQ(InsertText, "X");
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to