Skip to content

Commit 9ed6ab4

Browse files
[clang][ExtractAPI] Add support C unions in non C++ parsing mode
Ensure that we generate correct symbol kinds and declaration fragments for unions in C and Objective-C parsing modes. rdar://120544091
1 parent e35c912 commit 9ed6ab4

File tree

9 files changed

+378
-73
lines changed

9 files changed

+378
-73
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
AvailabilitySet Availabilities, const DocComment &Comment,
484485
DeclarationFragments Declaration,
485-
DeclarationFragments SubHeading, bool IsFromSystemHeader)
486-
: APIRecord(RK_StructField, USR, Name, Loc, std::move(Availabilities),
486+
DeclarationFragments SubHeading, RecordKind Kind,
487+
bool IsFromSystemHeader)
488+
: APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
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
AvailabilitySet Availabilities, const DocComment &Comment,
504507
DeclarationFragments Declaration,
505-
DeclarationFragments SubHeading, bool IsFromSystemHeader)
506-
: APIRecord(RK_Struct, USR, Name, Loc, std::move(Availabilities),
508+
DeclarationFragments SubHeading, RecordKind Kind,
509+
bool IsFromSystemHeader)
510+
: APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
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:
@@ -1267,30 +1271,31 @@ class APISet {
12671271
DeclarationFragments Declaration,
12681272
DeclarationFragments SubHeading, bool IsFromSystemHeader);
12691273

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

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

12951300
StaticFieldRecord *
12961301
addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
@@ -1545,7 +1550,7 @@ class APISet {
15451550
return GlobalVariableTemplatePartialSpecializations;
15461551
}
15471552
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
1548-
const RecordMap<StructRecord> &getStructs() const { return Structs; }
1553+
const RecordMap<RecordRecord> &getRecords() const { return Records; }
15491554
const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
15501555
const RecordMap<CXXMethodTemplateRecord> &getCXXMethodTemplates() const {
15511556
return CXXMethodTemplates;
@@ -1564,7 +1569,6 @@ class APISet {
15641569
const RecordMap<CXXFieldTemplateRecord> &getCXXFieldTemplates() const {
15651570
return CXXFieldTemplates;
15661571
}
1567-
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
15681572
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
15691573
return ClassTemplates;
15701574
}
@@ -1576,7 +1580,7 @@ class APISet {
15761580
getClassTemplatePartialSpecializations() const {
15771581
return ClassTemplatePartialSpecializations;
15781582
}
1579-
const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
1583+
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
15801584
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
15811585
return ObjCCategories;
15821586
}
@@ -1642,7 +1646,7 @@ class APISet {
16421646
RecordMap<ConceptRecord> Concepts;
16431647
RecordMap<StaticFieldRecord> StaticFields;
16441648
RecordMap<EnumRecord> Enums;
1645-
RecordMap<StructRecord> Structs;
1649+
RecordMap<RecordRecord> Records;
16461650
RecordMap<CXXClassRecord> CXXClasses;
16471651
RecordMap<CXXFieldRecord> CXXFields;
16481652
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: 25 additions & 14 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"
@@ -128,9 +129,10 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
128129
void recordEnumConstants(EnumRecord *EnumRecord,
129130
const EnumDecl::enumerator_range Constants);
130131

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

136138
/// Collect API information for the Objective-C methods and associate with the
@@ -524,17 +526,25 @@ bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
524526

525527
// Build declaration fragments and sub-heading for the struct.
526528
DeclarationFragments Declaration =
527-
DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
529+
DeclarationFragmentsBuilder::getFragmentsForRecordDecl(Decl);
528530
DeclarationFragments SubHeading =
529531
DeclarationFragmentsBuilder::getSubHeading(Decl);
530532

531-
StructRecord *StructRecord =
532-
API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
533-
SubHeading, isInSystemHeader(Decl));
533+
auto RecordKind = APIRecord::RK_Struct;
534+
auto FieldRecordKind = APIRecord::RK_StructField;
535+
536+
if (Decl->isUnion()) {
537+
RecordKind = APIRecord::RK_Union;
538+
FieldRecordKind = APIRecord::RK_UnionField;
539+
}
540+
541+
RecordRecord *RecordRecord =
542+
API.addRecord(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
543+
SubHeading, RecordKind, isInSystemHeader(Decl));
534544

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

539549
return true;
540550
}
@@ -1055,8 +1065,8 @@ bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
10551065
dyn_cast<ElaboratedType>(Decl->getUnderlyingType())) {
10561066
if (const TagType *TagTy = dyn_cast<TagType>(ET->desugar())) {
10571067
if (Decl->getName() == TagTy->getDecl()->getName()) {
1058-
if (TagTy->getDecl()->isStruct()) {
1059-
modifyRecords(API.getStructs(), Decl->getName());
1068+
if (isa<RecordDecl>(TagTy->getDecl())) {
1069+
modifyRecords(API.getRecords(), Decl->getName());
10601070
}
10611071
if (TagTy->getDecl()->isEnum()) {
10621072
modifyRecords(API.getEnums(), Decl->getName());
@@ -1169,8 +1179,9 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
11691179
/// Collect API information for the struct fields and associate with the
11701180
/// parent struct.
11711181
template <typename Derived>
1172-
void ExtractAPIVisitorBase<Derived>::recordStructFields(
1173-
StructRecord *StructRecord, const RecordDecl::field_range Fields) {
1182+
void ExtractAPIVisitorBase<Derived>::recordRecordFields(
1183+
RecordRecord *RecordRecord, APIRecord::RecordKind FieldKind,
1184+
const RecordDecl::field_range Fields) {
11741185
for (const auto *Field : Fields) {
11751186
// Collect symbol information.
11761187
StringRef Name = Field->getName();
@@ -1189,8 +1200,8 @@ void ExtractAPIVisitorBase<Derived>::recordStructFields(
11891200
DeclarationFragments SubHeading =
11901201
DeclarationFragmentsBuilder::getSubHeading(Field);
11911202

1192-
API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
1193-
Comment, Declaration, SubHeading,
1203+
API.addRecordField(RecordRecord, Name, USR, Loc, AvailabilitySet(Field),
1204+
Comment, Declaration, SubHeading, FieldKind,
11941205
isInSystemHeader(Field));
11951206
}
11961207
}

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
@@ -145,31 +145,30 @@ EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
145145
SubHeading, IsFromSystemHeader);
146146
}
147147

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

164-
StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
162+
RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
165163
AvailabilitySet Availabilities,
166164
const DocComment &Comment,
167165
DeclarationFragments Declaration,
168166
DeclarationFragments SubHeading,
167+
APIRecord::RecordKind Kind,
169168
bool IsFromSystemHeader) {
170-
return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc,
169+
return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc,
171170
std::move(Availabilities), Comment, Declaration,
172-
SubHeading, IsFromSystemHeader);
171+
SubHeading, Kind, IsFromSystemHeader);
173172
}
174173

175174
StaticFieldRecord *
@@ -548,8 +547,8 @@ void GlobalFunctionRecord::anchor() {}
548547
void GlobalVariableRecord::anchor() {}
549548
void EnumConstantRecord::anchor() {}
550549
void EnumRecord::anchor() {}
551-
void StructFieldRecord::anchor() {}
552-
void StructRecord::anchor() {}
550+
void RecordFieldRecord::anchor() {}
551+
void RecordRecord::anchor() {}
553552
void CXXFieldRecord::anchor() {}
554553
void CXXClassRecord::anchor() {}
555554
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)