forked from OSchip/llvm-project
Don't format the code completion for parameters of block literal
arguments as block literal arguments; the block literal argument code completion should only go one level deep. Fixes <rdar://problem/10291294>. llvm-svn: 142335
This commit is contained in:
parent
bab66789d5
commit
d793e7c3f7
|
@ -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<ObjCMethodDecl>(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<TypedefTypeLoc>(&TL)) {
|
||||
if (TypeSourceInfo *InnerTSInfo
|
||||
= TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
|
||||
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
|
||||
if (!SuppressBlock) {
|
||||
if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
|
||||
if (TypeSourceInfo *InnerTSInfo
|
||||
= TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
|
||||
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Look through qualified types
|
||||
if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
|
||||
TL = QualifiedTL->getUnqualifiedLoc();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Look through qualified types
|
||||
if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue