This revision was automatically updated to reflect the committed changes.
Closed by commit rL299421: [clangd] Add code completion support (authored by 
krasimir).

Changed prior to commit:
  https://reviews.llvm.org/D31328?vs=92948&id=94026#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D31328

Files:
  clang-tools-extra/trunk/clangd/ASTManager.cpp
  clang-tools-extra/trunk/clangd/ASTManager.h
  clang-tools-extra/trunk/clangd/ClangDMain.cpp
  clang-tools-extra/trunk/clangd/Protocol.cpp
  clang-tools-extra/trunk/clangd/Protocol.h
  clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
  clang-tools-extra/trunk/clangd/ProtocolHandlers.h
  clang-tools-extra/trunk/test/clangd/completion.test
  clang-tools-extra/trunk/test/clangd/formatting.test

Index: clang-tools-extra/trunk/clangd/Protocol.cpp
===================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp
+++ clang-tools-extra/trunk/clangd/Protocol.cpp
@@ -570,3 +570,75 @@
   }
   return Result;
 }
+
+llvm::Optional<TextDocumentPositionParams>
+TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) {
+  TextDocumentPositionParams Result;
+  for (auto &NextKeyValue : *Params) {
+    auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+    if (!KeyString)
+      return llvm::None;
+
+    llvm::SmallString<10> KeyStorage;
+    StringRef KeyValue = KeyString->getValue(KeyStorage);
+    auto *Value =
+        dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
+    if (!Value)
+      return llvm::None;
+
+    llvm::SmallString<10> Storage;
+    if (KeyValue == "textDocument") {
+      auto Parsed = TextDocumentIdentifier::parse(Value);
+      if (!Parsed)
+        return llvm::None;
+      Result.textDocument = std::move(*Parsed);
+    } else if (KeyValue == "position") {
+      auto Parsed = Position::parse(Value);
+      if (!Parsed)
+        return llvm::None;
+      Result.position = std::move(*Parsed);
+    } else {
+      return llvm::None;
+    }
+  }
+  return Result;
+}
+
+std::string CompletionItem::unparse(const CompletionItem &CI) {
+  std::string Result = "{";
+  llvm::raw_string_ostream Os(Result);
+  assert(!CI.label.empty() && "completion item label is required");
+  Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";
+  if (CI.kind != CompletionItemKind::Missing)
+    Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(",)";
+  if (!CI.detail.empty())
+    Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";
+  if (!CI.documentation.empty())
+    Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation)
+       << R"(",)";
+  if (!CI.sortText.empty())
+    Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)";
+  if (!CI.filterText.empty())
+    Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)";
+  if (!CI.insertText.empty())
+    Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
+  if (CI.insertTextFormat != InsertTextFormat::Missing) {
+    Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat)
+       << R"(",)";
+  }
+  if (CI.textEdit)
+    Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';
+  if (!CI.additionalTextEdits.empty()) {
+    Os << R"("additionalTextEdits":[)";
+    for (const auto &Edit : CI.additionalTextEdits)
+      Os << TextEdit::unparse(Edit) << ",";
+    Os.flush();
+    // The list additionalTextEdits is guaranteed nonempty at this point.
+    // Replace the trailing comma with right brace.
+    Result.back() = ']';
+  }
+  Os.flush();
+  // Label is required, so Result is guaranteed to have a trailing comma.
+  Result.back() = '}';
+  return Result;
+}
Index: clang-tools-extra/trunk/clangd/ClangDMain.cpp
===================================================================
--- clang-tools-extra/trunk/clangd/ClangDMain.cpp
+++ clang-tools-extra/trunk/clangd/ClangDMain.cpp
@@ -61,6 +61,8 @@
       llvm::make_unique<TextDocumentFormattingHandler>(Out, Store));
   Dispatcher.registerHandler("textDocument/codeAction",
                              llvm::make_unique<CodeActionHandler>(Out, AST));
+  Dispatcher.registerHandler("textDocument/completion",
+                             llvm::make_unique<CompletionHandler>(Out, AST));
 
   while (std::cin.good()) {
     // A Language Server Protocol message starts with a HTTP header, delimited
Index: clang-tools-extra/trunk/clangd/ProtocolHandlers.h
===================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.h
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h
@@ -36,7 +36,8 @@
           "documentFormattingProvider": true,
           "documentRangeFormattingProvider": true,
           "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
-          "codeActionProvider": true
+          "codeActionProvider": true,
+          "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]}
         }}})");
   }
 };
@@ -114,6 +115,16 @@
   ASTManager &AST;
 };
 
