Index: clangd/ClangdUnit.cpp =================================================================== --- clangd/ClangdUnit.cpp +++ clangd/ClangdUnit.cpp @@ -288,36 +288,21 @@ void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) override { + // Sort the completions by their priority. A higher priority should come + // earlier in the sequence. + std::stable_sort(Results, Results + NumResults, + [](const CodeCompletionResult &lhs, + const CodeCompletionResult &rhs) -> bool { + return lhs.Priority > rhs.Priority; + }); for (unsigned I = 0; I != NumResults; ++I) { - CodeCompletionResult &Result = Results[I]; - CodeCompletionString *CCS = Result.CreateCodeCompletionString( - S, Context, *Allocator, CCTUInfo, - CodeCompleteOpts.IncludeBriefComments); - if (CCS) { + if (Results[I].Availability == CXAvailability_NotAvailable || + Results[I].Availability == CXAvailability_NotAccessible) { + // A private member variable outside of the class, for example. + continue; + } else { CompletionItem Item; - for (CodeCompletionString::Chunk C : *CCS) { - switch (C.Kind) { - case CodeCompletionString::CK_ResultType: - Item.detail = C.Text; - break; - case CodeCompletionString::CK_Optional: - break; - default: - Item.label += C.Text; - break; - } - } - assert(CCS->getTypedText()); - Item.kind = getKind(Result.CursorKind); - // Priority is a 16-bit integer, hence at most 5 digits. - assert(CCS->getPriority() < 99999 && "Expecting code completion result " - "priority to have at most " - "5-digits"); - llvm::raw_string_ostream(Item.sortText) - << llvm::format("%05d%s", CCS->getPriority(), CCS->getTypedText()); - Item.insertText = Item.filterText = CCS->getTypedText(); - if (CCS->getBriefComment()) - Item.documentation = CCS->getBriefComment(); + this->ProcessCodeCompleteResult(S, Context, Results[I], Item); Items->push_back(std::move(Item)); } } @@ -326,7 +311,157 @@ GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; } CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; } -}; + +private: + void ProcessCodeCompleteResult(Sema &S, CodeCompletionContext Context, + CodeCompletionResult &Result, + CompletionItem &Item) { + unsigned ArgCount = 0; + + // Fill in the label, detail, documentation and insertText fields of the + // CompletionItem. + switch (Result.Kind) { + case CodeCompletionResult::RK_Declaration: { + auto Completion = Result.CreateCodeCompletionString( + S, Context, *Allocator, CCTUInfo, + CodeCompleteOpts.IncludeBriefComments); + if (!Completion) { + Item.label = Result.Declaration->getNameAsString(); + } else { + ProcessCodeCompleteString(*Completion, ArgCount, Item); + } + break; + } + case CodeCompletionResult::RK_Keyword: + Item.label = Result.Keyword; + break; + case CodeCompletionResult::RK_Macro: { + auto Completion = Result.CreateCodeCompletionString( + S, Context, *Allocator, CCTUInfo, + CodeCompleteOpts.IncludeBriefComments); + if (!Completion) { + Item.label = Result.Macro->getName().str(); + } else { + ProcessCodeCompleteString(*Completion, ArgCount, Item); + } + break; + } + case CodeCompletionResult::RK_Pattern: { + assert(Result.Pattern && "we should have a code completion string here"); + ProcessCodeCompleteString(*Result.Pattern, ArgCount, Item); + break; + } + default: + llvm_unreachable("Unknown CodeCompletionResult kind"); + } + + // Fill in the kind field of the CompletionItem. + Item.kind = getKind(Result.CursorKind); + + // Always a snippet for now. + Item.insertTextFormat = InsertTextFormat::Snippet; + } + + void ProcessCodeCompleteString(const CodeCompletionString &CCS, + unsigned &ArgCount, + CompletionItem &Item) const { + for (unsigned j = 0; j < CCS.getAnnotationCount(); ++j) { + // Things like __attribute__((nonnull(1,3))). Stash this information in + // the documentation field. + Item.documentation += "[" + std::string(CCS.getAnnotation(j)) + "]"; + if (j != CCS.getAnnotationCount() - 1) + Item.documentation += ' '; + } + for (const auto &Chunk : CCS) { + 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.label += Chunk.Text; + Item.insertText += Chunk.Text; + break; + 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. + 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) + ":" + Chunk.Text + "}"; + Item.label += Chunk.Text; + break; + case CodeCompletionString::CK_Informative: + // A piece of text that describes something about the result + // but should not be inserted into the buffer. + Item.documentation += "[" + std::string(Chunk.Text) + "] "; + break; + case CodeCompletionString::CK_ResultType: + // A piece of text that describes the type of an entity or, + // for functions and methods, the return type. + 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. + ++ArgCount; + Item.insertText += + "${" + std::to_string(ArgCount) + ":" + Chunk.Text + "}"; + Item.label += Chunk.Text; + 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 (' '). + case CodeCompletionString::CK_VerticalSpace: + // Vertical whitespace ('\n' or '\r\n', depending on the + // platform). + Item.insertText += Chunk.Text; + Item.label += Chunk.Text; + break; + default: + llvm_unreachable("Unknown CodeCompletionString chunk type!"); + } + } + + // Add documentation (if there is any). + if (CCS.getBriefComment() != nullptr) { + Item.documentation += CCS.getBriefComment(); + } + } +}; // CompletionItemsCollector } // namespace std::vector Index: clangd/Protocol.cpp =================================================================== --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -724,8 +724,8 @@ if (!CI.insertText.empty()) Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)"; if (CI.insertTextFormat != InsertTextFormat::Missing) { - Os << R"("insertTextFormat":")" << static_cast(CI.insertTextFormat) - << R"(",)"; + Os << R"("insertTextFormat":)" << static_cast(CI.insertTextFormat) + << R"(,)"; } if (CI.textEdit) Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';