Skip to content

[clang][ExtractAPI] Add support for blocks in declaration fragments (… #7841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/ExtractAPI/DeclarationFragments.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/StringRef.h"
#include <vector>
Expand Down Expand Up @@ -304,6 +305,11 @@ class DeclarationFragmentsBuilder {
/// Build DeclarationFragments for a parameter variable declaration
/// ParmVarDecl.
static DeclarationFragments getFragmentsForParam(const ParmVarDecl *);

static DeclarationFragments
getFragmentsForBlock(const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
FunctionProtoTypeLoc &BlockProto,
DeclarationFragments &After);
};

} // namespace extractapi
Expand Down
180 changes: 150 additions & 30 deletions clang/lib/ExtractAPI/DeclarationFragments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,49 @@
//===----------------------------------------------------------------------===//

#include "clang/ExtractAPI/DeclarationFragments.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
#include "clang/Index/USRGeneration.h"
#include "llvm/ADT/StringSwitch.h"

using namespace clang::extractapi;
using namespace llvm;

namespace {

void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo,
clang::FunctionTypeLoc &Block,
clang::FunctionProtoTypeLoc &BlockProto) {
if (!TSInfo)
return;

clang::TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
while (true) {
// Look through qualified types
if (auto QualifiedTL = TL.getAs<clang::QualifiedTypeLoc>()) {
TL = QualifiedTL.getUnqualifiedLoc();
continue;
}

if (auto AttrTL = TL.getAs<clang::AttributedTypeLoc>()) {
TL = AttrTL.getModifiedLoc();
continue;
}

// Try to get the function prototype behind the block pointer type,
// then we're done.
if (auto BlockPtr = TL.getAs<clang::BlockPointerTypeLoc>()) {
TL = BlockPtr.getPointeeLoc().IgnoreParens();
Block = TL.getAs<clang::FunctionTypeLoc>();
BlockProto = TL.getAs<clang::FunctionProtoTypeLoc>();
}
break;
}
}

} // namespace

DeclarationFragments &DeclarationFragments::appendSpace() {
if (!Fragments.empty()) {
Fragment &Last = Fragments.back();
Expand Down Expand Up @@ -161,7 +197,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(

// Declaration fragments of a pointer type is the declaration fragments of
// the pointee type followed by a `*`,
if (T->isPointerType())
if (T->isPointerType() && !T->isFunctionPointerType())
return Fragments
.append(getFragmentsForType(T->getPointeeType(), Context, After))
.append(" *", DeclarationFragments::FragmentKind::Text);
Expand Down Expand Up @@ -371,46 +407,110 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
.append(VarDecl::getStorageClassSpecifierString(SC),
DeclarationFragments::FragmentKind::Keyword)
.appendSpace();
QualType T =
Var->getTypeSourceInfo()
? Var->getTypeSourceInfo()->getType()
: Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());

// Capture potential fragments that needs to be placed after the variable name
// ```
// int nums[5];
// char (*ptr_to_array)[6];
// ```
DeclarationFragments After;
return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
.appendSpace()
FunctionTypeLoc BlockLoc;
FunctionProtoTypeLoc BlockProtoLoc;
findTypeLocForBlockDecl(Var->getTypeSourceInfo(), BlockLoc, BlockProtoLoc);

if (!BlockLoc) {
QualType T = Var->getTypeSourceInfo()
? Var->getTypeSourceInfo()->getType()
: Var->getASTContext().getUnqualifiedObjCPointerType(
Var->getType());

Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
.appendSpace();
} else {
Fragments.append(getFragmentsForBlock(Var, BlockLoc, BlockProtoLoc, After));
}

return Fragments
.append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
.append(std::move(After));
.append(std::move(After))
.append(";", DeclarationFragments::FragmentKind::Text);
}

DeclarationFragments
DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
DeclarationFragments Fragments, After;

QualType T = Param->getTypeSourceInfo()
? Param->getTypeSourceInfo()->getType()
: Param->getASTContext().getUnqualifiedObjCPointerType(
Param->getType());
auto *TSInfo = Param->getTypeSourceInfo();

DeclarationFragments TypeFragments =
getFragmentsForType(T, Param->getASTContext(), After);
QualType T = TSInfo ? TSInfo->getType()
: Param->getASTContext().getUnqualifiedObjCPointerType(
Param->getType());

if (Param->isObjCMethodParameter())
FunctionTypeLoc BlockLoc;
FunctionProtoTypeLoc BlockProtoLoc;
findTypeLocForBlockDecl(TSInfo, BlockLoc, BlockProtoLoc);

DeclarationFragments TypeFragments;
if (BlockLoc)
TypeFragments.append(
getFragmentsForBlock(Param, BlockLoc, BlockProtoLoc, After));
else
TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After));

if (Param->isObjCMethodParameter()) {
Fragments.append("(", DeclarationFragments::FragmentKind::Text)
.append(std::move(TypeFragments))
.append(") ", DeclarationFragments::FragmentKind::Text);
else
Fragments.append(std::move(TypeFragments)).appendSpace();
.append(std::move(After))
.append(") ", DeclarationFragments::FragmentKind::Text)
.append(Param->getName(),
DeclarationFragments::FragmentKind::InternalParam);
} else {
Fragments.append(std::move(TypeFragments));
if (!T->isBlockPointerType())
Fragments.appendSpace();
Fragments
.append(Param->getName(),
DeclarationFragments::FragmentKind::InternalParam)
.append(std::move(After));
}
return Fragments;
}