+struct CompletionHandler : Handler {
+  CompletionHandler(JSONOutput &Output, ASTManager &AST)
+      : Handler(Output), AST(AST) {}
+
+  void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override;
+
+ private:
+  ASTManager &AST;
+};
+
 } // namespace clangd
 } // namespace clang
 
Index: clang-tools-extra/trunk/clangd/ASTManager.h
===================================================================
--- clang-tools-extra/trunk/clangd/ASTManager.h
+++ clang-tools-extra/trunk/clangd/ASTManager.h
@@ -36,7 +36,13 @@
 
   void onDocumentAdd(StringRef Uri) override;
   // FIXME: Implement onDocumentRemove
-  // FIXME: Implement codeComplete
+
+  /// Get code completions at a specified \p Line and \p Column in \p File.
+  ///
+  /// This function is thread-safe and returns completion items that own the
+  /// data they contain.
+  std::vector<CompletionItem> codeComplete(StringRef File, unsigned Line,
+                                           unsigned Column);
 
   /// Get the fixes associated with a certain diagnostic as replacements.
   ///
@@ -59,16 +65,26 @@
   /// database is cached for subsequent accesses.
   clang::tooling::CompilationDatabase *
   getOrCreateCompilationDatabaseForFile(StringRef Uri);
-  // Craetes a new ASTUnit for the document at Uri.
+  // Creates a new ASTUnit for the document at Uri.
   // FIXME: This calls chdir internally, which is thread unsafe.
   std::unique_ptr<clang::ASTUnit>
   createASTUnitForFile(StringRef Uri, const DocumentStore &Docs);
 
   void runWorker();
   void parseFileAndPublishDiagnostics(StringRef File);
 
   /// Clang objects.
+
+  /// A map from Uri-s to ASTUnit-s. Guarded by \c ASTLock. ASTUnit-s are used
+  /// for generating diagnostics and fix-it-s asynchronously by the worker
+  /// thread and synchronously for code completion.
+  ///
+  /// TODO(krasimir): code completion should always have priority over parsing
+  /// for diagnostics.
   llvm::StringMap<std::unique_ptr<clang::ASTUnit>> ASTs;
+  /// A lock for access to the map \c ASTs.
+  std::mutex ASTLock;
+
   llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
       CompilationDatabases;
   std::shared_ptr<clang::PCHContainerOperations> PCHs;
Index: clang-tools-extra/trunk/clangd/Protocol.h
===================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h
+++ clang-tools-extra/trunk/clangd/Protocol.h
@@ -233,6 +233,113 @@
   parse(llvm::yaml::MappingNode *Params);
 };
 
+struct TextDocumentPositionParams {
+  /// The text document.
+  TextDocumentIdentifier textDocument;
+
+  /// The position inside the text document.
+  Position position;
+
+  static llvm::Optional<TextDocumentPositionParams>
+  parse(llvm::yaml::MappingNode *Params);
+};
+
+/// The kind of a completion entry.
+enum class CompletionItemKind {
+  Missing = 0,
+  Text = 1,
+  Method = 2,
+  Function = 3,
+  Constructor = 4,
+  Field = 5,
+  Variable = 6,
+  Class = 7,
+  Interface = 8,
+  Module = 9,
+  Property = 10,
+  Unit = 11,
+  Value = 12,
+  Enum = 13,
+  Keyword = 14,
+  Snippet = 15,
+  Color = 16,
+  File = 17,
+  Reference = 18,
+};
+
+/// Defines whether the insert text in a completion item should be interpreted
+/// as plain text or a snippet.
+enum class InsertTextFormat {
+  Missing = 0,
+  /// The primary text to be inserted is treated as a plain string.
+  PlainText = 1,
+  /// The primary text to be inserted is treated as a snippet.
+  ///
+  /// A snippet can define tab stops and placeholders with `$1`, `$2`
+  /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to the end
+  /// of the snippet. Placeholders with equal identifiers are linked, that is
+  /// typing in one will update others too.
+  ///
+  /// See also:
+  /// https//github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
+  Snippet = 2,
+};
+
+struct CompletionItem {
+  /// The label of this completion item. By default also the text that is
+  /// inserted when selecting this completion.
+  std::string label;
+
+  /// The kind of this completion item. Based of the kind an icon is chosen by
+  /// the editor.
+  CompletionItemKind kind = CompletionItemKind::Missing;
+
+  /// A human-readable string with additional information about this item, like
+  /// type or symbol information.
+  std::string detail;
+
+  /// A human-readable string that represents a doc-comment.
+  std::string documentation;
+
+  /// A string that should be used when comparing this item with other items.
+  /// When `falsy` the label is used.
+  std::string sortText;
+
+  /// A string that should be used when filtering a set of completion items.
+  /// When `falsy` the label is used.
+  std::string filterText;
+
+  /// A string that should be inserted to a document when selecting this
+  /// completion. When `falsy` the label is used.
+  std::string insertText;
+
+  /// The format of the insert text. The format applies to both the `insertText`
+  /// property and the `newText` property of a provided `textEdit`.
+  InsertTextFormat insertTextFormat = InsertTextFormat::Missing;
+
+  /// An edit which is applied to a document when selecting this completion.
+  /// When an edit is provided `insertText` is ignored.
+  ///
+  /// Note: The range of the edit must be a single line range and it must
+  /// contain the position at which completion has been requested.
+  llvm::Optional<TextEdit> textEdit;
+
+  /// An optional array of additional text edits that are applied when selecting
+  /// this completion. Edits must not overlap with the main edit nor with
+  /// themselves.
+  std::vector<TextEdit> additionalTextEdits;
+  
+  // TODO(krasimir): The following optional fields defined by the language
+  // server protocol are unsupported:
+  //
+  // command?: Command - An optional command that is executed *after* inserting
+  //                     this completion.
+  //
+  // data?: any - A data entry field that is preserved on a completion item
+  //              between a completion and a completion resolve request.
+  static std::string unparse(const CompletionItem &P);
+};
+
 } // namespace clangd
 } // namespace clang
 
