From ebb7c8489192626159d59f64307d515de65c4765 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 25 Aug 2010 22:15:42 +0000 Subject: [PATCH] Move the sorting of code-completion results out of the main path and into the clients, e.g., the printing code-completion consumer and c-index-test. Clients may want to re-sort the results anyway. llvm-svn: 112095 --- clang/lib/Frontend/ASTUnit.cpp | 4 +- clang/lib/Sema/CodeCompleteConsumer.cpp | 9 +- clang/lib/Sema/SemaCodeComplete.cpp | 2 - clang/test/Index/code-completion.cpp | 2 +- clang/test/Index/complete-method-decls.m | 4 +- clang/test/Index/complete-objc-message.m | 31 ++++--- clang/tools/c-index-test/c-index-test.c | 86 ++++++++++++++++++- clang/tools/libclang/CIndexCodeCompletion.cpp | 2 + 8 files changed, 116 insertions(+), 24 deletions(-) diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 452803acd29b..874fd012b3c9 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1678,9 +1678,7 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, Next.ProcessCodeCompleteResults(S, Context, Results, NumResults); return; } - - // Sort the completion results before passing them on to the actual consumer. - std::stable_sort(AllResults.begin(), AllResults.end()); + Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), AllResults.size()); diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 43451235589e..c4e7bb4269d1 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -443,6 +443,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) { + std::stable_sort(Results, Results + NumResults); + // Print the results. for (unsigned I = 0; I != NumResults; ++I) { OS << "COMPLETION: "; @@ -660,6 +662,11 @@ bool clang::operator<(const CodeCompletionResult &X, if (cmp) return cmp < 0; + // If case-insensitive comparison fails, try case-sensitive comparison. + cmp = XStr.compare(YStr); + if (cmp) + return cmp < 0; + // Non-hidden names precede hidden names. if (X.Hidden != Y.Hidden) return !X.Hidden; @@ -695,7 +702,7 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { WriteUnsigned(OS, CXCursor_NotImplemented); - WriteUnsigned(OS, /*Priority=*/0); + WriteUnsigned(OS, /*Priority=*/I); WriteUnsigned(OS, /*Availability=*/CXAvailability_Available); CodeCompletionString *CCS = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index fed65365706c..d61ddcdf758a 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -2277,8 +2277,6 @@ static void HandleCodeCompleteResults(Sema *S, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) { - std::stable_sort(Results, Results + NumResults); - if (CodeCompleter) CodeCompleter->ProcessCodeCompleteResults(*S, Context, Results, NumResults); diff --git a/clang/test/Index/code-completion.cpp b/clang/test/Index/code-completion.cpp index 354e7461660a..8efac1fea1d3 100644 --- a/clang/test/Index/code-completion.cpp +++ b/clang/test/Index/code-completion.cpp @@ -60,8 +60,8 @@ Z::operator int() const { // RUN: c-index-test -code-completion-at=%s:37:10 %s | FileCheck -check-prefix=CHECK-EXPR %s // CHECK-EXPR: NotImplemented:{TypedText int} (65) // CHECK-EXPR: NotImplemented:{TypedText long} (65) -// CHECK-EXPR: FieldDecl:{ResultType double}{TypedText member} (10) // CHECK-EXPR: FieldDecl:{ResultType int}{Text X::}{TypedText member} (5) +// CHECK-EXPR: FieldDecl:{ResultType double}{TypedText member} (10) // CHECK-EXPR: FieldDecl:{ResultType float}{Text Y::}{TypedText member} (11) // CHECK-EXPR: FunctionDecl:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} (22) // CHECK-EXPR: NotImplemented:{TypedText N}{Text ::} (75) diff --git a/clang/test/Index/complete-method-decls.m b/clang/test/Index/complete-method-decls.m index 1324ae4a6970..0c9a55a2b371 100644 --- a/clang/test/Index/complete-method-decls.m +++ b/clang/test/Index/complete-method-decls.m @@ -113,13 +113,13 @@ // CHECK-CCC: ObjCInstanceMethodDecl:{TypedText first}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second2}{Colon :}{LeftParen (}{Text float}{RightParen )}{Text y}{HorizontalSpace }{Text third}{Colon :}{LeftParen (}{Text double}{RightParen )}{Text z} (30) // RUN: c-index-test -code-completion-at=%s:56:21 %s | FileCheck -check-prefix=CHECK-CCD %s // FIXME: These results could be more precise. -// CHECK-CCD: ObjCInstanceMethodDecl:{ResultType id}{Informative first:}{TypedText second2:}{Text (float)y2}{HorizontalSpace }{Text third:}{Text (double)z} (20) // CHECK-CCD: ObjCInstanceMethodDecl:{ResultType int}{Informative first:}{TypedText second2:}{Text (float)y}{HorizontalSpace }{Text third:}{Text (double)z} (5) +// CHECK-CCD: ObjCInstanceMethodDecl:{ResultType id}{Informative first:}{TypedText second2:}{Text (float)y2}{HorizontalSpace }{Text third:}{Text (double)z} (20) // CHECK-CCD: ObjCInstanceMethodDecl:{ResultType void *}{Informative first:}{TypedText second3:}{Text (float)y3}{HorizontalSpace }{Text third:}{Text (double)z} (20) // CHECK-CCD: ObjCInstanceMethodDecl:{ResultType int}{Informative first:}{TypedText second:}{Text (float)y}{HorizontalSpace }{Text third:}{Text (double)z} (5) // RUN: c-index-test -code-completion-at=%s:56:38 %s | FileCheck -check-prefix=CHECK-CCE %s -// CHECK-CCE: ObjCInstanceMethodDecl:{ResultType id}{Informative first:}{Informative second2:}{TypedText third:}{Text (double)z} (20) // CHECK-CCE: ObjCInstanceMethodDecl:{ResultType int}{Informative first:}{Informative second2:}{TypedText third:}{Text (double)z} (5) +// CHECK-CCE: ObjCInstanceMethodDecl:{ResultType id}{Informative first:}{Informative second2:}{TypedText third:}{Text (double)z} (20) // RUN: c-index-test -code-completion-at=%s:60:4 %s | FileCheck -check-prefix=CHECK-CCF %s // CHECK-CCF: ObjCInterfaceDecl:{TypedText A} (65) // CHECK-CCF: ObjCInterfaceDecl:{TypedText B} (65) diff --git a/clang/test/Index/complete-objc-message.m b/clang/test/Index/complete-objc-message.m index 54f62a045db3..1f96bb61e3b7 100644 --- a/clang/test/Index/complete-objc-message.m +++ b/clang/test/Index/complete-objc-message.m @@ -209,20 +209,23 @@ void test_ranking(B *b) { // CHECK-CCF: {ResultType Class}{TypedText self} // CHECK-CCF: {TypedText super} // RUN: c-index-test -code-completion-at=%s:120:6 %s | FileCheck -check-prefix=CHECK-CCG %s -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText categoryInstanceMethod} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod1} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{HorizontalSpace }{Text second:}{Placeholder (id)y} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyPrivateInstMethod} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod:}{Placeholder (id)obj} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText protocolInstanceMethod:}{Placeholder (int)value} -// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText secondProtocolInstanceMethod} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText categoryInstanceMethod} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod1} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{HorizontalSpace }{Text second:}{Placeholder (id)y} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyPrivateInstMethod} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod:}{Placeholder (id)obj} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText protocolInstanceMethod:}{Placeholder (int)value} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText secondProtocolInstanceMethod} (20) +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText SentinelMethod:}{Placeholder (int)i}{Placeholder , ...}{Text , nil} (20) + + // RUN: c-index-test -code-completion-at=%s:121:14 %s | FileCheck -check-prefix=CHECK-CCG %s // RUN: c-index-test -code-completion-at=%s:122:7 %s | FileCheck -check-prefix=CHECK-CCH %s // CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText categoryClassMethod} diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 330fa545f931..c13ae91cb656 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -1,6 +1,7 @@ /* c-index-test.c */ #include "clang-c/Index.h" +#include #include #include #include @@ -895,6 +896,84 @@ void print_completion_result(CXCompletionResult *completion_result, fprintf(file, "\n"); } +int my_stricmp(const char *s1, const char *s2) { + while (*s1 && *s2) { + int c1 = tolower(*s1), c2 = tolower(*s2); + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + + ++s1; + ++s2; + } + + if (*s1) + return 1; + else if (*s2) + return -1; + return 0; +} + +int compare_completion_string(const void *xv, const void *yv) { + CXCompletionString x = ((CXCompletionResult *)xv)->CompletionString; + CXCompletionString y = ((CXCompletionResult *)yv)->CompletionString; + CXString xText, yText; + int I, N; + int result; + int FoundXText = 0, FoundYText = 0; + + /* Find the typed text in x. */ + for (I = 0, N = clang_getNumCompletionChunks(x); I != N; ++I) { + if (clang_getCompletionChunkKind(x, I) == CXCompletionChunk_TypedText) { + xText = clang_getCompletionChunkText(x, I); + FoundXText = 1; + break; + } + } + + /* Find the typed text in x. */ + for (I = 0, N = clang_getNumCompletionChunks(y); I != N; ++I) { + if (clang_getCompletionChunkKind(y, I) == CXCompletionChunk_TypedText) { + yText = clang_getCompletionChunkText(y, I); + FoundYText = 1; + break; + } + } + + if (!FoundXText || !FoundYText) { + /* At least one of the results is missing a TypedText chunk. */ + if (FoundXText) + clang_disposeString(xText); + if (FoundYText) + clang_disposeString(xText); + + if (FoundXText || FoundYText) + return FoundXText? -1 : 1; + } else { + /* First, try case-insensitive comparisons. */ + result = my_stricmp(clang_getCString(xText), clang_getCString(yText)); + + /* If that fails, try case-sensitive comparison. */ + if (!result) + result = strcmp(clang_getCString(xText), clang_getCString(yText)); + + clang_disposeString(xText); + clang_disposeString(yText); + if (result) + return result; + } + + /* The completion strings appear to be the same; try to order based on + priority. */ + if (clang_getCompletionPriority(x) < clang_getCompletionPriority(y)) + return -1; + else if (clang_getCompletionPriority(x) > clang_getCompletionPriority(y)) + return 1; + + return 0; +} + int perform_code_completion(int argc, const char **argv, int timing_only) { const char *input = argv[1]; char *filename = 0; @@ -950,9 +1029,14 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { if (results) { unsigned i, n = results->NumResults; - if (!timing_only) + if (!timing_only) { + /* Sort the code-completion results based on the typed text. */ + mergesort(results->Results, results->NumResults, + sizeof(CXCompletionResult), &compare_completion_string); + for (i = 0; i != n; ++i) print_completion_result(results->Results + i, stdout); + } n = clang_codeCompleteGetNumDiagnostics(results); for (i = 0; i != n; ++i) { CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i); diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp index 026d0be4ba4a..7cf8f9f7792f 100644 --- a/clang/tools/libclang/CIndexCodeCompletion.cpp +++ b/clang/tools/libclang/CIndexCodeCompletion.cpp @@ -582,6 +582,8 @@ namespace { AllocatedResults.Results[I].CompletionString = StoredCompletion; } } + + // FIXME: Add ProcessOverloadCandidates? }; }