From 3b49aca913dc0c1838321b9bb2dc9a4cb4681922 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 18 Nov 2009 16:26:39 +0000 Subject: [PATCH] Code completion for Objective-C class names after @interface, @implementation, and in the declaration of the superclass of an @interface. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89207 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Action.h | 18 ++++++++ lib/Parse/ParseObjc.cpp | 19 +++++++++ lib/Sema/Sema.h | 6 ++- lib/Sema/SemaCodeComplete.cpp | 70 ++++++++++++++++++++++++++++++++ test/Index/complete-interfaces.m | 43 ++++++++++++++++++++ 5 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 test/Index/complete-interfaces.m diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index a9b3213323..62f7221a88 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2371,6 +2371,24 @@ public: /// /// \param S the scope in which the protocol declaration occurs. virtual void CodeCompleteObjCProtocolDecl(Scope *S) { } + + /// \brief Code completion for an Objective-C interface, after the + /// @interface but before any identifier. + virtual void CodeCompleteObjCInterfaceDecl(Scope *S) { } + + /// \brief Code completion for the superclass of an Objective-C + /// interface, after the ':'. + /// + /// \param S the scope in which the interface declaration occurs. + /// + /// \param ClassName the name of the class being defined. + virtual void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName) { + } + + /// \brief Code completion for an Objective-C implementation, after the + /// @implementation but before any identifier. + virtual void CodeCompleteObjCImplementationDecl(Scope *S) { } //@} }; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 65bd79d6b4..a60c89a0f1 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -123,6 +123,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( "ParseObjCAtInterfaceDeclaration(): Expected @interface"); ConsumeToken(); // the "interface" identifier + // Code completion after '@interface'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceDecl(CurScope); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); @@ -181,6 +187,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); + + // Code completion of superclass names. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSuperclass(CurScope, nameId); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing super class name. return DeclPtrTy(); @@ -1078,6 +1091,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( "ParseObjCAtImplementationDeclaration(): Expected @implementation"); ConsumeToken(); // the "implementation" identifier + // Code completion after '@implementation'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCImplementationDecl(CurScope); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3e186b2b5b..ae5304de44 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3645,7 +3645,11 @@ public: virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols); virtual void CodeCompleteObjCProtocolDecl(Scope *S); - //@} + virtual void CodeCompleteObjCInterfaceDecl(Scope *S); + virtual void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName); + virtual void CodeCompleteObjCImplementationDecl(Scope *S); + //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 9cecdadc86..eaa4f1514a 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1885,3 +1885,73 @@ void Sema::CodeCompleteObjCProtocolDecl(Scope *) { Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } + +/// \brief Add all of the Objective-C interface declarations that we find in +/// the given (translation unit) context. +static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, + bool OnlyForwardDeclarations, + bool OnlyUnimplemented, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + + for (DeclContext::decl_iterator D = Ctx->decls_begin(), + DEnd = Ctx->decls_end(); + D != DEnd; ++D) { + // Record any interfaces we find. + if (ObjCInterfaceDecl *Class = dyn_cast(*D)) + if ((!OnlyForwardDeclarations || Class->isForwardDecl()) && + (!OnlyUnimplemented || !Class->getImplementation())) + Results.MaybeAddResult(Result(Class, 0), CurContext); + + // Record any forward-declared interfaces we find. + if (ObjCClassDecl *Forward = dyn_cast(*D)) { + for (ObjCClassDecl::iterator C = Forward->begin(), CEnd = Forward->end(); + C != CEnd; ++C) + if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) && + (!OnlyUnimplemented || !C->getInterface()->getImplementation())) + Results.MaybeAddResult(Result(C->getInterface(), 0), CurContext); + } + } +} + +void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, true, + false, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Make sure that we ignore the class we're currently defining. + NamedDecl *CurClass + = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + if (isa(CurClass)) + Results.Ignore(CurClass); + + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add all unimplemented classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + true, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} diff --git a/test/Index/complete-interfaces.m b/test/Index/complete-interfaces.m new file mode 100644 index 0000000000..229ec2dcbe --- /dev/null +++ b/test/Index/complete-interfaces.m @@ -0,0 +1,43 @@ +/* Note: the RUN lines are near the end of the file, since line/column + matter for this test. */ + +@class Int1, Int2, Int3, Int4; + +@interface Int3 +{ +} +@end + +@interface Int2 : Int3 +{ +} +@end + +@implementation Int2 +@end + +@implementation Int3 +@end + +// RUN: c-index-test -code-completion-at=%s:6:12 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: ObjCInterfaceDecl:{TypedText Int1} +// CHECK-CC1: ObjCInterfaceDecl:{TypedText Int2} +// CHECK-CC1: ObjCInterfaceDecl:{TypedText Int3} +// CHECK-CC1: ObjCInterfaceDecl:{TypedText Int4} +// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: ObjCInterfaceDecl:{TypedText Int1} +// CHECK-CC2-NEXT: ObjCInterfaceDecl:{TypedText Int2} +// CHECK-CC2-NEXT: ObjCInterfaceDecl:{TypedText Int4} +// RUN: c-index-test -code-completion-at=%s:11:19 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: ObjCInterfaceDecl:{TypedText Int1} +// CHECK-CC3-NEXT: ObjCInterfaceDecl:{TypedText Int3} +// CHECK-CC3-NEXT: ObjCInterfaceDecl:{TypedText Int4} +// RUN: c-index-test -code-completion-at=%s:16:17 %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: ObjCInterfaceDecl:{TypedText Int1} +// CHECK-CC4-NEXT: ObjCInterfaceDecl:{TypedText Int2} +// CHECK-CC4-NEXT: ObjCInterfaceDecl:{TypedText Int3} +// CHECK-CC4-NEXT: ObjCInterfaceDecl:{TypedText Int4} +// RUN: c-index-test -code-completion-at=%s:19:17 %s | FileCheck -check-prefix=CHECK-CC5 %s +// CHECK-CC5: ObjCInterfaceDecl:{TypedText Int1} +// CHECK-CC5-NEXT: ObjCInterfaceDecl:{TypedText Int3} +// CHECK-CC5-NEXT: ObjCInterfaceDecl:{TypedText Int4} -- 2.40.0