[clang] [clang][ExtractAPI] Add support C unions in non C++ parsing mode (PR #77451)
Daniel Grumberg via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 11 05:32:45 PST 2024
https://github.com/daniel-grumberg updated https://github.com/llvm/llvm-project/pull/77451
>From 9ed6ab49d39df12b95c65d48d065e82672dba48f Mon Sep 17 00:00:00 2001
From: Daniel Grumberg <dgrumberg at apple.com>
Date: Tue, 9 Jan 2024 12:06:14 +0000
Subject: [PATCH] [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
---
clang/include/clang/ExtractAPI/API.h | 48 +--
.../clang/ExtractAPI/DeclarationFragments.h | 5 +-
.../clang/ExtractAPI/ExtractAPIVisitor.h | 39 ++-
.../ExtractAPI/Serialization/SerializerBase.h | 12 +-
.../Serialization/SymbolGraphSerializer.h | 4 +-
clang/lib/ExtractAPI/API.cpp | 35 ++-
clang/lib/ExtractAPI/DeclarationFragments.cpp | 9 +-
.../Serialization/SymbolGraphSerializer.cpp | 18 +-
clang/test/ExtractAPI/union.c | 281 ++++++++++++++++++
9 files changed, 378 insertions(+), 73 deletions(-)
create mode 100644 clang/test/ExtractAPI/union.c
diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index b4c0e0ad39cdf2..a86654dd64bec5 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,30 +1271,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, 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.
+ /// 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,
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/test/ExtractAPI/union.c b/clang/test/ExtractAPI/union.c
new file mode 100644
index 00000000000000..6ec9fd3ddf6e99
--- /dev/null
+++ b/clang/test/ExtractAPI/union.c
@@ -0,0 +1,281 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at INPUT_DIR@%{/t:regex_replacement}@g" \
+// RUN: %t/reference.output.json.in >> %t/reference.output.json
+// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx -x c-header\
+// RUN: %t/input.h -o %t/output.json -verify
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+//--- input.h
+/// My Union
+union Union{
+ /// the a option
+ int a;
+ /// the b option
+ char b;
+};
+// expected-no-diagnostics
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationships": [
+ {
+ "kind": "memberOf",
+ "source": "c:@U at Union@FI at a",
+ "target": "c:@U at Union",
+ "targetFallback": "Union"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:@U at Union@FI at b",
+ "target": "c:@U at Union",
+ "targetFallback": "Union"
+ }
+ ],
+ "symbols": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "union"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Union"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 12,
+ "line": 0
+ },
+ "start": {
+ "character": 4,
+ "line": 0
+ }
+ },
+ "text": "My Union"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@U at Union"
+ },
+ "kind": {
+ "displayName": "Union",
+ "identifier": "c.union"
+ },
+ "location": {
+ "position": {
+ "character": 6,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Union"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Union"
+ }
+ ],
+ "title": "Union"
+ },
+ "pathComponents": [
+ "Union"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "a"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 20,
+ "line": 2
+ },
+ "start": {
+ "character": 8,
+ "line": 2
+ }
+ },
+ "text": "the a option"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@U at Union@FI at a"
+ },
+ "kind": {
+ "displayName": "Instance Property",
+ "identifier": "c.property"
+ },
+ "location": {
+ "position": {
+ "character": 8,
+ "line": 3
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "a"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "a"
+ }
+ ],
+ "title": "a"
+ },
+ "pathComponents": [
+ "Union",
+ "a"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:C",
+ "spelling": "char"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "b"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 20,
+ "line": 4
+ },
+ "start": {
+ "character": 8,
+ "line": 4
+ }
+ },
+ "text": "the b option"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@U at Union@FI at b"
+ },
+ "kind": {
+ "displayName": "Instance Property",
+ "identifier": "c.property"
+ },
+ "location": {
+ "position": {
+ "character": 9,
+ "line": 5
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "b"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "b"
+ }
+ ],
+ "title": "b"
+ },
+ "pathComponents": [
+ "Union",
+ "b"
+ ]
+ }
+ ]
+}
More information about the cfe-commits
mailing list