Index: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
===================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
@@ -178,3 +178,25 @@
       R"(, "result": [)" + Commands +
       R"(]})");
 }
+
+void CompletionHandler::handleMethod(llvm::yaml::MappingNode *Params,
+                                     StringRef ID) {
+  auto TDPP = TextDocumentPositionParams::parse(Params);
+  if (!TDPP) {
+    Output.log("Failed to decode TextDocumentPositionParams!\n");
+    return;
+  }
+
+  auto Items = AST.codeComplete(TDPP->textDocument.uri, TDPP->position.line,
+                                TDPP->position.character);
+  std::string Completions;
+  for (const auto &Item : Items) {
+    Completions += CompletionItem::unparse(Item);
+    Completions += ",";
+  }
+  if (!Completions.empty())
+    Completions.pop_back();
+  writeMessage(
+      R"({"jsonrpc":"2.0","id":)" + ID.str() +
+      R"(,"result":[)" + Completions + R"(]})");
+}
Index: clang-tools-extra/trunk/clangd/ASTManager.cpp
===================================================================
--- clang-tools-extra/trunk/clangd/ASTManager.cpp
+++ clang-tools-extra/trunk/clangd/ASTManager.cpp
@@ -83,50 +83,54 @@
 }
 
 void ASTManager::parseFileAndPublishDiagnostics(StringRef File) {
-  auto &Unit = ASTs[File]; // Only one thread can access this at a time.
+  DiagnosticToReplacementMap LocalFixIts; // Temporary storage
+  std::string Diagnostics;
+  {
+    std::lock_guard<std::mutex> ASTGuard(ASTLock);
+    auto &Unit = ASTs[File]; // Only one thread can access this at a time.
 
-  if (!Unit) {
-    Unit = createASTUnitForFile(File, this->Store);
-  } else {
-    // Do a reparse if this wasn't the first parse.
-    // FIXME: This might have the wrong working directory if it changed in the
-    // meantime.
-    Unit->Reparse(PCHs, getRemappedFiles(this->Store));
-  }
+    if (!Unit) {
+      Unit = createASTUnitForFile(File, this->Store);
+    } else {
+      // Do a reparse if this wasn't the first parse.
+      // FIXME: This might have the wrong working directory if it changed in the
+      // meantime.
+      Unit->Reparse(PCHs, getRemappedFiles(this->Store));
+    }
 
-  if (!Unit)
-    return;
+    if (!Unit)
+      return;
 
-  // Send the diagnotics to the editor.
-  // FIXME: If the diagnostic comes from a different file, do we want to
-  // show them all? Right now we drop everything not coming from the
-  // main file.
-  std::string Diagnostics;
-  DiagnosticToReplacementMap LocalFixIts; // Temporary storage
-  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
-                                     DEnd = Unit->stored_diag_end();
-       D != DEnd; ++D) {
-    if (!D->getLocation().isValid() ||
-        !D->getLocation().getManager().isInMainFile(D->getLocation()))
-      continue;
-    Position P;
-    P.line = D->getLocation().getSpellingLineNumber() - 1;
-    P.character = D->getLocation().getSpellingColumnNumber();
-    Range R = {P, P};
-    Diagnostics +=
-        R"({"range":)" + Range::unparse(R) +
-        R"(,"severity":)" + std::to_string(getSeverity(D->getLevel())) +
-        R"(,"message":")" + llvm::yaml::escape(D->getMessage()) +
-        R"("},)";
-
-    // We convert to Replacements to become independent of the SourceManager.
-    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};
-    auto &FixItsForDiagnostic = LocalFixIts[Diag];
-    for (const FixItHint &Fix : D->getFixIts()) {
-      FixItsForDiagnostic.push_back(clang::tooling::Replacement(
-          Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
+    // Send the diagnotics to the editor.
+    // FIXME: If the diagnostic comes from a different file, do we want to
+    // show them all? Right now we drop everything not coming from the
+    // main file.
+    for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
+                                       DEnd = Unit->stored_diag_end();
+         D != DEnd; ++D) {
+      if (!D->getLocation().isValid() ||
+          !D->getLocation().getManager().isInMainFile(D->getLocation()))
+        continue;
+      Position P;
+      P.line = D->getLocation().getSpellingLineNumber() - 1;
+      P.character = D->getLocation().getSpellingColumnNumber();
+      Range R = {P, P};
+      Diagnostics +=
+          R"({"range":)" + Range::unparse(R) +
+          R"(,"severity":)" + std::to_string(getSeverity(D->getLevel())) +
+          R"(,"message":")" + llvm::yaml::escape(D->getMessage()) +
+          R"("},)";
+
+      // We convert to Replacements to become independent of the SourceManager.
+      clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()),
+                                 D->getMessage()};
+      auto &FixItsForDiagnostic = LocalFixIts[Diag];
+      for (const FixItHint &Fix : D->getFixIts()) {
+        FixItsForDiagnostic.push_back(clang::tooling::Replacement(
+            Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
+      }
     }
-  }
+  } // unlock ASTLock
 
   // Put FixIts into place.
   {
@@ -232,3 +236,79 @@
     return I->second;
   return {};
 }
