Skip to content

[clang][ExtractAPI] Add support C unions in non C++ parsing mode #77451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 26 additions & 22 deletions clang/include/clang/ExtractAPI/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ struct APIRecord {
RK_Enum,
RK_StructField,
RK_Struct,
RK_UnionField,
RK_Union,
RK_StaticField,
RK_CXXField,
Expand Down Expand Up @@ -478,37 +479,40 @@ struct EnumRecord : APIRecord {
};

/// This holds information associated with struct fields.
struct StructFieldRecord : APIRecord {
StructFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
struct RecordFieldRecord : APIRecord {
RecordFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilityInfo Availability, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, bool IsFromSystemHeader)
: APIRecord(RK_StructField, USR, Name, Loc, std::move(Availability),
DeclarationFragments SubHeading, RecordKind Kind,
bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Loc, std::move(Availability),
LinkageInfo::none(), Comment, Declaration, SubHeading,
IsFromSystemHeader) {}

static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_StructField;
return Record->getKind() == RK_StructField ||
Record->getKind() == RK_UnionField;
}

private:
virtual void anchor();
};

/// This holds information associated with structs.
struct StructRecord : APIRecord {
SmallVector<std::unique_ptr<StructFieldRecord>> Fields;
struct RecordRecord : APIRecord {
SmallVector<std::unique_ptr<RecordFieldRecord>> Fields;

StructRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
RecordRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilityInfo Availability, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, bool IsFromSystemHeader)
: APIRecord(RK_Struct, USR, Name, Loc, std::move(Availability),
DeclarationFragments SubHeading, RecordKind Kind,
bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Loc, std::move(Availability),
LinkageInfo::none(), Comment, Declaration, SubHeading,
IsFromSystemHeader) {}

static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_Struct;
return Record->getKind() == RK_Struct || Record->getKind() == RK_Union;
}

private:
Expand Down Expand Up @@ -1266,30 +1270,31 @@ class APISet {
DeclarationFragments Declaration,
DeclarationFragments SubHeading, bool IsFromSystemHeader);

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

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

