Skip to content

Commit 69fedaf

Browse files
[clang][ExtractAPI] Add support C unions in non C++ parsing mode (#77451)
Ensure that we generate correct symbol kinds and declaration fragments for unions in C and Objective-C parsing modes. rdar://120544091
1 parent 726d940 commit 69fedaf

File tree

9 files changed

+380
-74
lines changed

9 files changed

+380
-74
lines changed

clang/include/clang/ExtractAPI/API.h

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ struct APIRecord {
169169
RK_Enum,
170170
RK_StructField,
171171
RK_Struct,
172+
RK_UnionField,
172173
RK_Union,
173174
RK_StaticField,
174175
RK_CXXField,
@@ -478,37 +479,40 @@ struct EnumRecord : APIRecord {
478479
};
479480

480481
/// This holds information associated with struct fields.
481-
struct StructFieldRecord : APIRecord {
482-
StructFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
482+
struct RecordFieldRecord : APIRecord {
483+
RecordFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
483484
AvailabilityInfo Availability, const DocComment &Comment,
484485
DeclarationFragments Declaration,
485-
DeclarationFragments SubHeading, bool IsFromSystemHeader)
486-
: APIRecord(RK_StructField, USR, Name, Loc, std::move(Availability),
486+
DeclarationFragments SubHeading, RecordKind Kind,
487+
bool IsFromSystemHeader)
488+
: APIRecord(Kind, USR, Name, Loc, std::move(Availability),
487489
LinkageInfo::none(), Comment, Declaration, SubHeading,
488490
IsFromSystemHeader) {}
489491

490492
static bool classof(const APIRecord *Record) {
491-
return Record->getKind() == RK_StructField;
493+
return Record->getKind() == RK_StructField ||
494+
Record->getKind() == RK_UnionField;
492495
}
493496

494497
private:
495498
virtual void anchor();
496499
};
497500

498501
/// This holds information associated with structs.
499-
struct StructRecord : APIRecord {
500-
SmallVector<std::unique_ptr<StructFieldRecord>> Fields;
502+
struct RecordRecord : APIRecord {
503+
SmallVector<std::unique_ptr<RecordFieldRecord>> Fields;
501504

502-
StructRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
505+
RecordRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
503506
AvailabilityInfo Availability, const DocComment &Comment,
504507
DeclarationFragments Declaration,
505-
DeclarationFragments SubHeading, bool IsFromSystemHeader)
506-
: APIRecord(RK_Struct, USR, Name, Loc, std::move(Availability),
508+
DeclarationFragments SubHeading, RecordKind Kind,
509+
bool IsFromSystemHeader)
510+
: APIRecord(Kind, USR, Name, Loc, std::move(Availability),
507511
LinkageInfo::none(), Comment, Declaration, SubHeading,
508512
IsFromSystemHeader) {}
509513

510514
static bool classof(const APIRecord *Record) {
511-
return Record->getKind() == RK_Struct;
515+
return Record->getKind() == RK_Struct || Record->getKind() == RK_Union;
512516
}
513517

514518
private:
@@ -1266,30 +1270,31 @@ class APISet {
12661270
DeclarationFragments Declaration,
12671271
DeclarationFragments SubHeading, bool IsFromSystemHeader);
12681272

1269-
/// Create and add a struct field record into the API set.
1273+
/// Create and add a record field record into the API set.
12701274
///
12711275
/// Note: the caller is responsible for keeping the StringRef \p Name and
12721276
/// \p USR alive. APISet::copyString provides a way to copy strings into
12731277
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
12741278
/// to generate the USR for \c D and keep it alive in APISet.
1275-
StructFieldRecord *
1276-
addStructField(StructRecord *Struct, StringRef Name, StringRef USR,
1279+
RecordFieldRecord *
1280+
addRecordField(RecordRecord *Record, StringRef Name, StringRef USR,
12771281
PresumedLoc Loc, AvailabilityInfo Availability,
12781282
const DocComment &Comment, DeclarationFragments Declaration,
1279-
DeclarationFragments SubHeading, bool IsFromSystemHeader);
1283+
DeclarationFragments SubHeading, APIRecord::RecordKind Kind,
1284+
bool IsFromSystemHeader);
12801285

1281-
/// Create and add a struct record into the API set.
1286+
/// Create and add a record record into the API set.
12821287
///
12831288
/// Note: the caller is responsible for keeping the StringRef \p Name and
12841289
/// \p USR alive. APISet::copyString provides a way to copy strings into
12851290
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
12861291
/// to generate the USR for \c D and keep it alive in APISet.
1287-
StructRecord *addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
1292+
RecordRecord *addRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
12881293
AvailabilityInfo Availability,
12891294
const DocComment &Comment,
12901295
DeclarationFragments Declaration,
12911296
DeclarationFragments SubHeading,
1292-
bool IsFromSystemHeader);
1297+
APIRecord::RecordKind Kind, bool IsFromSystemHeader);
12931298

12941299
StaticFieldRecord *
12951300
addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
@@ -1544,7 +1549,7 @@ class APISet {
15441549
return GlobalVariableTemplatePartialSpecializations;
15451550
}
15461551
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
1547-
const RecordMap<StructRecord> &getStructs() const { return Structs; }
1552+
const RecordMap<RecordRecord> &getRecords() const { return Records; }
15481553
const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
15491554
const RecordMap<CXXMethodTemplateRecord> &getCXXMethodTemplates() const {
15501555
return CXXMethodTemplates;
@@ -1563,7 +1568,6 @@ class APISet {
15631568
const RecordMap<CXXFieldTemplateRecord> &getCXXFieldTemplates() const {
15641569
return CXXFieldTemplates;
15651570
}
1566-
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
15671571
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
15681572
return ClassTemplates;
15691573
}
@@ -1575,7 +1579,7 @@ class APISet {
15751579
getClassTemplatePartialSpecializations() const {
15761580
return ClassTemplatePartialSpecializations;
15771581
}
1578-
const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
1582+
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
15791583
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
15801584
return ObjCCategories;
15811585
}
@@ -1641,7 +1645,7 @@ class APISet {
16411645
RecordMap<ConceptRecord> Concepts;
16421646
RecordMap<StaticFieldRecord> StaticFields;
16431647
RecordMap<EnumRecord> Enums;
1644-
RecordMap<StructRecord> Structs;
1648+
RecordMap<RecordRecord> Records;
16451649
RecordMap<CXXClassRecord> CXXClasses;
16461650
RecordMap<CXXFieldRecord> CXXFields;
16471651
RecordMap<CXXMethodRecord> CXXMethods;

clang/include/clang/ExtractAPI/DeclarationFragments.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,9 @@ class DeclarationFragmentsBuilder {
295295
/// Build DeclarationFragments for a field declaration FieldDecl.
296296
static DeclarationFragments getFragmentsForField(const FieldDecl *);
297297

298-
/// Build DeclarationFragments for a struct record declaration RecordDecl.
299-
static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
298+
/// Build DeclarationFragments for a struct/union record declaration
299+
/// RecordDecl.
300+
static DeclarationFragments getFragmentsForRecordDecl(const RecordDecl *);
300301

301302
static DeclarationFragments getFragmentsForCXXClass(const CXXRecordDecl *);
302303

clang/include/clang/ExtractAPI/ExtractAPIVisitor.h

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
1515
#define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
1616

17+
#include "clang/AST/Decl.h"
1718
#include "clang/AST/DeclCXX.h"
1819
#include "clang/AST/DeclTemplate.h"
1920
#include "clang/Basic/OperatorKinds.h"
@@ -129,9 +130,10 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
129130
void recordEnumConstants(EnumRecord *EnumRecord,
130131
const EnumDecl::enumerator_range Constants);
131132

132-
/// Collect API information for the struct fields and associate with the
133+
/// Collect API information for the record fields and associate with the
133134
/// parent struct.
134-
void recordStructFields(StructRecord *StructRecord,
135+
void recordRecordFields(RecordRecord *RecordRecord,
136+
APIRecord::RecordKind FieldKind,
135137
const RecordDecl::field_range Fields);
136138

137139
/// Collect API information for the Objective-C methods and associate with the
@@ -525,16 +527,25 @@ bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
525527

526528
// Build declaration fragments and sub-heading for the struct.
527529
DeclarationFragments Declaration =
528-
DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
530+
DeclarationFragmentsBuilder::getFragmentsForRecordDecl(Decl);
529531
DeclarationFragments SubHeading =
530532
DeclarationFragmentsBuilder::getSubHeading(Decl);
531-
StructRecord *StructRecord =
532-
API.addStruct(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl),
533-
Comment, Declaration, SubHeading, isInSystemHeader(Decl));
533+
534+
auto RecordKind = APIRecord::RK_Struct;
535+
auto FieldRecordKind = APIRecord::RK_StructField;
536+
537+
if (Decl->isUnion()) {
538+
RecordKind = APIRecord::RK_Union;
539+
FieldRecordKind = APIRecord::RK_UnionField;
540+
}
541+
542+
RecordRecord *RecordRecord = API.addRecord(
543+
Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
544+
Declaration, SubHeading, RecordKind, isInSystemHeader(Decl));
534545

535546
// Now collect information about the fields in this struct.
536-
getDerivedExtractAPIVisitor().recordStructFields(StructRecord,
537-
Decl->fields());
547+
getDerivedExtractAPIVisitor().recordRecordFields(
548+
RecordRecord, FieldRecordKind, Decl->fields());
538549

539550
return true;
540551
}
@@ -1055,8 +1066,8 @@ bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
10551066
dyn_cast<ElaboratedType>(Decl->getUnderlyingType())) {
10561067
if (const TagType *TagTy = dyn_cast<TagType>(ET->desugar())) {
10571068
if (Decl->getName() == TagTy->getDecl()->getName()) {
1058-
if (TagTy->getDecl()->isStruct()) {
1059-
modifyRecords(API.getStructs(), Decl->getName());
1069+
if (isa<RecordDecl>(TagTy->getDecl())) {
1070+
modifyRecords(API.getRecords(), Decl->getName());
10601071
}
10611072
if (TagTy->getDecl()->isEnum()) {
10621073
modifyRecords(API.getEnums(), Decl->getName());
@@ -1171,8 +1182,9 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
11711182
/// Collect API information for the struct fields and associate with the
11721183
/// parent struct.
11731184
template <typename Derived>
1174-
void ExtractAPIVisitorBase<Derived>::recordStructFields(
1175-
StructRecord *StructRecord, const RecordDecl::field_range Fields) {
1185+
void ExtractAPIVisitorBase<Derived>::recordRecordFields(
1186+
RecordRecord *RecordRecord, APIRecord::RecordKind FieldKind,
1187+
const RecordDecl::field_range Fields) {
11761188
for (const auto *Field : Fields) {
11771189
// Collect symbol information.
11781190
StringRef Name = Field->getName();
@@ -1191,9 +1203,9 @@ void ExtractAPIVisitorBase<Derived>::recordStructFields(
11911203
DeclarationFragments SubHeading =
11921204
DeclarationFragmentsBuilder::getSubHeading(Field);
11931205

1194-
API.addStructField(StructRecord, Name, USR, Loc,
1195-
AvailabilityInfo::createFromDecl(Field), Comment,
1196-
Declaration, SubHeading, isInSystemHeader(Field));
1206+
API.addRecordField(
1207+
RecordRecord, Name, USR, Loc, AvailabilityInfo::createFromDecl(Field),
1208+
Comment, Declaration, SubHeading, FieldKind, isInSystemHeader(Field));
11971209
}
11981210
}
11991211

clang/include/clang/ExtractAPI/Serialization/SerializerBase.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ template <typename Derived> class APISetVisitor {
6565

6666
getDerived()->traverseGlobalFunctionTemplateSpecializationRecords();
6767

68-
getDerived()->traverseStructRecords();
68+
getDerived()->traverseRecordRecords();
6969

7070
getDerived()->traverseObjCInterfaces();
7171

@@ -98,9 +98,9 @@ template <typename Derived> class APISetVisitor {
9898
getDerived()->visitEnumRecord(*Enum.second);
9999
}
100100

101-
void traverseStructRecords() {
102-
for (const auto &Struct : API.getStructs())
103-
getDerived()->visitStructRecord(*Struct.second);
101+
void traverseRecordRecords() {
102+
for (const auto &Record : API.getRecords())
103+
getDerived()->visitRecordRecord(*Record.second);
104104
}
105105

106106
void traverseStaticFieldRecords() {
@@ -238,8 +238,8 @@ template <typename Derived> class APISetVisitor {
238238
/// Visit an enum record.
239239
void visitEnumRecord(const EnumRecord &Record){};
240240

241-
/// Visit a struct record.
242-
void visitStructRecord(const StructRecord &Record){};
241+
/// Visit a record record.
242+
void visitRecordRecord(const RecordRecord &Record){};
243243

244244
void visitStaticFieldRecord(const StaticFieldRecord &Record){};
245245

clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
170170
/// Visit an enum record.
171171
void visitEnumRecord(const EnumRecord &Record);
172172

173-
/// Visit a struct record.
174-
void visitStructRecord(const StructRecord &Record);
173+
/// Visit a record record.
174+
void visitRecordRecord(const RecordRecord &Record);
175175

176176
void visitStaticFieldRecord(const StaticFieldRecord &Record);
177177

clang/lib/ExtractAPI/API.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -144,31 +144,30 @@ EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
144144
SubHeading, IsFromSystemHeader);
145145
}
146146

147-
StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
148-
StringRef USR, PresumedLoc Loc,
149-
AvailabilityInfo Availability,
150-
const DocComment &Comment,
151-
DeclarationFragments Declaration,
152-
DeclarationFragments SubHeading,
153-
bool IsFromSystemHeader) {
154-
auto Record = std::make_unique<StructFieldRecord>(
147+
RecordFieldRecord *APISet::addRecordField(
148+
RecordRecord *Record, StringRef Name, StringRef USR, PresumedLoc Loc,
149+
AvailabilityInfo Availability, const DocComment &Comment,
150+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
151+
APIRecord::RecordKind Kind, bool IsFromSystemHeader) {
152+
auto RecordField = std::make_unique<RecordFieldRecord>(
155153
USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading,
156-
IsFromSystemHeader);
157-
Record->ParentInformation = APIRecord::HierarchyInformation(
158-
Struct->USR, Struct->Name, Struct->getKind(), Struct);
159-
USRBasedLookupTable.insert({USR, Record.get()});
160-
return Struct->Fields.emplace_back(std::move(Record)).get();
154+
Kind, IsFromSystemHeader);
155+
RecordField->ParentInformation = APIRecord::HierarchyInformation(
156+
Record->USR, Record->Name, Record->getKind(), Record);
157+
USRBasedLookupTable.insert({USR, RecordField.get()});
158+
return Record->Fields.emplace_back(std::move(RecordField)).get();
161159
}
162160

163-
StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
161+
RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
164162
AvailabilityInfo Availability,
165163
const DocComment &Comment,
166164
DeclarationFragments Declaration,
167165
DeclarationFragments SubHeading,
166+
APIRecord::RecordKind Kind,
168167
bool IsFromSystemHeader) {
169-
return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc,
168+
return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc,
170169
std::move(Availability), Comment, Declaration,
171-
SubHeading, IsFromSystemHeader);
170+
SubHeading, Kind, IsFromSystemHeader);
172171
}
173172

174173
StaticFieldRecord *
@@ -547,8 +546,8 @@ void GlobalFunctionRecord::anchor() {}
547546
void GlobalVariableRecord::anchor() {}
548547
void EnumConstantRecord::anchor() {}
549548
void EnumRecord::anchor() {}
550-
void StructFieldRecord::anchor() {}
551-
void StructRecord::anchor() {}
549+
void RecordFieldRecord::anchor() {}
550+
void RecordRecord::anchor() {}
552551
void CXXFieldRecord::anchor() {}
553552
void CXXClassRecord::anchor() {}
554553
void CXXConstructorRecord::anchor() {}

clang/lib/ExtractAPI/DeclarationFragments.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -760,13 +760,16 @@ DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) {
760760
.append(";", DeclarationFragments::FragmentKind::Text);
761761
}
762762

763-
DeclarationFragments
764-
DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
763+
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl(
764+
const RecordDecl *Record) {
765765
if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
766766
return getFragmentsForTypedef(TypedefNameDecl);
767767

768768
DeclarationFragments Fragments;
769-
Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
769+
if (Record->isUnion())
770+
Fragments.append("union", DeclarationFragments::FragmentKind::Keyword);
771+
else
772+
Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
770773

771774
if (!Record->getName().empty())
772775
Fragments.appendSpace().append(

0 commit comments

Comments
 (0)