+
+namespace {
+
+class CompletionItemsCollector : public CodeCompleteConsumer {
+  std::vector<CompletionItem> *Items;
+  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+  CodeCompletionTUInfo CCTUInfo;
+
+public:
+  CompletionItemsCollector(std::vector<CompletionItem> *Items,
+                           const CodeCompleteOptions &CodeCompleteOpts)
+      : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
+        Items(Items),
+        Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+        CCTUInfo(Allocator) {}
+
+  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
+                                  CodeCompletionResult *Results,
+                                  unsigned NumResults) override {
+    for (unsigned I = 0; I != NumResults; ++I) {
+      CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(
+          S, Context, *Allocator, CCTUInfo,
+          CodeCompleteOpts.IncludeBriefComments);
+      if (CCS) {
+        CompletionItem Item;
+        assert(CCS->getTypedText());
+        Item.label = CCS->getTypedText();
+        if (CCS->getBriefComment())
+          Item.documentation = CCS->getBriefComment();
+        Items->push_back(std::move(Item));
+      }
+    }
+  }
+
+  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
+
+  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+};
+
+} // namespace
+
+std::vector<CompletionItem>
+ASTManager::codeComplete(StringRef Uri, unsigned Line, unsigned Column) {
+  CodeCompleteOptions CCO;
+  CCO.IncludeBriefComments = 1;
+  // This is where code completion stores dirty buffers. Need to free after
+  // completion.
+  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
+  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
+      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
+  std::vector<CompletionItem> Items;
+  CompletionItemsCollector Collector(&Items, CCO);
+  std::lock_guard<std::mutex> Guard(ASTLock);
+  auto &Unit = ASTs[Uri];
+  if (!Unit)
+    Unit = createASTUnitForFile(Uri, this->Store);
+  if (!Unit)
+    return {};
+  IntrusiveRefCntPtr<SourceManager> SourceMgr(
+      new SourceManager(*DiagEngine, Unit->getFileManager()));
+  StringRef File(Uri);
+  File.consume_front("file://");
+  // CodeComplete seems to require fresh LangOptions.
+  LangOptions LangOpts = Unit->getLangOpts();
+  // The language server protocol uses zero-based line and column numbers.
+  // The clang code completion uses one-based numbers.
+  Unit->CodeComplete(File, Line + 1, Column + 1, getRemappedFiles(this->Store),
+                     CCO.IncludeMacros, CCO.IncludeCodePatterns,
+                     CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
+                     LangOpts, *SourceMgr, Unit->getFileManager(),
+                     StoredDiagnostics, OwnedBuffers);
+  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
+    delete Buffer;
+  return Items;
+}
Index: clang-tools-extra/trunk/test/clangd/formatting.test
===================================================================
--- clang-tools-extra/trunk/test/clangd/formatting.test
+++ clang-tools-extra/trunk/test/clangd/formatting.test
@@ -4,13 +4,14 @@
 Content-Length: 125
 
 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-# CHECK: Content-Length: 332
