diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index ee852ff95c..a9b3213323 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2365,6 +2365,12 @@ public: /// parsed. virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols) { } + + /// \brief Code completion for a protocol declaration or definition, after + /// the @protocol but before any identifier. + /// + /// \param S the scope in which the protocol declaration occurs. + virtual void CodeCompleteObjCProtocolDecl(Scope *S) { } //@} }; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index dc173eaf4d..65bd79d6b4 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -994,6 +994,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, "ParseObjCAtProtocolDeclaration(): Expected @protocol"); ConsumeToken(); // the "protocol" identifier + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolDecl(CurScope); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing protocol name. return DeclPtrTy(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 333cc00069..e16bfaa57c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -4017,7 +4017,8 @@ public: virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver); virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols); - //@} + virtual void CodeCompleteObjCProtocolDecl(Scope *S); + //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index be1ddddd69..9cecdadc86 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1830,6 +1830,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { /// \brief Add all of the protocol declarations that we find in the given /// (translation unit) context. static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, + bool OnlyForwardDeclarations, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; @@ -1838,7 +1839,8 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, D != DEnd; ++D) { // Record any protocols we find. if (ObjCProtocolDecl *Proto = dyn_cast(*D)) - Results.MaybeAddResult(Result(Proto, 0), CurContext); + if (!OnlyForwardDeclarations || Proto->isForwardDecl()) + Results.MaybeAddResult(Result(Proto, 0), CurContext); // Record any forward-declared protocols we find. if (ObjCForwardProtocolDecl *Forward @@ -1847,7 +1849,8 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, P = Forward->protocol_begin(), PEnd = Forward->protocol_end(); P != PEnd; ++P) - Results.MaybeAddResult(Result(*P, 0), CurContext); + if (!OnlyForwardDeclarations || (*P)->isForwardDecl()) + Results.MaybeAddResult(Result(*P, 0), CurContext); } } } @@ -1864,7 +1867,20 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, Results.Ignore(Protocol); // Add all protocols. - AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, Results); + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, false, + Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCProtocolDecl(Scope *) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add all protocols. + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true, + Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); diff --git a/test/Index/complete-protocols.m b/test/Index/complete-protocols.m index f84b6248b8..89f61bcf9a 100644 --- a/test/Index/complete-protocols.m +++ b/test/Index/complete-protocols.m @@ -8,9 +8,18 @@ void f(id); +@protocol Protocol0; +@protocol NewProtocol +{ +} +@end + // RUN: c-index-test -code-completion-at=%s:9:11 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: ObjCProtocolDecl:{TypedText Protocol1} // CHECK-CC1: ObjCProtocolDecl:{TypedText Protocol2} // RUN: c-index-test -code-completion-at=%s:9:21 %s | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2-NOT: ObjCProtocolDecl:{TypedText Protocol1} // CHECK-CC2: ObjCProtocolDecl:{TypedText Protocol2} +// RUN: c-index-test -code-completion-at=%s:12:11 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: ObjCProtocolDecl:{TypedText Protocol0} +// CHECK-CC3-NEXT: ObjCProtocolDecl:{TypedText Protocol2}