Skip to content

Commit e131e99

Browse files
[clang][ExtractAPI] Add support for blocks in declaration fragments (llvm#73369)
Ensure that block types get represented correctly in declaration fragments, as block parameter names are important for documentation clients we need a separate system from getFragmentsForType in order to have access to full ParmVarDecls for the parameters. rdar://118257401
1 parent 4106480 commit e131e99

File tree

13 files changed

+1196
-29
lines changed

13 files changed

+1196
-29
lines changed

clang/include/clang/ExtractAPI/DeclarationFragments.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "clang/AST/Decl.h"
2323
#include "clang/AST/DeclCXX.h"
2424
#include "clang/AST/DeclObjC.h"
25+
#include "clang/AST/TypeLoc.h"
2526
#include "clang/Lex/MacroInfo.h"
2627
#include "llvm/ADT/StringRef.h"
2728
#include <vector>
@@ -314,6 +315,11 @@ class DeclarationFragmentsBuilder {
314315
/// Build DeclarationFragments for a parameter variable declaration
315316
/// ParmVarDecl.
316317
static DeclarationFragments getFragmentsForParam(const ParmVarDecl *);
318+
319+
static DeclarationFragments
320+
getFragmentsForBlock(const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
321+
FunctionProtoTypeLoc &BlockProto,
322+
DeclarationFragments &After);
317323
};
318324

319325
} // namespace extractapi

clang/lib/ExtractAPI/DeclarationFragments.cpp

Lines changed: 153 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,53 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "clang/ExtractAPI/DeclarationFragments.h"
15+
#include "clang/AST/Decl.h"
16+
#include "clang/AST/DeclCXX.h"
17+
#include "clang/AST/QualTypeNames.h"
18+
#include "clang/AST/Type.h"
19+
#include "clang/AST/TypeLoc.h"
20+
#include "clang/Basic/OperatorKinds.h"
1521
#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
1622
#include "clang/Index/USRGeneration.h"
1723
#include "llvm/ADT/StringSwitch.h"
1824

1925
using namespace clang::extractapi;
2026
using namespace llvm;
2127

28+
namespace {
29+
30+
void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo,
31+
clang::FunctionTypeLoc &Block,
32+
clang::FunctionProtoTypeLoc &BlockProto) {
33+
if (!TSInfo)
34+
return;
35+
36+
clang::TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
37+
while (true) {
38+
// Look through qualified types
39+
if (auto QualifiedTL = TL.getAs<clang::QualifiedTypeLoc>()) {
40+
TL = QualifiedTL.getUnqualifiedLoc();
41+
continue;
42+
}
43+
44+
if (auto AttrTL = TL.getAs<clang::AttributedTypeLoc>()) {
45+
TL = AttrTL.getModifiedLoc();
46+
continue;
47+
}
48+
49+
// Try to get the function prototype behind the block pointer type,
50+
// then we're done.
51+
if (auto BlockPtr = TL.getAs<clang::BlockPointerTypeLoc>()) {
52+
TL = BlockPtr.getPointeeLoc().IgnoreParens();
53+
Block = TL.getAs<clang::FunctionTypeLoc>();
54+
BlockProto = TL.getAs<clang::FunctionProtoTypeLoc>();
55+
}
56+
break;
57+
}
58+
}
59+
60+
} // namespace
61+
2262
DeclarationFragments &DeclarationFragments::appendSpace() {
2363
if (!Fragments.empty()) {
2464
Fragment &Last = Fragments.back();
@@ -161,7 +201,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
161201

162202
// Declaration fragments of a pointer type is the declaration fragments of
163203
// the pointee type followed by a `*`,
164-
if (T->isPointerType())
204+
if (T->isPointerType() && !T->isFunctionPointerType())
165205
return Fragments
166206
.append(getFragmentsForType(T->getPointeeType(), Context, After))
167207
.append(" *", DeclarationFragments::FragmentKind::Text);
@@ -375,46 +415,110 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
375415
.append(VarDecl::getStorageClassSpecifierString(SC),
376416
DeclarationFragments::FragmentKind::Keyword)
377417
.appendSpace();
378-
QualType T =
379-
Var->getTypeSourceInfo()
380-
? Var->getTypeSourceInfo()->getType()
381-
: Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());
382418

383419
// Capture potential fragments that needs to be placed after the variable name
384420
// ```
385421
// int nums[5];
386422
// char (*ptr_to_array)[6];
387423
// ```
388424
DeclarationFragments After;
389-
return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
390-
.appendSpace()
425+
FunctionTypeLoc BlockLoc;
426+
FunctionProtoTypeLoc BlockProtoLoc;
427+
findTypeLocForBlockDecl(Var->getTypeSourceInfo(), BlockLoc, BlockProtoLoc);
428+
429+
if (!BlockLoc) {
430+
QualType T = Var->getTypeSourceInfo()
431+
? Var->getTypeSourceInfo()->getType()
432+
: Var->getASTContext().getUnqualifiedObjCPointerType(
433+
Var->getType());
434+
435+
Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
436+
.appendSpace();
437+
} else {
438+
Fragments.append(getFragmentsForBlock(Var, BlockLoc, BlockProtoLoc, After));
439+
}
440+
441+
return Fragments
391442
.append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
392-
.append(std::move(After));
443+
.append(std::move(After))
444+
.append(";", DeclarationFragments::FragmentKind::Text);
393445
}
394446

