From 55385fe3e723cd675001e45f42d61adde6b7f075 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 18 Nov 2009 04:19:12 +0000 Subject: [PATCH] Code completion for Objective-C properly lists git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89194 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Action.h | 13 ++++++++ lib/Parse/ParseObjc.cpp | 6 ++++ lib/Sema/Sema.h | 2 ++ lib/Sema/SemaCodeComplete.cpp | 46 +++++++++++++++++++++++++++++ test/Index/complete-member-access.m | 4 +-- test/Index/complete-property-list.m | 16 ++++++++++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 test/Index/complete-property-list.m diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index d1f241ea70..ee852ff95c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2352,6 +2352,19 @@ public: /// \param S the scope in which the operator keyword occurs. /// \param Receiver an expression for the receiver of the message. virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { } + + /// \brief Code completion for a list of protocol references in Objective-C, + /// such as P1 and P2 in \c id. + /// + /// This code completion action is invoked prior to each identifier + /// in the protocol list. + /// + /// \param Protocols the set of protocols that have already been parsed. + /// + /// \param NumProtocols the number of protocols that have already been + /// parsed. + virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, + unsigned NumProtocols) { } //@} }; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index f0b1e9f3ef..dc173eaf4d 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -834,6 +834,12 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl &Protocols, llvm::SmallVector ProtocolIdents; while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), + ProtocolIdents.size()); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::greater); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 35a7d782f1..333cc00069 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -4015,6 +4015,8 @@ public: virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, SourceLocation FNameLoc); virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver); + virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, + unsigned NumProtocols); //@} //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ebd860b692..be1ddddd69 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -95,6 +95,9 @@ namespace { /// \brief Exit from the current scope. void ExitScope(); + /// \brief Ignore this declaration, if it is seen again. + void Ignore(Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); } + /// \name Name lookup predicates /// /// These predicates can be passed to the name lookup functions to filter the @@ -1823,3 +1826,46 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } + +/// \brief Add all of the protocol declarations that we find in the given +/// (translation unit) context. +static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + + for (DeclContext::decl_iterator D = Ctx->decls_begin(), + DEnd = Ctx->decls_end(); + D != DEnd; ++D) { + // Record any protocols we find. + if (ObjCProtocolDecl *Proto = dyn_cast(*D)) + Results.MaybeAddResult(Result(Proto, 0), CurContext); + + // Record any forward-declared protocols we find. + if (ObjCForwardProtocolDecl *Forward + = dyn_cast(*D)) { + for (ObjCForwardProtocolDecl::protocol_iterator + P = Forward->protocol_begin(), + PEnd = Forward->protocol_end(); + P != PEnd; ++P) + Results.MaybeAddResult(Result(*P, 0), CurContext); + } + } +} + +void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, + unsigned NumProtocols) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Tell the result set to ignore all of the protocols we have + // already seen. + for (unsigned I = 0; I != NumProtocols; ++I) + if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first)) + Results.Ignore(Protocol); + + // Add all protocols. + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} diff --git a/test/Index/complete-member-access.m b/test/Index/complete-member-access.m index 94ba8e60c7..9202d0522f 100644 --- a/test/Index/complete-member-access.m +++ b/test/Index/complete-member-access.m @@ -1,5 +1,5 @@ -// Note: the RUN lines are near the end of the file, since line/column -// matter for this test. +/* Note: the RUN lines are near the end of the file, since line/column + matter for this test. */ @protocol MyProtocol @property float ProtoProp; diff --git a/test/Index/complete-property-list.m b/test/Index/complete-property-list.m new file mode 100644 index 0000000000..f84b6248b8 --- /dev/null +++ b/test/Index/complete-property-list.m @@ -0,0 +1,16 @@ +/* Note: the RUN lines are near the end of the file, since line/column + matter for this test. */ + +@protocol Protocol1 +@end + +@protocol Protocol2; + +void f(id); + +// 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}