Skip to content

Commit 16475a3

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

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,
@@ -474,37 +475,40 @@ struct EnumRecord : APIRecord {
474475
};
475476

476477
/// This holds information associated with struct fields.
477-
struct StructFieldRecord : APIRecord {
478-
StructFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
478+
struct RecordFieldRecord : APIRecord {
479+
RecordFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
479480
AvailabilityInfo Availability, const DocComment &Comment,
480481
DeclarationFragments Declaration,
481-
DeclarationFragments SubHeading, bool IsFromSystemHeader)
482-
: APIRecord(RK_StructField, USR, Name, Loc, std::move(Availability),
482+
DeclarationFragments SubHeading, RecordKind Kind,
483+
bool IsFromSystemHeader)
484+
: APIRecord(Kind, USR, Name, Loc, std::move(Availability),
483485
LinkageInfo::none(), Comment, Declaration, SubHeading,
484486
IsFromSystemHeader) {}
485487

486488
static bool classof(const APIRecord *Record) {
487-
return Record->getKind() == RK_StructField;
489+
return Record->getKind() == RK_StructField ||
490+
Record->getKind() == RK_UnionField;
488491
}
489492

490493
private:
491494
virtual void anchor();
492495
};
493496

494497
/// This holds information associated with structs.
495-
struct StructRecord : APIRecord {
496-
SmallVector<std::unique_ptr<StructFieldRecord>> Fields;
498+
struct RecordRecord : APIRecord {
499+
SmallVector<std::unique_ptr<RecordFieldRecord>> Fields;
497500

498-
StructRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
501+
RecordRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
499502
AvailabilityInfo Availability, const DocComment &Comment,
500503
DeclarationFragments Declaration,
501-
DeclarationFragments SubHeading, bool IsFromSystemHeader)
502-
: APIRecord(RK_Struct, USR, Name, Loc, std::move(Availability),
504+
DeclarationFragments SubHeading, RecordKind Kind,
505+
bool IsFromSystemHeader)
506+
: APIRecord(Kind, USR, Name, Loc, std::move(Availability),
503507
LinkageInfo::none(), Comment, Declaration, SubHeading,
504508
IsFromSystemHeader) {}
505509

506510
static bool classof(const APIRecord *Record) {
507-
return Record->getKind() == RK_Struct;
511+
return Record->getKind() == RK_Struct || Record->getKind() == RK_Union;
508512
}
509513

510514
private:
@@ -1260,30 +1264,31 @@ class APISet {
12601264
DeclarationFragments Declaration,
12611265
DeclarationFragments SubHeading, bool IsFromSystemHeader);
12621266

1263-
/// Create and add a struct field record into the API set.
1267+
/// Create and add a record field record into the API set.
12641268
///
12651269
/// Note: the caller is responsible for keeping the StringRef \p Name and
12661270
/// \p USR alive. APISet::copyString provides a way to copy strings into
12671271
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
12681272
/// to generate the USR for \c D and keep it alive in APISet.
1269-
StructFieldRecord *
1270-
addStructField(StructRecord *Struct, StringRef Name, StringRef USR,
1273+
RecordFieldRecord *
1274+
addRecordField(RecordRecord *Record, StringRef Name, StringRef USR,
12711275
PresumedLoc Loc, AvailabilityInfo Availability,
12721276
const DocComment &Comment, DeclarationFragments Declaration,
1273-
DeclarationFragments SubHeading, bool IsFromSystemHeader);
1277+
DeclarationFragments SubHeading, APIRecord::RecordKind Kind,
1278+
bool IsFromSystemHeader);
12741279

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

12881293
StaticFieldRecord *
12891294
addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
@@ -1538,7 +1543,7 @@ class APISet {
15381543
return GlobalVariableTemplatePartialSpecializations;
15391544
}
15401545
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
1541-
const RecordMap<StructRecord> &getStructs() const { return Structs; }
1546+
const RecordMap<RecordRecord> &getRecords() const { return Records; }
15421547
const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
15431548
const RecordMap<CXXMethodTemplateRecord> &getCXXMethodTemplates() const {
15441549
return CXXMethodTemplates;
@@ -1557,7 +1562,6 @@ class APISet {
15571562
const RecordMap<CXXFieldTemplateRecord> &getCXXFieldTemplates() const {
15581563
return CXXFieldTemplates;
15591564
}
1560-
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
15611565
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
15621566
return ClassTemplates;
15631567
}
@@ -1569,7 +1573,7 @@ class APISet {
15691573
getClassTemplatePartialSpecializations() const {
15701574
return ClassTemplatePartialSpecializations;
15711575
}
1572-
const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
1576+
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
15731577
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
15741578
return ObjCCategories;
15751579
}
@@ -1635,7 +1639,7 @@ class APISet {
16351639
RecordMap<ConceptRecord> Concepts;
16361640
RecordMap<StaticFieldRecord> StaticFields;
16371641
RecordMap<EnumRecord> Enums;
1638-
RecordMap<StructRecord> Structs;
1642+
RecordMap<RecordRecord> Records;
16391643
RecordMap<CXXClassRecord> CXXClasses;
16401644
RecordMap<CXXFieldRecord> CXXFields;
16411645
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
@@ -523,16 +525,25 @@ bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
523525

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

533544
// Now collect information about the fields in this struct.
534-
getDerivedExtractAPIVisitor().recordStructFields(StructRecord,
535-
Decl->fields());
545+
getDerivedExtractAPIVisitor().recordRecordFields(
546+
RecordRecord, FieldRecordKind, Decl->fields());
536547

537548
return true;
538549
}
@@ -1053,8 +1064,8 @@ bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
10531064
dyn_cast<ElaboratedType>(Decl->getUnderlyingType())) {
10541065
if (const TagType *TagTy = dyn_cast<TagType>(ET->desugar())) {
10551066
if (Decl->getName() == TagTy->getDecl()->getName()) {
1056-
if (TagTy->getDecl()->isStruct()) {
1057-
modifyRecords(API.getStructs(), Decl->getName());
1067+
if (isa<RecordDecl>(TagTy->getDecl())) {
1068+
modifyRecords(API.getRecords(), Decl->getName());
10581069
}
10591070
if (TagTy->getDecl()->isEnum()) {
10601071
modifyRecords(API.getEnums(), Decl->getName());
@@ -1160,8 +1171,9 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
11601171
/// Collect API information for the struct fields and associate with the
11611172
/// parent struct.
11621173
template <typename Derived>
1163-
void ExtractAPIVisitorBase<Derived>::recordStructFields(
1164-
StructRecord *StructRecord, const RecordDecl::field_range Fields) {
1174+
void ExtractAPIVisitorBase<Derived>::recordRecordFields(
1175+
RecordRecord *RecordRecord, APIRecord::RecordKind FieldKind,
1176+
const RecordDecl::field_range Fields) {
11651177
for (const auto *Field : Fields) {
11661178
// Collect symbol information.
11671179
StringRef Name = Field->getName();
@@ -1180,9 +1192,9 @@ void ExtractAPIVisitorBase<Derived>::recordStructFields(
11801192
DeclarationFragments SubHeading =
11811193
DeclarationFragmentsBuilder::getSubHeading(Field);
11821194

1183-
API.addStructField(StructRecord, Name, USR, Loc,
1184-
AvailabilityInfo::createFromDecl(Field), Comment,
1185-
Declaration, SubHeading, isInSystemHeader(Field));
1195+
API.addRecordField(
1196+
RecordRecord, Name, USR, Loc, AvailabilityInfo::createFromDecl(Field),
1197+
Comment, Declaration, SubHeading, FieldKind, isInSystemHeader(Field));
11861198
}
11871199
}
11881200

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

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

99-
void traverseStructRecords() {
100-
for (const auto &Struct : API.getStructs())
101-
getDerived()->visitStructRecord(*Struct.second);
99+
void traverseRecordRecords() {
100+
for (const auto &Record : API.getRecords())
101+
getDerived()->visitRecordRecord(*Record.second);
102102
}
103103

104104
void traverseStaticFieldRecords() {
@@ -231,8 +231,8 @@ template <typename Derived> class APISetVisitor {
231231
/// Visit an enum record.
232232
void visitEnumRecord(const EnumRecord &Record){};
233233

234-
/// Visit a struct record.
235-
void visitStructRecord(const StructRecord &Record){};
234+
/// Visit a record record.
235+
void visitRecordRecord(const RecordRecord &Record){};
236236

237237
void visitStaticFieldRecord(const StaticFieldRecord &Record){};
238238

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

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

166-
/// Visit a struct record.
167-
void visitStructRecord(const StructRecord &Record);
166+
/// Visit a record record.
167+
void visitRecordRecord(const RecordRecord &Record);
168168

169169
void visitStaticFieldRecord(const StaticFieldRecord &Record);
170170

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-
AvailabilityInfo Availability,
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+
AvailabilityInfo Availability, 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(Availability), Comment, Declaration, SubHeading,
157-
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+
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
AvailabilityInfo Availability,
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(Availability), Comment, Declaration,
172-
SubHeading, IsFromSystemHeader);
171+
SubHeading, Kind, IsFromSystemHeader);
173172
}
174173

175174
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)