395447
DeclarationFragments
396448
DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
397449
DeclarationFragments Fragments, After;
398450

399-
QualType T = Param->getTypeSourceInfo()
400-
? Param->getTypeSourceInfo()->getType()
401-
: Param->getASTContext().getUnqualifiedObjCPointerType(
402-
Param->getType());
451+
auto *TSInfo = Param->getTypeSourceInfo();
403452

404-
DeclarationFragments TypeFragments =
405-
getFragmentsForType(T, Param->getASTContext(), After);
453+
QualType T = TSInfo ? TSInfo->getType()
454+
: Param->getASTContext().getUnqualifiedObjCPointerType(
455+
Param->getType());
406456

407-
if (Param->isObjCMethodParameter())
457+
FunctionTypeLoc BlockLoc;
458+
FunctionProtoTypeLoc BlockProtoLoc;
459+
findTypeLocForBlockDecl(TSInfo, BlockLoc, BlockProtoLoc);
460+
461+
DeclarationFragments TypeFragments;
462+
if (BlockLoc)
463+
TypeFragments.append(
464+
getFragmentsForBlock(Param, BlockLoc, BlockProtoLoc, After));
465+
else
466+
TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After));
467+
468+
if (Param->isObjCMethodParameter()) {
408469
Fragments.append("(", DeclarationFragments::FragmentKind::Text)
409470
.append(std::move(TypeFragments))
410-
.append(") ", DeclarationFragments::FragmentKind::Text);
411-
else
412-
Fragments.append(std::move(TypeFragments)).appendSpace();
471+
.append(std::move(After))
472+
.append(") ", DeclarationFragments::FragmentKind::Text)
473+
.append(Param->getName(),
474+
DeclarationFragments::FragmentKind::InternalParam);
475+
} else {
476+
Fragments.append(std::move(TypeFragments));
477+
if (!T->isBlockPointerType())
478+
Fragments.appendSpace();
479+
Fragments
480+
.append(Param->getName(),
481+
DeclarationFragments::FragmentKind::InternalParam)
482+
.append(std::move(After));
483+
}
484+
return Fragments;
485+
}
413486

414-
return Fragments
415-
.append(Param->getName(),
416-
DeclarationFragments::FragmentKind::InternalParam)
417-
.append(std::move(After));
487+
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
488+
const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
489+
FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After) {
490+
DeclarationFragments Fragments;
491+
492+
DeclarationFragments RetTyAfter;
493+
auto ReturnValueFragment = getFragmentsForType(
494+
Block.getTypePtr()->getReturnType(), BlockDecl->getASTContext(), After);
495+
496+
Fragments.append(std::move(ReturnValueFragment))
497+
.append(std::move(RetTyAfter))
498+
.appendSpace()
499+
.append("(^", DeclarationFragments::FragmentKind::Text);
500+
501+
After.append(")", DeclarationFragments::FragmentKind::Text);
502+
unsigned NumParams = Block.getNumParams();
503+
504+
if (!BlockProto || NumParams == 0) {
505+
if (BlockProto && BlockProto.getTypePtr()->isVariadic())
506+
After.append("(...)", DeclarationFragments::FragmentKind::Text);
507+
else
508+
After.append("()", DeclarationFragments::FragmentKind::Text);
509+
} else {
510+
After.append("(", DeclarationFragments::FragmentKind::Text);
511+
for (unsigned I = 0; I != NumParams; ++I) {
512+
if (I)
513+
After.append(", ", DeclarationFragments::FragmentKind::Text);
514+
After.append(getFragmentsForParam(Block.getParam(I)));
515+
if (I == NumParams - 1 && BlockProto.getTypePtr()->isVariadic())
516+
After.append(", ...", DeclarationFragments::FragmentKind::Text);
517+
}
518+
After.append(")", DeclarationFragments::FragmentKind::Text);
519+
}
520+
521+
return Fragments;
418522
}
419523

