[clang] [clang][ExtractAPI] Add support C unions in non C++ parsing mode (PR #77451)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 9 04:09:23 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Daniel Grumberg (daniel-grumberg)
<details>
<summary>Changes</summary>
Ensure that we generate correct symbol kinds and declaration fragments for unions in C and Objective-C parsing modes.
rdar://120544091
---
Patch is 26.16 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/77451.diff
9 Files Affected:
- (modified) clang/include/clang/ExtractAPI/API.h (+25-21)
- (modified) clang/include/clang/ExtractAPI/DeclarationFragments.h (+3-2)
- (modified) clang/include/clang/ExtractAPI/ExtractAPIVisitor.h (+25-14)
- (modified) clang/include/clang/ExtractAPI/Serialization/SerializerBase.h (+6-6)
- (modified) clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h (+2-2)
- (modified) clang/lib/ExtractAPI/API.cpp (+17-18)
- (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+6-3)
- (modified) clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (+12-6)
- (added) clang/test/ExtractAPI/union.c (+281)
``````````diff
diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index b4c0e0ad39cdf2..3bd3162da89a82 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -169,6 +169,7 @@ struct APIRecord {
RK_Enum,
RK_StructField,
RK_Struct,
+ RK_UnionField,
RK_Union,
RK_StaticField,
RK_CXXField,
@@ -478,17 +479,19 @@ 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,
AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading, bool IsFromSystemHeader)
- : APIRecord(RK_StructField, USR, Name, Loc, std::move(Availabilities),
+ DeclarationFragments SubHeading, RecordKind Kind,
+ bool IsFromSystemHeader)
+ : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
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:
@@ -496,19 +499,20 @@ struct StructFieldRecord : APIRecord {
};
/// 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,
AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading, bool IsFromSystemHeader)
- : APIRecord(RK_Struct, USR, Name, Loc, std::move(Availabilities),
+ DeclarationFragments SubHeading, RecordKind Kind,
+ bool IsFromSystemHeader)
+ : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
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:
@@ -1267,17 +1271,18 @@ 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, AvailabilitySet 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.
///
@@ -1285,12 +1290,12 @@ class APISet {
/// \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,
AvailabilitySet Availability,
const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading,
- bool IsFromSystemHeader);
+ APIRecord::RecordKind Kind, bool IsFromSystemHeader);
StaticFieldRecord *
addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
@@ -1545,7 +1550,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;
@@ -1564,7 +1569,6 @@ class APISet {
const RecordMap<CXXFieldTemplateRecord> &getCXXFieldTemplates() const {
return CXXFieldTemplates;
}
- const RecordMap<ConceptRecord> &getConcepts() const { return Concepts; }
const RecordMap<ClassTemplateRecord> &getClassTemplates() const {
return ClassTemplates;
}
@@ -1576,7 +1580,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;
}
@@ -1642,7 +1646,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;
diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h
index d719196b9a43ec..1b78c8b5931e41 100644
--- a/clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -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 *);
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index a344fa7d5d8a78..abf2b7108a7eed 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -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"
@@ -128,9 +129,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
@@ -524,17 +526,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, AvailabilitySet(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, AvailabilitySet(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;
}
@@ -1055,8 +1065,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());
@@ -1169,8 +1179,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();
@@ -1189,8 +1200,8 @@ void ExtractAPIVisitorBase<Derived>::recordStructFields(
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Field);
- API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
- Comment, Declaration, SubHeading,
+ API.addRecordField(RecordRecord, Name, USR, Loc, AvailabilitySet(Field),
+ Comment, Declaration, SubHeading, FieldKind,
isInSystemHeader(Field));
}
}
diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
index a188400a74d558..f0629a9ad56b03 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -65,7 +65,7 @@ template <typename Derived> class APISetVisitor {
getDerived()->traverseGlobalFunctionTemplateSpecializationRecords();
- getDerived()->traverseStructRecords();
+ getDerived()->traverseRecordRecords();
getDerived()->traverseObjCInterfaces();
@@ -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() {
@@ -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){};
diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
index a9b714dc484659..4249ac405fd262 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -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);
diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp
index 71c655ba5b5b32..9cdadd41685aa9 100644
--- a/clang/lib/ExtractAPI/API.cpp
+++ b/clang/lib/ExtractAPI/API.cpp
@@ -145,31 +145,30 @@ EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
SubHeading, IsFromSystemHeader);
}
-StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
- StringRef USR, PresumedLoc Loc,
- AvailabilitySet Availabilities,
- 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,
+ AvailabilitySet Availabilities, const DocComment &Comment,
+ DeclarationFragments Declaration, DeclarationFragments SubHeading,
+ APIRecord::RecordKind Kind, bool IsFromSystemHeader) {
+ auto RecordField = std::make_unique<RecordFieldRecord>(
USR, Name, Loc, std::move(Availabilities), 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();
+ SubHeading, 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,
AvailabilitySet Availabilities,
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(Availabilities), Comment, Declaration,
- SubHeading, IsFromSystemHeader);
+ SubHeading, Kind, IsFromSystemHeader);
}
StaticFieldRecord *
@@ -548,8 +547,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() {}
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index eb6eea0aaf5465..044ccf5dea095b 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -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(
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index 53b22297ee0ea1..6a9e09a191965c 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -406,7 +406,7 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
Kind["identifier"] = AddLangPrefix("struct");
Kind["displayName"] = "Structure";
break;
- case APIRecord::RK_CXXField:
+ case APIRecord::RK_UnionField:
Kind["identifier"] = AddLangPrefix("property");
Kind["displayName"] = "Instance Property";
break;
@@ -414,6 +414,10 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
Kind["identifier"] = AddLangPrefix("union");
Kind["displayName"] = "Union";
break;
+ case APIRecord::RK_CXXField:
+ Kind["identifier"] = AddLangPrefix("property");
+ Kind["displayName"] = "Instance Property";
+ break;
case APIRecord::RK_StaticField:
Kind["identifier"] = AddLangPrefix("type.property");
Kind["displayName"] = "Type Property";
@@ -877,12 +881,12 @@ void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) {
serializeMembers(Record, Record.Constants);
}
-void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) {
- auto Struct = serializeAPIRecord(Record);
- if (!Struct)
+void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) {
+ auto SerializedRecord = serializeAPIRecord(Record);
+ if (!SerializedRecord)
return;
- Symbols.emplace_back(std::move(*Struct));
+ Symbols.emplace_back(std::move(*SerializedRecord));
serializeMembers(Record, Record.Fields);
}
@@ -1173,7 +1177,9 @@ void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
visitEnumRecord(*cast<EnumRecord>(Record));
break;
case APIRecord::RK_Struct:
- visitStructRecord(*cast<StructRecord>(Record));
+ LLVM_FALLTHROUGH;
+ case APIRecord::RK_Union:
+ visitRecordRecord(*cast<RecordRecord>(Record));
break;
case APIRecord::RK_StaticField:
visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
diff --git a/clang/te...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/77451
More information about the cfe-commits
mailing list