diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index d4fa9a2453..0a73a644a3 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -3234,6 +3234,21 @@ enum CXCursorKind clang_codeCompleteGetContainerKind( CINDEX_LINKAGE CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results); + +/** + * \brief Returns the currently-entered selector for an Objective-C message + * send, formatted like "initWithFoo:bar:". Only guaranteed to return a + * non-empty string for CXCompletionContext_ObjCInstanceMessage and + * CXCompletionContext_ObjCClassMessage. + * + * \param Results the code completion results to query + * + * \returns the selector (or partial selector) that has been entered thus far + * for an Objective-C message send. + */ +CINDEX_LINKAGE +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results); + /** * @} */ diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 9b5564853c..8c7a00280b 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -268,12 +268,23 @@ private: /// \brief The type of the base object in a member access expression. QualType BaseType; + /// \brief The identifiers for Objective-C selector parts. + IdentifierInfo **SelIdents; + + /// \brief The number of Objective-C selector parts. + unsigned NumSelIdents; + public: /// \brief Construct a new code-completion context of the given kind. - CodeCompletionContext(enum Kind Kind) : Kind(Kind) { } + CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(NULL), + NumSelIdents(0) { } /// \brief Construct a new code-completion context of the given kind. - CodeCompletionContext(enum Kind Kind, QualType T) : Kind(Kind) { + CodeCompletionContext(enum Kind Kind, QualType T, + IdentifierInfo **SelIdents = NULL, + unsigned NumSelIdents = 0) : Kind(Kind), + SelIdents(SelIdents), + NumSelIdents(NumSelIdents) { if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess || Kind == CCC_ObjCPropertyAccess || Kind == CCC_ObjCClassMessage || Kind == CCC_ObjCInstanceMessage) @@ -293,6 +304,12 @@ public: /// \brief Retrieve the type of the base object in a member-access /// expression. QualType getBaseType() const { return BaseType; } + + /// \brief Retrieve the Objective-C selector identifiers. + IdentifierInfo **getSelIdents() const { return SelIdents; } + + /// \brief Retrieve the number of Objective-C selector identifiers. + unsigned getNumSelIdents() const { return NumSelIdents; } /// \brief Determines whether we want C++ constructors as results within this /// context. diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index a60fafe29c..01e95174e2 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4960,7 +4960,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, - T)); + T, SelIdents, NumSelIdents)); AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents, AtArgumentExpression, IsSuper, Results); @@ -5025,7 +5025,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // Build the set of methods we can see. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage, - ReceiverType)); + ReceiverType, SelIdents, NumSelIdents)); Results.EnterNewScope(); diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index e80243a300..7477f3f09a 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -228,6 +228,7 @@ void test_block_invoke(A *(^block1)(int), // RUN: c-index-test -code-completion-at=%s:95:24 %s | FileCheck -check-prefix=CHECK-CC9 %s // CHECK-CC9: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)} // CHECK-CC9: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)} +// CHECK-CC9: Objective-C selector: Method:Arg1: // RUN: c-index-test -code-completion-at=%s:61:11 %s | FileCheck -check-prefix=CHECK-CCA %s // CHECK-CCA: TypedefDecl:{TypedText Class} // CHECK-CCA-NEXT: ObjCInterfaceDecl:{TypedText Foo} @@ -253,6 +254,7 @@ void test_block_invoke(A *(^block1)(int), // CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)}{HorizontalSpace }{TypedText OtherArg:}{Placeholder (id)} // CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText SomeArg:}{Placeholder (int)}{HorizontalSpace }{TypedText OtherArg:}{Placeholder (id)} // CHECK-CCD-NOT: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText } +// CHECK-CCD: Objective-C selector: Method: // RUN: c-index-test -code-completion-at=%s:116:30 %s | FileCheck -check-prefix=CHECK-CCE %s // CHECK-CCE: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)} // CHECK-CCE: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)} diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 6d7bf5bb15..b737a38229 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1201,6 +1201,8 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { unsigned i, n = results->NumResults, containerIsIncomplete = 0; unsigned long long contexts; enum CXCursorKind containerKind; + CXString objCSelector; + const char *selectorString; if (!timing_only) { /* Sort the code-completion results based on the typed text. */ clang_sortCodeCompletionResults(results->Results, results->NumResults); @@ -1218,7 +1220,8 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { contexts = clang_codeCompleteGetContexts(results); print_completion_contexts(contexts, stdout); - containerKind = clang_codeCompleteGetContainerKind(results, &containerIsIncomplete); + containerKind = clang_codeCompleteGetContainerKind(results, + &containerIsIncomplete); if (containerKind != CXCursor_InvalidCode) { /* We have found a container */ @@ -1239,6 +1242,13 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { clang_disposeString(containerUSR); } + objCSelector = clang_codeCompleteGetObjCSelector(results); + selectorString = clang_getCString(objCSelector); + if (selectorString && strlen(selectorString) > 0) { + printf("Objective-C selector: %s\n", selectorString); + } + clang_disposeString(objCSelector); + clang_disposeCodeCompleteResults(results); } clang_disposeTranslationUnit(TU); diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 59636bf2d8..84050b2cfd 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -247,10 +247,17 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// current context. unsigned long long Contexts; + /// \brief The kind of the container for the current context for completions. enum CXCursorKind ContainerKind; + /// \brief The USR of the container for the current context for completions. CXString ContainerUSR; - + /// \brief a boolean value indicating whether there is complete information + /// about the container unsigned ContainerIsIncomplete; + + /// \brief A string containing the Objective-C selector entered thus far for a + /// message send. + std::string Selector; }; /// \brief Tracks the number of code-completion result objects that are @@ -495,6 +502,18 @@ namespace { AllocatedResults.ContextKind = contextKind; AllocatedResults.Contexts = getContextsForContextKind(contextKind, S); + AllocatedResults.Selector = ""; + if (Context.getNumSelIdents() > 0) { + for (unsigned i = 0; i < Context.getNumSelIdents(); i++) { + IdentifierInfo *selIdent = Context.getSelIdents()[i]; + if (selIdent != NULL) { + StringRef selectorString = Context.getSelIdents()[i]->getName(); + AllocatedResults.Selector += selectorString.str(); + } + AllocatedResults.Selector += ":"; + } + } + QualType baseType = Context.getBaseType(); NamedDecl *D = NULL; @@ -677,7 +696,7 @@ void clang_codeCompleteAt_Impl(void *UserData) { } pchName.push_back('\0'); struct stat stat_results; - if (stat(pchName.data(), &stat_results) == 0) + if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } @@ -810,6 +829,16 @@ CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) { return createCXString(clang_getCString(Results->ContainerUSR)); } + + +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast(ResultsIn); + if (!Results) + return createCXString(""); + + return createCXString(Results->Selector); +} } // end extern "C" diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index 96108649a1..59905364d8 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -10,6 +10,7 @@ _clang_codeCompleteGetNumDiagnostics _clang_codeCompleteGetContainerKind _clang_codeCompleteGetContainerUSR _clang_codeCompleteGetContexts +_clang_codeCompleteGetObjCSelector _clang_constructUSR_ObjCCategory _clang_constructUSR_ObjCClass _clang_constructUSR_ObjCIvar diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 329ae5a558..ab9face5ec 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -10,6 +10,7 @@ clang_codeCompleteGetNumDiagnostics clang_codeCompleteGetContainerKind clang_codeCompleteGetContainerUSR clang_codeCompleteGetContexts +clang_codeCompleteGetObjCSelector clang_constructUSR_ObjCCategory clang_constructUSR_ObjCClass clang_constructUSR_ObjCIvar