https://github.com/daniel-grumberg updated https://github.com/llvm/llvm-project/pull/77451
>From 8ff189e707a909f5228bce2042812a45a98d1e6c Mon Sep 17 00:00:00 2001 From: Daniel Grumberg <dgrumb...@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 | 42 ++- .../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, 380 insertions(+), 74 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 f4a6374161685e2..0a0f1bd1e95f7fe 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, 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: @@ -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, 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: @@ -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, @@ -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; @@ -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; } @@ -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; } @@ -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; diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index d719196b9a43ecb..1b78c8b5931e410 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 1f76add1faae86a..ac6f4e313540c86 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" @@ -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 @@ -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; } @@ -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()); @@ -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(); @@ -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)); } } diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h index a188400a74d5589..f0629a9ad56b033 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 a9b714dc4846596..4249ac405fd2622 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 a7709fff85ffe00..aa7a1e9360f4746 100644 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -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 * @@ -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() {} diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index eb6eea0aaf54655..044ccf5dea095b9 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 ee424a16fc1cf5d..349b93e2a2326f7 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -400,7 +400,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; @@ -408,6 +408,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"; @@ -871,12 +875,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); } @@ -1167,7 +1171,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 000000000000000..6ec9fd3ddf6e990 --- /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@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@Union@FI@a", + "target": "c:@U@Union", + "targetFallback": "Union" + }, + { + "kind": "memberOf", + "source": "c:@U@Union@FI@b", + "target": "c:@U@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@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@Union@FI@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@Union@FI@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" + ] + } + ] +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits