Index: clang-tools-extra/trunk/clangd/ClangdUnit.cpp =================================================================== --- clang-tools-extra/trunk/clangd/ClangdUnit.cpp +++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp @@ -375,50 +375,62 @@ : Result(&Result), Score(score(Result)) {} CodeCompletionResult *Result; - // Higher score is worse. FIXME: use a more natural scale! - int Score; + float Score; // 0 to 1, higher is better. // Comparison reflects rank: better candidates are smaller. bool operator<(const CompletionCandidate &C) const { if (Score != C.Score) - return Score < C.Score; + return Score > C.Score; return *Result < *C.Result; } + // Returns a string that sorts in the same order as operator<, for LSP. + // Conceptually, this is [-Score, Name]. We convert -Score to an integer, and + // hex-encode it for readability. Example: [0.5, "foo"] -> "41000000foo" std::string sortText() const { - // Fill in the sortText of the CompletionItem. - assert(Score <= 999999 && "Expecting score to have at most 6-digits"); std::string S, NameStorage; - StringRef Name = Result->getOrderedName(NameStorage); - llvm::raw_string_ostream(S) - << llvm::format("%06d%.*s", Score, Name.size(), Name.data()); - return S; + llvm::raw_string_ostream OS(S); + write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower, + /*Width=*/2 * sizeof(Score)); + OS << Result->getOrderedName(NameStorage); + return OS.str(); } private: - static int score(const CodeCompletionResult &Result) { - int Score = Result.Priority; - // Fill in the sortText of the CompletionItem. - assert(Score <= 99999 && "Expecting code completion result " - "priority to have at most 5-digits"); + static float score(const CodeCompletionResult &Result) { + // Priority 80 is a really bad score. + float Score = 1 - std::min(80, Result.Priority) / 80; - const int Penalty = 100000; switch (static_cast(Result.Availability)) { case CXAvailability_Available: // No penalty. break; case CXAvailability_Deprecated: - Score += Penalty; + Score *= 0.1; break; case CXAvailability_NotAccessible: - Score += 2 * Penalty; - break; case CXAvailability_NotAvailable: - Score += 3 * Penalty; + Score = 0; break; } return Score; } + + // Produces an integer that sorts in the same order as F. + // That is: a < b <==> encodeFloat(a) < encodeFloat(b). + static uint32_t encodeFloat(float F) { + static_assert(std::numeric_limits::is_iec559, ""); + static_assert(sizeof(float) == sizeof(uint32_t), ""); + constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1); + + // Get the bits of the float. Endianness is the same as for integers. + uint32_t U; + memcpy(&U, &F, sizeof(float)); + // IEEE 754 floats compare like sign-magnitude integers. + if (U & TopBit) // Negative float. + return 0 - U; // Map onto the low half of integers, order reversed. + return U + TopBit; // Positive floats map onto the high half of integers. + } }; class CompletionItemsCollector : public CodeCompleteConsumer { Index: clang-tools-extra/trunk/test/clangd/authority-less-uri.test =================================================================== --- clang-tools-extra/trunk/test/clangd/authority-less-uri.test +++ clang-tools-extra/trunk/test/clangd/authority-less-uri.test @@ -25,7 +25,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}fake" # CHECK: ] # CHECK-NEXT: } Content-Length: 172 @@ -43,7 +43,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}fake" # CHECK: ] # CHECK-NEXT: } Content-Length: 44 Index: clang-tools-extra/trunk/test/clangd/completion-items-kinds.test =================================================================== --- clang-tools-extra/trunk/test/clangd/completion-items-kinds.test +++ clang-tools-extra/trunk/test/clangd/completion-items-kinds.test @@ -12,20 +12,20 @@ {"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":7}}} # CHECK: {"id":1,"jsonrpc":"2.0","result":{"isIncomplete":false,"items": # +# Function +# CHECK: {"detail":"int","filterText":"function","insertText":"function()","insertTextFormat":1,"kind":3,"label":"function()","sortText":"{{.*}}function"} +# +# Variable +# CHECK: {"detail":"int","filterText":"variable","insertText":"variable","insertTextFormat":1,"kind":6,"label":"variable","sortText":"{{.*}}variable"} +# # Keyword -# CHECK-DAG: {"filterText":"int","insertText":"int","insertTextFormat":1,"kind":14,"label":"int","sortText":"000050int"} +# CHECK: {"filterText":"int","insertText":"int","insertTextFormat":1,"kind":14,"label":"int","sortText":"{{.*}}int"} # # Struct -# CHECK-DAG: {"filterText":"Struct","insertText":"Struct","insertTextFormat":1,"kind":7,"label":"Struct","sortText":"000050Struct"} +# CHECK: {"filterText":"Struct","insertText":"Struct","insertTextFormat":1,"kind":7,"label":"Struct","sortText":"{{.*}}Struct"} # # Macro -# CHECK-DAG: {"filterText":"MACRO","insertText":"MACRO","insertTextFormat":1,"kind":1,"label":"MACRO","sortText":"000070MACRO"} -# -# Variable -# CHECK-DAG: {"detail":"int","filterText":"variable","insertText":"variable","insertTextFormat":1,"kind":6,"label":"variable","sortText":"000012variable"} -# -# Function -# CHECK-DAG: {"detail":"int","filterText":"function","insertText":"function()","insertTextFormat":1,"kind":3,"label":"function()","sortText":"000012function"} +# CHECK: {"filterText":"MACRO","insertText":"MACRO","insertTextFormat":1,"kind":1,"label":"MACRO","sortText":"{{.*}}MACRO"} # # CHECK-SAME: ]}} Content-Length: 146 @@ -35,7 +35,7 @@ {"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":3}}} # Code pattern (unfortunately there are none in expression context) -# CHECK-DAG: {"filterText":"namespace","insertText":"namespace ${1:identifier}{${2:declarations}\n}","insertTextFormat":2,"kind":15,"label":"namespace identifier{declarations}","sortText":"000040namespace"} +# CHECK-DAG: {"filterText":"namespace","insertText":"namespace ${1:identifier}{${2:declarations}\n}","insertTextFormat":2,"kind":15,"label":"namespace identifier{declarations}","sortText":"{{.*}}namespace"} # Content-Length: 58 Index: clang-tools-extra/trunk/test/clangd/completion-priorities.test =================================================================== --- clang-tools-extra/trunk/test/clangd/completion-priorities.test +++ clang-tools-extra/trunk/test/clangd/completion-priorities.test @@ -25,7 +25,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "priv()", -# CHECK-NEXT: "sortText": "000034priv" +# CHECK-NEXT: "sortText": "{{.*}}priv" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "void", @@ -34,7 +34,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "prot()", -# CHECK-NEXT: "sortText": "000034prot" +# CHECK-NEXT: "sortText": "{{.*}}prot" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "void", @@ -43,7 +43,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "pub()", -# CHECK-NEXT: "sortText": "000034pub" +# CHECK-NEXT: "sortText": "{{.*}}pub" # CHECK-NEXT: }, Content-Length: 151 @@ -60,7 +60,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "pub()", -# CHECK-NEXT: "sortText": "000034pub" +# CHECK-NEXT: "sortText": "{{.*}}pub" # CHECK-NEXT: } # CHECK-NOT: "label": "priv()", # CHECK-NOT: "label": "prot()", Index: clang-tools-extra/trunk/test/clangd/completion-qualifiers.test =================================================================== --- clang-tools-extra/trunk/test/clangd/completion-qualifiers.test +++ clang-tools-extra/trunk/test/clangd/completion-qualifiers.test @@ -21,7 +21,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "bar() const", -# CHECK-NEXT: "sortText": "000037bar" +# CHECK-NEXT: "sortText": "{{.*}}bar" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -30,7 +30,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "Foo::foo() const", -# CHECK-NEXT: "sortText": "000037foo" +# CHECK-NEXT: "sortText": "{{.*}}foo" # CHECK-NEXT: }, # Ineligible private functions are not present. # CHECK-NOT: "label": "foo() const", Index: clang-tools-extra/trunk/test/clangd/completion-snippet.test =================================================================== --- clang-tools-extra/trunk/test/clangd/completion-snippet.test +++ clang-tools-extra/trunk/test/clangd/completion-snippet.test @@ -24,7 +24,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "a", -# CHECK-NEXT: "sortText": "000035a" +# CHECK-NEXT: "sortText": "{{.*}}a" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -33,7 +33,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "bb", -# CHECK-NEXT: "sortText": "000035bb" +# CHECK-NEXT: "sortText": "{{.*}}bb" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -42,7 +42,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "ccc", -# CHECK-NEXT: "sortText": "000035ccc" +# CHECK-NEXT: "sortText": "{{.*}}ccc" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -51,7 +51,7 @@ # CHECK-NEXT: "insertTextFormat": 2, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "f(int i, const float f) const", -# CHECK-NEXT: "sortText": "000035f" +# CHECK-NEXT: "sortText": "{{.*}}f" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "filterText": "fake", @@ -59,7 +59,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}fake" # CHECK-NEXT: }, # CHECK: { # CHECK: "detail": "void", @@ -68,7 +68,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 4, # CHECK-NEXT: "label": "~fake()", -# CHECK-NEXT: "sortText": "000079~fake" +# CHECK-NEXT: "sortText": "{{.*}}~fake" # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } @@ -92,7 +92,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "func()", -# CHECK-NEXT: "sortText": "000034func" +# CHECK-NEXT: "sortText": "{{.*}}func" # CHECK-NEXT: }, Content-Length: 44 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 @@ -25,7 +25,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "a", -# CHECK-NEXT: "sortText": "000035a" +# CHECK-NEXT: "sortText": "{{.*}}a" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -34,7 +34,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "bb", -# CHECK-NEXT: "sortText": "000035bb" +# CHECK-NEXT: "sortText": "{{.*}}bb" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -43,7 +43,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "ccc", -# CHECK-NEXT: "sortText": "000035ccc" +# CHECK-NEXT: "sortText": "{{.*}}ccc" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -52,7 +52,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "f(int i, const float f) const", -# CHECK-NEXT: "sortText": "000035f" +# CHECK-NEXT: "sortText": "{{.*}}f" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "filterText": "fake", @@ -60,7 +60,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}fake" # CHECK-NEXT: }, # FIXME: Why do buildbots show different operator=s here? # CHECK: { @@ -70,7 +70,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 4, # CHECK-NEXT: "label": "~fake()", -# CHECK-NEXT: "sortText": "000079~fake" +# CHECK-NEXT: "sortText": "{{.*}}~fake" # CHECK-NEXT: } # CHECK-NEXT: ] Content-Length: 148 @@ -88,7 +88,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "a", -# CHECK-NEXT: "sortText": "000035a" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -97,7 +97,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "bb", -# CHECK-NEXT: "sortText": "000035bb" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -106,7 +106,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": "ccc", -# CHECK-NEXT: "sortText": "000035ccc" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "detail": "int", @@ -115,7 +115,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "f(int i, const float f) const", -# CHECK-NEXT: "sortText": "000035f" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "filterText": "fake", @@ -123,7 +123,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK: { # CHECK: "detail": "void", @@ -132,7 +132,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 4, # CHECK-NEXT: "label": "~fake()", -# CHECK-NEXT: "sortText": "000079~fake" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: } # CHECK-NEXT: ] # Update the source file and check for completions again. @@ -155,7 +155,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 2, # CHECK-NEXT: "label": "func()", -# CHECK-NEXT: "sortText": "000034func" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "filterText": "fancy", @@ -163,7 +163,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fancy::", -# CHECK-NEXT: "sortText": "000075fancy" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: }, # CHECK: { # CHECK: "detail": "void", @@ -172,7 +172,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 4, # CHECK-NEXT: "label": "~fancy()", -# CHECK-NEXT: "sortText": "000079~fancy" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK-NEXT: } # CHECK-NEXT: ] Content-Length: 44 Index: clang-tools-extra/trunk/test/clangd/protocol.test =================================================================== --- clang-tools-extra/trunk/test/clangd/protocol.test +++ clang-tools-extra/trunk/test/clangd/protocol.test @@ -39,7 +39,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK: ] # CHECK-NEXT: } @@ -68,7 +68,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK: ] # CHECK-NEXT: } # STDERR: Warning: Duplicate Content-Length header received. The previous value for this message (10) was ignored. @@ -97,7 +97,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 7, # CHECK-NEXT: "label": "fake::", -# CHECK-NEXT: "sortText": "000075fake" +# CHECK-NEXT: "sortText": "{{.*}}" # CHECK: ] # CHECK-NEXT: } Content-Length: 1024