420524
DeclarationFragments
@@ -449,11 +553,18 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
449553
.append(std::move(After));
450554

451555
Fragments.append("(", DeclarationFragments::FragmentKind::Text);
452-
for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
556+
unsigned NumParams = Func->getNumParams();
557+
for (unsigned i = 0; i != NumParams; ++i) {
453558
if (i)
454559
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
455560
Fragments.append(getFragmentsForParam(Func->getParamDecl(i)));
456561
}
562+
563+
if (Func->isVariadic()) {
564+
if (NumParams > 0)
565+
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
566+
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
567+
}
457568
Fragments.append(")", DeclarationFragments::FragmentKind::Text);
458569

459570
// FIXME: Handle exception specifiers: throw, noexcept
@@ -709,14 +820,27 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
709820
Fragments.append(")", DeclarationFragments::FragmentKind::Text);
710821
}
711822

712-
// Build the property type and name, and return the completed fragments.
713-
return Fragments.appendSpace()
714-
.append(getFragmentsForType(Property->getType(),
715-
Property->getASTContext(), After))
716-
.appendSpace()
823+
Fragments.appendSpace();
824+
825+
FunctionTypeLoc BlockLoc;
826+
FunctionProtoTypeLoc BlockProtoLoc;
827+
findTypeLocForBlockDecl(Property->getTypeSourceInfo(), BlockLoc,
828+
BlockProtoLoc);
829+
830+
auto PropType = Property->getType();
831+
if (!BlockLoc)
832+
Fragments
833+
.append(getFragmentsForType(PropType, Property->getASTContext(), After))
834+
.appendSpace();
835+
else
836+
Fragments.append(
837+
getFragmentsForBlock(Property, BlockLoc, BlockProtoLoc, After));
838+
839+
return Fragments
717840
.append(Property->getName(),
718841
DeclarationFragments::FragmentKind::Identifier)
719-
.append(std::move(After));
842+
.append(std::move(After))
843+
.append(";", DeclarationFragments::FragmentKind::Text);
720844
}
721845

722846
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(

clang/test/ExtractAPI/global_record.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ char unavailable __attribute__((unavailable));
6868
{
6969
"kind": "identifier",
7070
"spelling": "num"
71+
},
72+
{
73+
"kind": "text",
74+
"spelling": ";"
7175
}
7276
],
7377
"identifier": {

clang/test/ExtractAPI/global_record_multifile.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ char unavailable __attribute__((unavailable));
7070
{
7171
"kind": "identifier",
7272
"spelling": "num"
73+
},
74+
{
75+
"kind": "text",
76+
"spelling": ";"
7377
}
7478
],
7579
"identifier": {

clang/test/ExtractAPI/known_files_only.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ struct Foo { int a; };
6666
{
6767
"kind": "identifier",
6868
"spelling": "num"
69+
},
70+
{
71+
"kind": "text",
72+
"spelling": ";"
6973
}
7074
],
7175
"identifier": {

clang/test/ExtractAPI/language.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ char objc;
7070
{
7171
"kind": "identifier",
7272
"spelling": "c"
73+
},
74+
{
75+
"kind": "text",
76+
"spelling": ";"
7377
}
7478
],
7579
"identifier": {
@@ -150,6 +154,10 @@ char objc;
150154
{
151155
"kind": "identifier",
152156
"spelling": "objc"
157+
},
158+
{
159+
"kind": "text",
160+
"spelling": ";"
153161
}
154162
],
155163
"identifier": {

0 commit comments

Comments
 (0)