return Fragments
.append(Param->getName(),
DeclarationFragments::FragmentKind::InternalParam)
.append(std::move(After));
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After) {
DeclarationFragments Fragments;

DeclarationFragments RetTyAfter;
auto ReturnValueFragment = getFragmentsForType(
Block.getTypePtr()->getReturnType(), BlockDecl->getASTContext(), After);

Fragments.append(std::move(ReturnValueFragment))
.append(std::move(RetTyAfter))
.appendSpace()
.append("(^", DeclarationFragments::FragmentKind::Text);

After.append(")", DeclarationFragments::FragmentKind::Text);
unsigned NumParams = Block.getNumParams();

if (!BlockProto || NumParams == 0) {
if (BlockProto && BlockProto.getTypePtr()->isVariadic())
After.append("(...)", DeclarationFragments::FragmentKind::Text);
else
After.append("()", DeclarationFragments::FragmentKind::Text);
} else {
After.append("(", DeclarationFragments::FragmentKind::Text);
for (unsigned I = 0; I != NumParams; ++I) {
if (I)
After.append(", ", DeclarationFragments::FragmentKind::Text);
After.append(getFragmentsForParam(Block.getParam(I)));
if (I == NumParams - 1 && BlockProto.getTypePtr()->isVariadic())
After.append(", ...", DeclarationFragments::FragmentKind::Text);
}
After.append(")", DeclarationFragments::FragmentKind::Text);
}

return Fragments;
}

DeclarationFragments
Expand Down Expand Up @@ -445,12 +545,19 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
.append(std::move(After));

Fragments.append("(", DeclarationFragments::FragmentKind::Text);
for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
unsigned NumParams = Func->getNumParams();
for (unsigned i = 0; i != NumParams; ++i) {
if (i)
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
Fragments.append(getFragmentsForParam(Func->getParamDecl(i)));
}
Fragments.append(")", DeclarationFragments::FragmentKind::Text);

if (Func->isVariadic()) {
if (NumParams > 0)
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
}
Fragments.append(");", DeclarationFragments::FragmentKind::Text);

// FIXME: Handle exception specifiers: throw, noexcept
return Fragments;
Expand Down Expand Up @@ -705,14 +812,27 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
Fragments.append(")", DeclarationFragments::FragmentKind::Text);
}

// Build the property type and name, and return the completed fragments.
return Fragments.appendSpace()
.append(getFragmentsForType(Property->getType(),
Property->getASTContext(), After))
.appendSpace()
Fragments.appendSpace();

FunctionTypeLoc BlockLoc;
FunctionProtoTypeLoc BlockProtoLoc;
findTypeLocForBlockDecl(Property->getTypeSourceInfo(), BlockLoc,
BlockProtoLoc);

auto PropType = Property->getType();
if (!BlockLoc)
Fragments
.append(getFragmentsForType(PropType, Property->getASTContext(), After))
.appendSpace();
else
Fragments.append(
getFragmentsForBlock(Property, BlockLoc, BlockProtoLoc, After));

return Fragments
.append(Property->getName(),
DeclarationFragments::FragmentKind::Identifier)
.append(std::move(After));
.append(std::move(After))
.append(";", DeclarationFragments::FragmentKind::Text);
}

DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(
Expand Down
10 changes: 5 additions & 5 deletions clang/test/ExtractAPI/availability.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
},
{
"kind": "text",
"spelling": "()"
"spelling": "();"
}
],
"functionSignature": {
Expand Down Expand Up @@ -150,7 +150,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
},
{
"kind": "text",
"spelling": "()"
"spelling": "();"
}
],
"functionSignature": {
Expand Down Expand Up @@ -234,7 +234,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
},
{
"kind": "text",
"spelling": "()"
"spelling": "();"
}
],
"functionSignature": {
Expand Down Expand Up @@ -334,7 +334,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
},
{
"kind": "text",
"spelling": "()"
"spelling": "();"
}
],
"functionSignature": {
Expand Down Expand Up @@ -416,7 +416,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
},
{
"kind": "text",
"spelling": "()"
"spelling": "();"
}
],
"functionSignature": {
Expand Down
6 changes: 5 additions & 1 deletion clang/test/ExtractAPI/global_record.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ char unavailable __attribute__((unavailable));
{
"kind": "identifier",
"spelling": "num"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
Expand Down Expand Up @@ -189,7 +193,7 @@ char unavailable __attribute__((unavailable));
},
{
"kind": "text",
"spelling": ")"
"spelling": ");"
}
],
"docComment": {
Expand Down
6 changes: 5 additions & 1 deletion clang/test/ExtractAPI/global_record_multifile.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ char unavailable __attribute__((unavailable));
{
"kind": "identifier",
"spelling": "num"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
Expand Down Expand Up @@ -191,7 +195,7 @@ char unavailable __attribute__((unavailable));
},
{
"kind": "text",
"spelling": ")"
"spelling": ");"
}
],
"docComment": {
Expand Down
4 changes: 4 additions & 0 deletions clang/test/ExtractAPI/known_files_only.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ struct Foo { int a; };
{
"kind": "identifier",
"spelling": "num"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
Expand Down
8 changes: 8 additions & 0 deletions clang/test/ExtractAPI/language.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ char objc;
{
"kind": "identifier",
"spelling": "c"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
Expand Down Expand Up @@ -150,6 +154,10 @@ char objc;
{
"kind": "identifier",
"spelling": "objc"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
Expand Down
Loading