diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 405d626ae9ba..5589245d1a72 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1966,7 +1966,8 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals) { static std::string FormatFunctionParameter(ASTContext &Context, const PrintingPolicy &Policy, ParmVarDecl *Param, - bool SuppressName = false) { + bool SuppressName = false, + bool SuppressBlock = false) { bool ObjCMethodParam = isa(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -1997,20 +1998,22 @@ static std::string FormatFunctionParameter(ASTContext &Context, TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); while (true) { // Look through typedefs. - if (TypedefTypeLoc *TypedefTL = dyn_cast(&TL)) { - if (TypeSourceInfo *InnerTSInfo - = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) { - TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); + if (!SuppressBlock) { + if (TypedefTypeLoc *TypedefTL = dyn_cast(&TL)) { + if (TypeSourceInfo *InnerTSInfo + = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) { + TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); + continue; + } + } + + // Look through qualified types + if (QualifiedTypeLoc *QualifiedTL = dyn_cast(&TL)) { + TL = QualifiedTL->getUnqualifiedLoc(); continue; } } - // Look through qualified types - if (QualifiedTypeLoc *QualifiedTL = dyn_cast(&TL)) { - TL = QualifiedTL->getUnqualifiedLoc(); - continue; - } - // Try to get the function prototype behind the block pointer type, // then we're done. if (BlockPointerTypeLoc *BlockPtr @@ -2027,6 +2030,9 @@ static std::string FormatFunctionParameter(ASTContext &Context, // We were unable to find a FunctionProtoTypeLoc with parameter names // for the block; just use the parameter type as a placeholder. std::string Result; + if (!ObjCMethodParam && Param->getIdentifier()) + Result = Param->getIdentifier()->getName(); + Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { @@ -2038,36 +2044,52 @@ static std::string FormatFunctionParameter(ASTContext &Context, return Result; } - + // We have the function prototype behind the block pointer type, as it was // written in the source. std::string Result; QualType ResultType = Block->getTypePtr()->getResultType(); - if (!ResultType->isVoidType()) + if (!ResultType->isVoidType() || SuppressBlock) ResultType.getAsStringInternal(Result, Policy); - - Result = '^' + Result; + + // Format the parameter list. + std::string Params; if (!BlockProto || Block->getNumArgs() == 0) { if (BlockProto && BlockProto->getTypePtr()->isVariadic()) - Result += "(...)"; + Params = "(...)"; else - Result += "(void)"; + Params = "(void)"; } else { - Result += "("; + Params += "("; for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) { if (I) - Result += ", "; - Result += FormatFunctionParameter(Context, Policy, Block->getArg(I)); + Params += ", "; + Params += FormatFunctionParameter(Context, Policy, Block->getArg(I), + /*SuppressName=*/false, + /*SuppressBlock=*/true); if (I == N - 1 && BlockProto->getTypePtr()->isVariadic()) - Result += ", ..."; + Params += ", ..."; } - Result += ")"; + Params += ")"; + } + + if (SuppressBlock) { + // Format as a parameter. + Result = Result + " (^"; + if (Param->getIdentifier()) + Result += Param->getIdentifier()->getName(); + Result += ")"; + Result += Params; + } else { + // Format as a block literal argument. + Result = '^' + Result; + Result += Params; + + if (Param->getIdentifier()) + Result += Param->getIdentifier()->getName(); } - if (Param->getIdentifier()) - Result += Param->getIdentifier()->getName(); - return Result; } diff --git a/clang/test/Index/complete-blocks.m b/clang/test/Index/complete-blocks.m index e7919efb0eb8..cb507e2be34e 100644 --- a/clang/test/Index/complete-blocks.m +++ b/clang/test/Index/complete-blocks.m @@ -26,14 +26,22 @@ void test_B(B *b) { } @interface C -- method4:(void(^)(void))arg { }; -- method5:(void(^)())arg5 { }; +- method4:(void(^)(void))arg; +- method5:(void(^)())arg5; @end void test_C(C *c) { [c method4:^{}]; } +@interface D +- method6:(void(^)(block_t block))arg; +@end + +void test_D(D *d) { + [d method6:0]; +} + // RUN: c-index-test -code-completion-at=%s:8:1 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: FunctionDecl:{ResultType void}{TypedText f}{LeftParen (}{Placeholder ^int(int x, int y)block}{RightParen )} (50) // CHECK-CC1: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{Placeholder ^(float f, double d)b}{RightParen )} (50) @@ -51,3 +59,6 @@ void test_C(C *c) { // CHECK-CC5-NOT: test_A // CHECK-CC5: {TypedText union} (50) +// RUN: c-index-test -code-completion-at=%s:42:6 %s | FileCheck -check-prefix=CHECK-CC6 %s +// CHECK-CC6: ObjCInstanceMethodDecl:{ResultType id}{TypedText method6:}{Placeholder ^(block_t block)arg} (35) +