StaticFieldRecord *
addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
Expand Down Expand Up @@ -1544,7 +1549,7 @@ class APISet {
return GlobalVariableTemplatePartialSpecializations;
}
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
const RecordMap<StructRecord> &getStructs() const { return Structs; }
const RecordMap<RecordRecord> &getRecords() const { return Records; }
const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
const RecordMap<CXXMethodTemplateRecord> &getCXXMethodTemplates() const {
return CXXMethodTemplates;
Expand All @@ -1563,7 +1568,6 @@ class APISet {
const RecordMap<CXXFieldTemplateRecord> &getCXXFieldTemplates() const {
return CXXFieldTemplates;
}
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
return ClassTemplates;
}
Expand All @@ -1575,7 +1579,7 @@ class APISet {
getClassTemplatePartialSpecializations() const {
return ClassTemplatePartialSpecializations;
}
const RecordMap<ConceptRecord> &getRecords() const { return Concepts; }
const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
return ObjCCategories;
}
Expand Down Expand Up @@ -1641,7 +1645,7 @@ class APISet {
RecordMap<ConceptRecord> Concepts;
RecordMap<StaticFieldRecord> StaticFields;
RecordMap<EnumRecord> Enums;
RecordMap<StructRecord> Structs;
RecordMap<RecordRecord> Records;
RecordMap<CXXClassRecord> CXXClasses;
RecordMap<CXXFieldRecord> CXXFields;
RecordMap<CXXMethodRecord> CXXMethods;
Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/ExtractAPI/DeclarationFragments.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,9 @@ class DeclarationFragmentsBuilder {
/// Build DeclarationFragments for a field declaration FieldDecl.
static DeclarationFragments getFragmentsForField(const FieldDecl *);

/// Build DeclarationFragments for a struct record declaration RecordDecl.
static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
/// Build DeclarationFragments for a struct/union record declaration
/// RecordDecl.
static DeclarationFragments getFragmentsForRecordDecl(const RecordDecl *);

static DeclarationFragments getFragmentsForCXXClass(const CXXRecordDecl *);

Expand Down
42 changes: 27 additions & 15 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
#define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H

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

/// Collect API information for the struct fields and associate with the
/// Collect API information for the record fields and associate with the
/// parent struct.
void recordStructFields(StructRecord *StructRecord,
void recordRecordFields(RecordRecord *RecordRecord,
APIRecord::RecordKind FieldKind,
const RecordDecl::field_range Fields);

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

// Build declaration fragments and sub-heading for the struct.
DeclarationFragments Declaration =
DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
DeclarationFragmentsBuilder::getFragmentsForRecordDecl(Decl);
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
StructRecord *StructRecord =
API.addStruct(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl),
Comment, Declaration, SubHeading, isInSystemHeader(Decl));

auto RecordKind = APIRecord::RK_Struct;
auto FieldRecordKind = APIRecord::RK_StructField;

if (Decl->isUnion()) {
RecordKind = APIRecord::RK_Union;
FieldRecordKind = APIRecord::RK_UnionField;
}

RecordRecord *RecordRecord = API.addRecord(
Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
Declaration, SubHeading, RecordKind, isInSystemHeader(Decl));

// Now collect information about the fields in this struct.
getDerivedExtractAPIVisitor().recordStructFields(StructRecord,
Decl->fields());
getDerivedExtractAPIVisitor().recordRecordFields(
RecordRecord, FieldRecordKind, Decl->fields());

return true;
}
Expand Down Expand Up @@ -1055,8 +1066,8 @@ bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
dyn_cast<ElaboratedType>(Decl->getUnderlyingType())) {
if (const TagType *TagTy = dyn_cast<TagType>(ET->desugar())) {
if (Decl->getName() == TagTy->getDecl()->getName()) {
if (TagTy->getDecl()->isStruct()) {
modifyRecords(API.getStructs(), Decl->getName());
if (isa<RecordDecl>(TagTy->getDecl())) {
modifyRecords(API.getRecords(), Decl->getName());
}
if (TagTy->getDecl()->isEnum()) {
modifyRecords(API.getEnums(), Decl->getName());
Expand Down Expand Up @@ -1171,8 +1182,9 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
/// Collect API information for the struct fields and associate with the
/// parent struct.
template <typename Derived>
void ExtractAPIVisitorBase<Derived>::recordStructFields(
StructRecord *StructRecord, const RecordDecl::field_range Fields) {
void ExtractAPIVisitorBase<Derived>::recordRecordFields(
RecordRecord *RecordRecord, APIRecord::RecordKind FieldKind,
const RecordDecl::field_range Fields) {
for (const auto *Field : Fields) {
// Collect symbol information.
StringRef Name = Field->getName();
Expand All @@ -1191,9 +1203,9 @@ void ExtractAPIVisitorBase<Derived>::recordStructFields(
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Field);

API.addStructField(StructRecord, Name, USR, Loc,
AvailabilityInfo::createFromDecl(Field), Comment,
Declaration, SubHeading, isInSystemHeader(Field));
API.addRecordField(
RecordRecord, Name, USR, Loc, AvailabilityInfo::createFromDecl(Field),
Comment, Declaration, SubHeading, FieldKind, isInSystemHeader(Field));
}
}

Expand Down
12 changes: 6 additions & 6 deletions clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ template <typename Derived> class APISetVisitor {

getDerived()->traverseGlobalFunctionTemplateSpecializationRecords();

getDerived()->traverseStructRecords();
getDerived()->traverseRecordRecords();

getDerived()->traverseObjCInterfaces();

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

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

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

/// Visit a struct record.
void visitStructRecord(const StructRecord &Record){};
/// Visit a record record.
void visitRecordRecord(const RecordRecord &Record){};

void visitStaticFieldRecord(const StaticFieldRecord &Record){};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
/// Visit an enum record.
void visitEnumRecord(const EnumRecord &Record);

/// Visit a struct record.
void visitStructRecord(const StructRecord &Record);
/// Visit a record record.
void visitRecordRecord(const RecordRecord &Record);

void visitStaticFieldRecord(const StaticFieldRecord &Record);

Expand Down
35 changes: 17 additions & 18 deletions clang/lib/ExtractAPI/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,31 +144,30 @@ EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
SubHeading, IsFromSystemHeader);
}

StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
StringRef USR, PresumedLoc Loc,
AvailabilityInfo Availability,
const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading,
bool IsFromSystemHeader) {
auto Record = std::make_unique<StructFieldRecord>(
RecordFieldRecord *APISet::addRecordField(
RecordRecord *Record, StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilityInfo Availability, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
APIRecord::RecordKind Kind, bool IsFromSystemHeader) {
auto RecordField = std::make_unique<RecordFieldRecord>(
USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading,
IsFromSystemHeader);
Record->ParentInformation = APIRecord::HierarchyInformation(
Struct->USR, Struct->Name, Struct->getKind(), Struct);
USRBasedLookupTable.insert({USR, Record.get()});
return Struct->Fields.emplace_back(std::move(Record)).get();
Kind, IsFromSystemHeader);
RecordField->ParentInformation = APIRecord::HierarchyInformation(
Record->USR, Record->Name, Record->getKind(), Record);
USRBasedLookupTable.insert({USR, RecordField.get()});
return Record->Fields.emplace_back(std::move(RecordField)).get();
}

StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilityInfo Availability,
const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading,
APIRecord::RecordKind Kind,
bool IsFromSystemHeader) {
return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc,
return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc,
std::move(Availability), Comment, Declaration,
SubHeading, IsFromSystemHeader);
SubHeading, Kind, IsFromSystemHeader);
}

StaticFieldRecord *
Expand Down Expand Up @@ -547,8 +546,8 @@ void GlobalFunctionRecord::anchor() {}
void GlobalVariableRecord::anchor() {}
void EnumConstantRecord::anchor() {}
void EnumRecord::anchor() {}
void StructFieldRecord::anchor() {}
void StructRecord::anchor() {}
void RecordFieldRecord::anchor() {}
void RecordRecord::anchor() {}
void CXXFieldRecord::anchor() {}
void CXXClassRecord::anchor() {}
void CXXConstructorRecord::anchor() {}
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/ExtractAPI/DeclarationFragments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,13 +760,16 @@ DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) {
.append(";", DeclarationFragments::FragmentKind::Text);
}

DeclarationFragments
DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl(
const RecordDecl *Record) {
if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
return getFragmentsForTypedef(TypedefNameDecl);

DeclarationFragments Fragments;
Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
if (Record->isUnion())
Fragments.append("union", DeclarationFragments::FragmentKind::Keyword);
else
Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);

if (!Record->getName().empty())
Fragments.appendSpace().append(
Expand Down
Loading