From ea76618ced548ea1550a7a4de21cb8b6eea878bc Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 18 Oct 2010 18:21:28 +0000 Subject: [PATCH] When providing code completions of Objective-C method declarations (after - or +), always traverse superclasses and all categories. The programmer may want to complete a method from *anywhere*. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116723 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaCodeComplete.cpp | 76 +++++++++++------------------- test/Index/complete-method-decls.m | 4 +- 2 files changed, 31 insertions(+), 49 deletions(-) diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 9b504113f9..13bcfea0d8 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -5156,7 +5156,6 @@ static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, bool WantInstanceMethods, QualType ReturnType, - bool IsInImplementation, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { if (ObjCInterfaceDecl *IFace = dyn_cast(Container)) { @@ -5164,28 +5163,23 @@ static void FindImplementableMethods(ASTContext &Context, const ObjCList &Protocols = IFace->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - InOriginalClass); - - // If we're not in the implementation of a class, also visit the - // superclass. - if (!IsInImplementation && IFace->getSuperClass()) - FindImplementableMethods(Context, IFace->getSuperClass(), - WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - false); + KnownMethods, InOriginalClass); - // Add methods from any class extensions (but not from categories; - // those should go into category implementations). - for (const ObjCCategoryDecl *Cat = IFace->getFirstClassExtension(); Cat; - Cat = Cat->getNextClassExtension()) + // Add methods from any class extensions and categories. + for (const ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat; + Cat = Cat->getNextClassCategory()) FindImplementableMethods(Context, const_cast(Cat), WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - InOriginalClass); + KnownMethods, false); + + // Visit the superclass. + if (IFace->getSuperClass()) + FindImplementableMethods(Context, IFace->getSuperClass(), + WantInstanceMethods, ReturnType, + KnownMethods, false); } if (ObjCCategoryDecl *Category = dyn_cast(Container)) { @@ -5193,11 +5187,16 @@ static void FindImplementableMethods(ASTContext &Context, const ObjCList &Protocols = Category->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, - InOriginalClass); + KnownMethods, InOriginalClass); + + // If this category is the original class, jump to the interface. + if (InOriginalClass && Category->getClassInterface()) + FindImplementableMethods(Context, Category->getClassInterface(), + WantInstanceMethods, ReturnType, KnownMethods, + false); } if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { @@ -5208,7 +5207,7 @@ static void FindImplementableMethods(ASTContext &Context, E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods, false); + KnownMethods, false); } // Add methods in this container. This operation occurs last because @@ -5235,33 +5234,27 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // provided. QualType ReturnType = GetTypeFromParser(ReturnTy); - // Determine where we should start searching for methods, and where we - ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0; + // Determine where we should start searching for methods. + ObjCContainerDecl *SearchDecl = 0; bool IsInImplementation = false; if (Decl *D = IDecl) { if (ObjCImplementationDecl *Impl = dyn_cast(D)) { SearchDecl = Impl->getClassInterface(); - CurrentDecl = Impl; IsInImplementation = true; } else if (ObjCCategoryImplDecl *CatImpl - = dyn_cast(D)) { + = dyn_cast(D)) { SearchDecl = CatImpl->getCategoryDecl(); - CurrentDecl = CatImpl; IsInImplementation = true; - } else { + } else SearchDecl = dyn_cast(D); - CurrentDecl = SearchDecl; - } } if (!SearchDecl && S) { - if (DeclContext *DC = static_cast(S->getEntity())) { + if (DeclContext *DC = static_cast(S->getEntity())) SearchDecl = dyn_cast(DC); - CurrentDecl = SearchDecl; - } } - if (!SearchDecl || !CurrentDecl) { + if (!SearchDecl) { HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, 0, 0); @@ -5271,21 +5264,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // Find all of the methods that we could declare/implement here. KnownMethodsMap KnownMethods; FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, - ReturnType, IsInImplementation, KnownMethods); + ReturnType, KnownMethods); - // Erase any methods that have already been declared or - // implemented here. - for (ObjCContainerDecl::method_iterator M = CurrentDecl->meth_begin(), - MEnd = CurrentDecl->meth_end(); - M != MEnd; ++M) { - if ((*M)->isInstanceMethod() != IsInstanceMethod) - continue; - - KnownMethodsMap::iterator Pos = KnownMethods.find((*M)->getSelector()); - if (Pos != KnownMethods.end()) - KnownMethods.erase(Pos); - } - // Add declarations or definitions for each of the known methods. typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompletionContext::CCC_Other); diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m index 30659353f4..1da5f1c6eb 100644 --- a/test/Index/complete-method-decls.m +++ b/test/Index/complete-method-decls.m @@ -92,11 +92,13 @@ // CHECK-CC5: ObjCInstanceMethodDecl:{TypedText setValue}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace // RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:37:7 %s | FileCheck -check-prefix=CHECK-CC6 %s // CHECK-CC6: ObjCInstanceMethodDecl:{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace -// CHECK-CC6-NOT: getSelf +// CHECK-CC6: ObjCInstanceMethodDecl:{TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (30) // CHECK-CC6: ObjCInstanceMethodDecl:{TypedText initWithInt}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace // CHECK-CC6: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace // RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:42:3 %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (32) // CHECK-CC7: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText categoryFunction}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace +// CHECK-CC7: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (32) // RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:52:21 %s | FileCheck -check-prefix=CHECK-CC8 %s // CHECK-CC8: ObjCInstanceMethodDecl:{ResultType id}{Informative first:}{TypedText second2:}{Text (float)y2}{HorizontalSpace }{Text third:}{Text (double)z} (20) // CHECK-CC8: ObjCInstanceMethodDecl:{ResultType void *}{Informative first:}{TypedText second3:}{Text (float)y3}{HorizontalSpace }{Text third:}{Text (double)z} (20) -- 2.40.0