From c2cb2e23bcce1a773a1c249df1d16449de77f2a3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 27 Aug 2010 15:29:55 +0000 Subject: [PATCH] When code-completing inside an Objective-C method, give a slight priority boost to methods with the same selector. llvm-svn: 112268 --- .../include/clang/Sema/CodeCompleteConsumer.h | 6 ++- clang/lib/Sema/SemaCodeComplete.cpp | 40 ++++++++++++++++++- clang/test/Index/complete-objc-message-id.m | 12 ++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index 46650baf2fab..28210576e025 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -69,7 +69,11 @@ enum { CCD_VoidMatch = -5, /// \brief The result is a C++ non-static member function whose qualifiers /// exactly match the object type on which the member function can be called. - CCD_ObjectQualifierMatch = -1 + CCD_ObjectQualifierMatch = -1, + /// \brief The selector of the given message exactly matches the selector + /// of the current method, which might imply that some kind of delegation + /// is occurring. + CCD_SelectorMatch = -3 }; /// \brief Priority value factors by which we will divide or multiply the diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 8e1e6914c669..384cf524c9ed 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -143,6 +143,9 @@ namespace { /// \brief Whether the \p ObjectTypeQualifiers field is active. bool HasObjectTypeQualifiers; + /// \brief The selector that we prefer. + Selector PreferredSelector; + void AdjustResultPriorityForPreferredType(Result &R); public: @@ -187,6 +190,15 @@ namespace { HasObjectTypeQualifiers = true; } + /// \brief Set the preferred selector. + /// + /// When an Objective-C method declaration result is added, and that + /// method's selector matches this preferred selector, we give that method + /// a slight priority boost. + void setPreferredSelector(Selector Sel) { + PreferredSelector = Sel; + } + /// \brief Specify whether nested-name-specifiers are allowed. void allowNestedNameSpecifiers(bool Allow = true) { AllowNestedNameSpecifiers = Allow; @@ -706,7 +718,14 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Make sure that any given declaration only shows up in the result set once. if (!AllDeclsFound.insert(CanonDecl)) return; - + + // If this is an Objective-C method declaration whose selector matches our + // preferred selector, give it a priority boost. + if (!PreferredSelector.isNull()) + if (ObjCMethodDecl *Method = dyn_cast(R.Declaration)) + if (PreferredSelector == Method->getSelector()) + R.Priority += CCD_SelectorMatch; + // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. if (AsNestedNameSpecifier) { @@ -714,7 +733,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { R.Priority = CCP_NestedNameSpecifier; } else if (!PreferredType.isNull()) AdjustResultPriorityForPreferredType(R); - + // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && !R.StartsNestedNameSpecifier) { @@ -787,6 +806,13 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (InBaseClass) R.Priority += CCD_InBaseClass; + // If this is an Objective-C method declaration whose selector matches our + // preferred selector, give it a priority boost. + if (!PreferredSelector.isNull()) + if (ObjCMethodDecl *Method = dyn_cast(R.Declaration)) + if (PreferredSelector == Method->getSelector()) + R.Priority += CCD_SelectorMatch; + if (!PreferredType.isNull()) AdjustResultPriorityForPreferredType(R); @@ -3996,6 +4022,11 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, Results.Ignore(SuperMethod); } + // If we're inside an Objective-C method definition, prefer its selector to + // others. + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + Results.setPreferredSelector(CurMethod->getSelector()); + if (CDecl) AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, Results); @@ -4071,6 +4102,11 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, Results.Ignore(SuperMethod); } + // If we're inside an Objective-C method definition, prefer its selector to + // others. + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + Results.setPreferredSelector(CurMethod->getSelector()); + // If we're messaging an expression with type "id" or "Class", check // whether we know something special about the receiver that allows // us to assume a more-specific receiver type. diff --git a/clang/test/Index/complete-objc-message-id.m b/clang/test/Index/complete-objc-message-id.m index a75ee4a81d5c..be42b9b855ef 100644 --- a/clang/test/Index/complete-objc-message-id.m +++ b/clang/test/Index/complete-objc-message-id.m @@ -26,6 +26,11 @@ void message_id(B *b) { [[b superclass] B_method]; } +@implementation Unrelated ++ (id)alloc { + return [A alloc]; +} +@end // RUN: c-index-test -code-completion-at=%s:24:14 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease} // CHECK-CC1-NOT: B_method @@ -40,3 +45,10 @@ void message_id(B *b) { // CHECK-CC3: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain} +// RUN: c-index-test -code-completion-at=%s:31:13 %s | FileCheck -check-prefix=CHECK-SELECTOR-PREF %s +// CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType id}{TypedText alloc} (17) +// CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType Class}{TypedText class} (20) +// CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType id}{TypedText init} (20) +// CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType id}{TypedText new} (20) +// CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType Class}{TypedText superclass} (20) +