Skip to content

Commit 0f77a37

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 92a99c4 commit 0f77a37

15 files changed

+1210
-79
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>
@@ -304,6 +305,11 @@ class DeclarationFragmentsBuilder {
304305
/// Build DeclarationFragments for a parameter variable declaration
305306
/// ParmVarDecl.
306307
static DeclarationFragments getFragmentsForParam(const ParmVarDecl *);
308+
309+
static DeclarationFragments
310+
getFragmentsForBlock(const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
311+
FunctionProtoTypeLoc &BlockProto,
312+
DeclarationFragments &After);
307313
};
308314

309315
} // namespace extractapi

clang/lib/ExtractAPI/DeclarationFragments.cpp

Lines changed: 150 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,49 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "clang/ExtractAPI/DeclarationFragments.h"
15+
#include "clang/AST/Type.h"
16+
#include "clang/AST/TypeLoc.h"
1517
#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
1618
#include "clang/Index/USRGeneration.h"
1719
#include "llvm/ADT/StringSwitch.h"
1820

1921
using namespace clang::extractapi;
2022
using namespace llvm;
2123

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

162198
// Declaration fragments of a pointer type is the declaration fragments of
163199
// the pointee type followed by a `*`,
164-
if (T->isPointerType())
200+
if (T->isPointerType() && !T->isFunctionPointerType())
165201
return Fragments
166202
.append(getFragmentsForType(T->getPointeeType(), Context, After))
167203
.append(" *", DeclarationFragments::FragmentKind::Text);
@@ -371,46 +407,110 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
371407
.append(VarDecl::getStorageClassSpecifierString(SC),
372408
DeclarationFragments::FragmentKind::Keyword)
373409
.appendSpace();
374-
QualType T =
375-
Var->getTypeSourceInfo()
376-
? Var->getTypeSourceInfo()->getType()
377-
: Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());
378410

379411
// Capture potential fragments that needs to be placed after the variable name
380412
// ```
381413
// int nums[5];
382414
// char (*ptr_to_array)[6];
383415
// ```
384416
DeclarationFragments After;
385-
return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
386-
.appendSpace()
417+
FunctionTypeLoc BlockLoc;
418+
FunctionProtoTypeLoc BlockProtoLoc;
419+
findTypeLocForBlockDecl(Var->getTypeSourceInfo(), BlockLoc, BlockProtoLoc);
420+
421+
if (!BlockLoc) {
422+
QualType T = Var->getTypeSourceInfo()
423+
? Var->getTypeSourceInfo()->getType()
424+
: Var->getASTContext().getUnqualifiedObjCPointerType(
425+
Var->getType());
426+
427+
Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
428+
.appendSpace();
429+
} else {
430+
Fragments.append(getFragmentsForBlock(Var, BlockLoc, BlockProtoLoc, After));
431+
}
432+
433+
return Fragments
387434
.append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
388-
.append(std::move(After));
435+
.append(std::move(After))
436+
.append(";", DeclarationFragments::FragmentKind::Text);
389437
}
390438

391439
DeclarationFragments
392440
DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
393441
DeclarationFragments Fragments, After;
394442

395-
QualType T = Param->getTypeSourceInfo()
396-
? Param->getTypeSourceInfo()->getType()
397-
: Param->getASTContext().getUnqualifiedObjCPointerType(
398-
Param->getType());
443+
auto *TSInfo = Param->getTypeSourceInfo();
399444

400-
DeclarationFragments TypeFragments =
401-
getFragmentsForType(T, Param->getASTContext(), After);
445+
QualType T = TSInfo ? TSInfo->getType()
446+
: Param->getASTContext().getUnqualifiedObjCPointerType(
447+
Param->getType());
402448

403-
if (Param->isObjCMethodParameter())
449+
FunctionTypeLoc BlockLoc;
450+
FunctionProtoTypeLoc BlockProtoLoc;
451+
findTypeLocForBlockDecl(TSInfo, BlockLoc, BlockProtoLoc);
452+
453+
DeclarationFragments TypeFragments;
454+
if (BlockLoc)
455+
TypeFragments.append(
456+
getFragmentsForBlock(Param, BlockLoc, BlockProtoLoc, After));
457+
else
458+
TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After));
459+
460+
if (Param->isObjCMethodParameter()) {
404461
Fragments.append("(", DeclarationFragments::FragmentKind::Text)
405462
.append(std::move(TypeFragments))
406-
.append(") ", DeclarationFragments::FragmentKind::Text);
407-
else
408-
Fragments.append(std::move(TypeFragments)).appendSpace();
463+
.append(std::move(After))
464+
.append(") ", DeclarationFragments::FragmentKind::Text)
465+
.append(Param->getName(),
466+
DeclarationFragments::FragmentKind::InternalParam);
467+
} else {
468+
Fragments.append(std::move(TypeFragments));
469+
if (!T->isBlockPointerType())
470+
Fragments.appendSpace();
471+
Fragments
472+
.append(Param->getName(),
473+
DeclarationFragments::FragmentKind::InternalParam)
474+
.append(std::move(After));
475+
}
476+
return Fragments;
477+
}
409478

410-
return Fragments
411-
.append(Param->getName(),
412-
DeclarationFragments::FragmentKind::InternalParam)
413-
.append(std::move(After));
479+
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
480+
const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
481+
FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After) {
482+
DeclarationFragments Fragments;
483+
484+
DeclarationFragments RetTyAfter;
485+
auto ReturnValueFragment = getFragmentsForType(
486+
Block.getTypePtr()->getReturnType(), BlockDecl->getASTContext(), After);
487+
488+
Fragments.append(std::move(ReturnValueFragment))
489+
.append(std::move(RetTyAfter))
490+
.appendSpace()
491+
.append("(^", DeclarationFragments::FragmentKind::Text);
492+
493+
After.append(")", DeclarationFragments::FragmentKind::Text);
494+
unsigned NumParams = Block.getNumParams();
495+
496+
if (!BlockProto || NumParams == 0) {
497+
if (BlockProto && BlockProto.getTypePtr()->isVariadic())
498+
After.append("(...)", DeclarationFragments::FragmentKind::Text);
499+
else
500+
After.append("()", DeclarationFragments::FragmentKind::Text);
501+
} else {
502+
After.append("(", DeclarationFragments::FragmentKind::Text);
503+
for (unsigned I = 0; I != NumParams; ++I) {
504+
if (I)
505+
After.append(", ", DeclarationFragments::FragmentKind::Text);
506+
After.append(getFragmentsForParam(Block.getParam(I)));
507+
if (I == NumParams - 1 && BlockProto.getTypePtr()->isVariadic())
508+
After.append(", ...", DeclarationFragments::FragmentKind::Text);
509+
}
510+
After.append(")", DeclarationFragments::FragmentKind::Text);
511+
}
512+
513+
return Fragments;
414514
}
415515

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

447547
Fragments.append("(", DeclarationFragments::FragmentKind::Text);
448-
for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
548+
unsigned NumParams = Func->getNumParams();
549+
for (unsigned i = 0; i != NumParams; ++i) {
449550
if (i)
450551
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
451552
Fragments.append(getFragmentsForParam(Func->getParamDecl(i)));
452553
}
453-
Fragments.append(")", DeclarationFragments::FragmentKind::Text);
554+
555+
if (Func->isVariadic()) {
556+
if (NumParams > 0)
557+
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
558+
Fragments.append("...", DeclarationFragments::FragmentKind::Text);
559+
}
560+
Fragments.append(");", DeclarationFragments::FragmentKind::Text);
454561

455562
// FIXME: Handle exception specifiers: throw, noexcept
456563
return Fragments;
@@ -705,14 +812,27 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
705812
Fragments.append(")", DeclarationFragments::FragmentKind::Text);
706813
}
707814

708-
// Build the property type and name, and return the completed fragments.
709-
return Fragments.appendSpace()
710-
.append(getFragmentsForType(Property->getType(),
711-
Property->getASTContext(), After))
712-
.appendSpace()
815+
Fragments.appendSpace();
816+
817+
FunctionTypeLoc BlockLoc;
818+
FunctionProtoTypeLoc BlockProtoLoc;
819+
findTypeLocForBlockDecl(Property->getTypeSourceInfo(), BlockLoc,
820+
BlockProtoLoc);
821+
822+
auto PropType = Property->getType();
823+
if (!BlockLoc)
824+
Fragments
825+
.append(getFragmentsForType(PropType, Property->getASTContext(), After))
826+
.appendSpace();
827+
else
828+
Fragments.append(
829+
getFragmentsForBlock(Property, BlockLoc, BlockProtoLoc, After));
830+
831+
return Fragments
713832
.append(Property->getName(),
714833
DeclarationFragments::FragmentKind::Identifier)
715-
.append(std::move(After));
834+
.append(std::move(After))
835+
.append(";", DeclarationFragments::FragmentKind::Text);
716836
}
717837

718838
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(

clang/test/ExtractAPI/availability.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
7676
},
7777
{
7878
"kind": "text",
79-
"spelling": "()"
79+
"spelling": "();"
8080
}
8181
],
8282
"functionSignature": {
@@ -150,7 +150,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
150150
},
151151
{
152152
"kind": "text",
153-
"spelling": "()"
153+
"spelling": "();"
154154
}
155155
],
156156
"functionSignature": {
@@ -234,7 +234,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
234234
},
235235
{
236236
"kind": "text",
237-
"spelling": "()"
237+
"spelling": "();"
238238
}
239239
],
240240
"functionSignature": {
@@ -334,7 +334,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
334334
},
335335
{
336336
"kind": "text",
337-
"spelling": "()"
337+
"spelling": "();"
338338
}
339339
],
340340
"functionSignature": {
@@ -416,7 +416,7 @@ void e(void) __attribute__((availability(tvos, unavailable)));
416416
},
417417
{
418418
"kind": "text",
419-
"spelling": "()"
419+
"spelling": "();"
420420
}
421421
],
422422
"functionSignature": {

clang/test/ExtractAPI/global_record.c

Lines changed: 5 additions & 1 deletion
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": {
@@ -189,7 +193,7 @@ char unavailable __attribute__((unavailable));
189193
},
190194
{
191195
"kind": "text",
192-
"spelling": ")"
196+
"spelling": ");"
193197
}
194198
],
195199
"docComment": {

clang/test/ExtractAPI/global_record_multifile.c

Lines changed: 5 additions & 1 deletion
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": {
@@ -191,7 +195,7 @@ char unavailable __attribute__((unavailable));
191195
},
192196
{
193197
"kind": "text",
194-
"spelling": ")"
198+
"spelling": ");"
195199
}
196200
],
197201
"docComment": {

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)