When providing completions for a function or method argument that

corresponds to a block pointer, provide the skeleton of a block
literal.

llvm-svn: 111918
This commit is contained in:
Douglas Gregor 2010-08-24 16:15:59 +00:00
parent c88fda477a
commit e90dd00c3c
2 changed files with 132 additions and 11 deletions

View File

@ -1690,6 +1690,102 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
}
}
static std::string FormatFunctionParameter(ASTContext &Context,
ParmVarDecl *Param) {
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
// The argument for a dependent or non-block parameter is a placeholder
// containing that parameter's type.
std::string Result;
if (Param->getIdentifier() && !ObjCMethodParam)
Result = Param->getIdentifier()->getName();
Param->getType().getAsStringInternal(Result,
Context.PrintingPolicy);
if (ObjCMethodParam) {
Result = "(" + Result;
Result += ")";
if (Param->getIdentifier())
Result += Param->getIdentifier()->getName();
}
return Result;
}
// The argument for a block pointer parameter is a block literal with
// the appropriate type.
FunctionProtoTypeLoc *Block = 0;
TypeLoc TL;
if (TypeSourceInfo *TSInfo = Param->getTypeSourceInfo()) {
TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
while (true) {
// Look through typedefs.
if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
if (TypeSourceInfo *InnerTSInfo
= TypedefTL->getTypedefDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().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
= dyn_cast<BlockPointerTypeLoc>(&TL)) {
TL = BlockPtr->getPointeeLoc();
Block = dyn_cast<FunctionProtoTypeLoc>(&TL);
}
break;
}
}
if (!Block) {
// We were unable to find a FunctionProtoTypeLoc with parameter names
// for the block; just use the parameter type as a placeholder.
std::string Result;
Param->getType().getUnqualifiedType().
getAsStringInternal(Result, Context.PrintingPolicy);
if (ObjCMethodParam) {
Result = "(" + Result;
Result += ")";
if (Param->getIdentifier())
Result += Param->getIdentifier()->getName();
}
return Result;
}
// We have the function prototype behind the block pointer type, as it was
// written in the source.
std::string Result = "(^)(";
for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) {
if (I)
Result += ", ";
Result += FormatFunctionParameter(Context, Block->getArg(I));
}
if (Block->getTypePtr()->isVariadic()) {
if (Block->getNumArgs() > 0)
Result += ", ...";
else
Result += "...";
} else if (Block->getNumArgs() == 0 && !Context.getLangOptions().CPlusPlus)
Result += "void";
Result += ")";
Block->getTypePtr()->getResultType().getAsStringInternal(Result,
Context.PrintingPolicy);
return Result;
}
/// \brief Add function parameter chunks to the given code completion string.
static void AddFunctionParameterChunks(ASTContext &Context,
FunctionDecl *Function,
@ -1713,13 +1809,8 @@ static void AddFunctionParameterChunks(ASTContext &Context,
CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma));
// Format the placeholder string.
std::string PlaceholderStr;
if (Param->getIdentifier())
PlaceholderStr = Param->getIdentifier()->getName();
Param->getType().getAsStringInternal(PlaceholderStr,
Context.PrintingPolicy);
std::string PlaceholderStr = FormatFunctionParameter(Context, Param);
// Add the placeholder string.
CCStr->AddPlaceholderChunk(PlaceholderStr);
}
@ -2028,10 +2119,16 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S,
continue;
std::string Arg;
(*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy);
Arg = "(" + Arg + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
Arg += II->getName().str();
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
Arg = FormatFunctionParameter(S.Context, *P);
else {
(*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy);
Arg = "(" + Arg + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
Arg += II->getName().str();
}
if (DeclaringEntity)
Result->AddTextChunk(Arg);
else if (AllParametersAreInformative)

View File

@ -0,0 +1,24 @@
// The line and column layout of this test is significant. Run lines
// are at the end.
typedef void (^block_t)(float f, double d);
void f(int (^block)(int x, int y));
void g(block_t b);
void test_f() {
}
@interface A
- method:(int (^)(int x, int y))b;
- method2:(block_t)b;
@end
void test_A(A *a) {
[a method: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)}{RightParen )} (50)
// CHECK-CC1: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{Placeholder void (^)(float f, double d)}{RightParen )} (50)
// RUN: c-index-test -code-completion-at=%s:17:6 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType id}{TypedText method2:}{Placeholder void (^)(float f, double d)} (20)
// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType id}{TypedText method:}{Placeholder int (^)(int x, int y)} (20)