+# CHECK: Content-Length: 424
 # CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
 # CHECK:   "textDocumentSync": 1,
 # CHECK:   "documentFormattingProvider": true,
 # CHECK:   "documentRangeFormattingProvider": true,
 # CHECK:   "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
-# CHECK:   "codeActionProvider": true
+# CHECK:   "codeActionProvider": true,
+# CHECK:   "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]}
 # CHECK: }}}
 #
 Content-Length: 193
Index: clang-tools-extra/trunk/test/clangd/completion.test
===================================================================
--- clang-tools-extra/trunk/test/clangd/completion.test
+++ clang-tools-extra/trunk/test/clangd/completion.test
@@ -0,0 +1,69 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+Content-Length: 208
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#include <vector>\nint main() {\n  std::vector<int> v;\n  v.\n}\n"}}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":4}}}
+# The order of results returned by ASTUnit CodeComplete seems to be
+# nondeterministic, so we check regardless of order.
+#
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[
+# CHECK-DAG: {"label":"_M_allocate"}
+# CHECK-DAG: {"label":"_M_allocate_and_copy"}
+# CHECK-DAG: {"label":"_M_assign_aux"}
+# CHECK-DAG: {"label":"_M_assign_dispatch"}
+# CHECK-DAG: {"label":"_M_check_len"}
+# CHECK-DAG: {"label":"_M_create_storage"
+# CHECK-DAG: {"label":"_M_deallocate"}
+# CHECK-DAG: {"label":"_M_erase_at_end"}
+# CHECK-DAG: {"label":"_M_fill_assign"}
+# CHECK-DAG: {"label":"_M_fill_initialize"}
+# CHECK-DAG: {"label":"_M_fill_insert"}
+# CHECK-DAG: {"label":"_M_get_Tp_allocator"}
+# CHECK-DAG: {"label":"_M_impl"}
+# CHECK-DAG: {"label":"_M_initialize_dispatch"}
+# CHECK-DAG: {"label":"_M_insert_aux"}
+# CHECK-DAG: {"label":"_M_insert_dispatch"}
+# CHECK-DAG: {"label":"_M_range_check"}
+# CHECK-DAG: {"label":"_M_range_initialize"}
+# CHECK-DAG: {"label":"_M_range_insert"}
+# CHECK-DAG: {"label":"_Vector_base"}
+# CHECK-DAG: {"label":"assign"}
+# CHECK-DAG: {"label":"at"}
+# CHECK-DAG: {"label":"back"}
+# CHECK-DAG: {"label":"begin"}
+# CHECK-DAG: {"label":"capacity"}
+# CHECK-DAG: {"label":"clear"}
+# CHECK-DAG: {"label":"data"}
+# CHECK-DAG: {"label":"empty"}
+# CHECK-DAG: {"label":"end"}
+# CHECK-DAG: {"label":"erase"}
+# CHECK-DAG: {"label":"front"}
+# CHECK-DAG: {"label":"get_allocator"}
+# CHECK-DAG: {"label":"insert"}
+# CHECK-DAG: {"label":"max_size"}
+# CHECK-DAG: {"label":"operator="}
+# CHECK-DAG: {"label":"operator[]"}
+# CHECK-DAG: {"label":"pop_back"}
+# CHECK-DAG: {"label":"push_back"}
+# CHECK-DAG: {"label":"rbegin"}
+# CHECK-DAG: {"label":"rend"}
+# CHECK-DAG: {"label":"reserve"}
+# CHECK-DAG: {"label":"resize"}
+# CHECK-DAG: {"label":"size"}
+# CHECK-DAG: {"label":"swap"}
+# CHECK-DAG: {"label":"vector"}
+# CHECK-DAG: {"label":"~_Vector_base"}
+# CHECK-DAG: {"label":"~vector"}
+# CHECK: ]}
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to