forked from OSchip/llvm-project
[clang][extract-api] Add Objective-C Category support
Add (partial) support for Objective-C category records in ExtractAPI. The current ExtractAPI collects everything for an Objective-C category, but not fully serialized in the SymbolGraphSerializer. Categories extending external interfaces are disgarded during serialization, and categories extending known interfaces are merged (all members surfaced) into the interfaces. Differential Revision: https://reviews.llvm.org/D122774
This commit is contained in:
parent
6b306233f7
commit
178aad9b94
|
@ -86,6 +86,7 @@ struct APIRecord {
|
|||
RK_ObjCIvar,
|
||||
RK_ObjCMethod,
|
||||
RK_ObjCInterface,
|
||||
RK_ObjCCategory,
|
||||
RK_ObjCProtocol,
|
||||
RK_MacroDefinition,
|
||||
RK_Typedef,
|
||||
|
@ -340,9 +341,33 @@ struct ObjCContainerRecord : APIRecord {
|
|||
virtual ~ObjCContainerRecord() = 0;
|
||||
};
|
||||
|
||||
/// This holds information associated with Objective-C categories.
|
||||
struct ObjCCategoryRecord : ObjCContainerRecord {
|
||||
SymbolReference Interface;
|
||||
|
||||
ObjCCategoryRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, SymbolReference Interface)
|
||||
: ObjCContainerRecord(RK_ObjCCategory, Name, USR, Loc, Availability,
|
||||
LinkageInfo::none(), Comment, Declaration,
|
||||
SubHeading),
|
||||
Interface(Interface) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ObjCCategory;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// This holds information associated with Objective-C interfaces/classes.
|
||||
struct ObjCInterfaceRecord : ObjCContainerRecord {
|
||||
SymbolReference SuperClass;
|
||||
// ObjCCategoryRecord%s are stored in and owned by APISet.
|
||||
SmallVector<ObjCCategoryRecord *> Categories;
|
||||
|
||||
ObjCInterfaceRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, LinkageInfo Linkage,
|
||||
|
@ -512,6 +537,18 @@ public:
|
|||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading);
|
||||
|
||||
/// Create and add an Objective-C category 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.
|
||||
ObjCCategoryRecord *
|
||||
addObjCCategory(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, SymbolReference Interface);
|
||||
|
||||
/// Create and add an Objective-C interface record into the API set.
|
||||
///
|
||||
/// Note: the caller is responsible for keeping the StringRef \p Name and
|
||||
|
@ -618,6 +655,9 @@ public:
|
|||
const RecordMap<GlobalRecord> &getGlobals() const { return Globals; }
|
||||
const RecordMap<EnumRecord> &getEnums() const { return Enums; }
|
||||
const RecordMap<StructRecord> &getStructs() const { return Structs; }
|
||||
const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
|
||||
return ObjCCategories;
|
||||
}
|
||||
const RecordMap<ObjCInterfaceRecord> &getObjCInterfaces() const {
|
||||
return ObjCInterfaces;
|
||||
}
|
||||
|
@ -662,6 +702,7 @@ private:
|
|||
RecordMap<GlobalRecord> Globals;
|
||||
RecordMap<EnumRecord> Enums;
|
||||
RecordMap<StructRecord> Structs;
|
||||
RecordMap<ObjCCategoryRecord> ObjCCategories;
|
||||
RecordMap<ObjCInterfaceRecord> ObjCInterfaces;
|
||||
RecordMap<ObjCProtocolRecord> ObjCProtocols;
|
||||
RecordMap<MacroDefinitionRecord> Macros;
|
||||
|
|
|
@ -204,6 +204,11 @@ public:
|
|||
/// Build DeclarationFragments for a struct record declaration RecordDecl.
|
||||
static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an Objective-C category declaration
|
||||
/// ObjCCategoryDecl.
|
||||
static DeclarationFragments
|
||||
getFragmentsForObjCCategory(const ObjCCategoryDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an Objective-C interface declaration
|
||||
/// ObjCInterfaceDecl.
|
||||
static DeclarationFragments
|
||||
|
|
|
@ -124,6 +124,12 @@ private:
|
|||
/// containing common symbol information of \p Record.
|
||||
Optional<Object> serializeAPIRecord(const APIRecord &Record) const;
|
||||
|
||||
/// Helper method to serialize second-level member records of \p Record and
|
||||
/// the member-of relationships.
|
||||
template <typename MemberTy>
|
||||
void serializeMembers(const APIRecord &Record,
|
||||
const SmallVector<std::unique_ptr<MemberTy>> &Members);
|
||||
|
||||
/// Serialize the \p Kind relationship between \p Source and \p Target.
|
||||
///
|
||||
/// Record the relationship between the two symbols in
|
||||
|
|
|
@ -109,6 +109,24 @@ StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
|
|||
Declaration, SubHeading);
|
||||
}
|
||||
|
||||
ObjCCategoryRecord *APISet::addObjCCategory(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading,
|
||||
SymbolReference Interface) {
|
||||
// Create the category record.
|
||||
auto *Record = addTopLevelRecord(ObjCCategories, Name, USR, Loc, Availability,
|
||||
Comment, Declaration, SubHeading, Interface);
|
||||
|
||||
// If this category is extending a known interface, associate it with the
|
||||
// ObjCInterfaceRecord.
|
||||
auto It = ObjCInterfaces.find(Interface.Name);
|
||||
if (It != ObjCInterfaces.end())
|
||||
It->second->Categories.push_back(Record);
|
||||
|
||||
return Record;
|
||||
}
|
||||
|
||||
ObjCInterfaceRecord *APISet::addObjCInterface(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, LinkageInfo Linkage,
|
||||
|
@ -219,6 +237,7 @@ void StructRecord::anchor() {}
|
|||
void ObjCPropertyRecord::anchor() {}
|
||||
void ObjCInstanceVariableRecord::anchor() {}
|
||||
void ObjCMethodRecord::anchor() {}
|
||||
void ObjCCategoryRecord::anchor() {}
|
||||
void ObjCInterfaceRecord::anchor() {}
|
||||
void ObjCProtocolRecord::anchor() {}
|
||||
void MacroDefinitionRecord::anchor() {}
|
||||
|
|
|
@ -526,6 +526,25 @@ DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name,
|
|||
return Fragments;
|
||||
}
|
||||
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory(
|
||||
const ObjCCategoryDecl *Category) {
|
||||
DeclarationFragments Fragments;
|
||||
|
||||
SmallString<128> InterfaceUSR;
|
||||
index::generateUSRForDecl(Category->getClassInterface(), InterfaceUSR);
|
||||
|
||||
Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
|
||||
.appendSpace()
|
||||
.append(Category->getClassInterface()->getName(),
|
||||
DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR)
|
||||
.append(" (", DeclarationFragments::FragmentKind::Text)
|
||||
.append(Category->getName(),
|
||||
DeclarationFragments::FragmentKind::Identifier)
|
||||
.append(")", DeclarationFragments::FragmentKind::Text);
|
||||
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface(
|
||||
const ObjCInterfaceDecl *Interface) {
|
||||
DeclarationFragments Fragments;
|
||||
|
|
|
@ -338,6 +338,39 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
|
||||
// Collect symbol information.
|
||||
StringRef Name = Decl->getName();
|
||||
StringRef USR = API.recordUSR(Decl);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Decl);
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
// Build declaration fragments and sub-heading for the category.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Decl);
|
||||
|
||||
const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
|
||||
SymbolReference Interface(InterfaceDecl->getName(),
|
||||
API.recordUSR(InterfaceDecl));
|
||||
|
||||
ObjCCategoryRecord *ObjCCategoryRecord =
|
||||
API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
|
||||
SubHeading, Interface);
|
||||
|
||||
recordObjCMethods(ObjCCategoryRecord, Decl->methods());
|
||||
recordObjCProperties(ObjCCategoryRecord, Decl->properties());
|
||||
recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
|
||||
recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Get availability information of the declaration \p D.
|
||||
AvailabilityInfo getAvailability(const Decl *D) const {
|
||||
|
|
|
@ -401,6 +401,11 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
|
|||
Kind["identifier"] = AddLangPrefix("class");
|
||||
Kind["displayName"] = "Class";
|
||||
break;
|
||||
case APIRecord::RK_ObjCCategory:
|
||||
// We don't serialize out standalone Objective-C category symbols yet.
|
||||
llvm_unreachable("Serializing standalone Objective-C category symbols is "
|
||||
"not supported.");
|
||||
break;
|
||||
case APIRecord::RK_ObjCProtocol:
|
||||
Kind["identifier"] = AddLangPrefix("protocol");
|
||||
Kind["displayName"] = "Protocol";
|
||||
|
@ -476,6 +481,21 @@ SymbolGraphSerializer::serializeAPIRecord(const APIRecord &Record) const {
|
|||
return Obj;
|
||||
}
|
||||
|
||||
template <typename MemberTy>
|
||||
void SymbolGraphSerializer::serializeMembers(
|
||||
const APIRecord &Record,
|
||||
const SmallVector<std::unique_ptr<MemberTy>> &Members) {
|
||||
for (const auto &Member : Members) {
|
||||
auto MemberPathComponentGuard = makePathComponentGuard(Member->Name);
|
||||
auto MemberRecord = serializeAPIRecord(*Member);
|
||||
if (!MemberRecord)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*MemberRecord));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
|
||||
}
|
||||
}
|
||||
|
||||
StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
|
||||
switch (Kind) {
|
||||
case RelationshipKind::MemberOf:
|
||||
|
@ -520,18 +540,7 @@ void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
|
|||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Enum));
|
||||
|
||||
for (const auto &Constant : Record.Constants) {
|
||||
auto EnumConstantPathComponentGuard =
|
||||
makePathComponentGuard(Constant->Name);
|
||||
auto EnumConstant = serializeAPIRecord(*Constant);
|
||||
|
||||
if (!EnumConstant)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*EnumConstant));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Constant, Record);
|
||||
}
|
||||
serializeMembers(Record, Record.Constants);
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
|
||||
|
@ -541,17 +550,7 @@ void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
|
|||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Struct));
|
||||
|
||||
for (const auto &Field : Record.Fields) {
|
||||
auto StructFieldPathComponentGuard = makePathComponentGuard(Field->Name);
|
||||
auto StructField = serializeAPIRecord(*Field);
|
||||
|
||||
if (!StructField)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*StructField));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Field, Record);
|
||||
}
|
||||
serializeMembers(Record, Record.Fields);
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeObjCContainerRecord(
|
||||
|
@ -563,53 +562,33 @@ void SymbolGraphSerializer::serializeObjCContainerRecord(
|
|||
|
||||
Symbols.emplace_back(std::move(*ObjCContainer));
|
||||
|
||||
// Record instance variables and that the instance variables are members of
|
||||
// the container.
|
||||
for (const auto &Ivar : Record.Ivars) {
|
||||
auto IvarPathComponentGuard = makePathComponentGuard(Ivar->Name);
|
||||
auto ObjCIvar = serializeAPIRecord(*Ivar);
|
||||
|
||||
if (!ObjCIvar)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*ObjCIvar));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Ivar, Record);
|
||||
}
|
||||
|
||||
// Record methods and that the methods are members of the container.
|
||||
for (const auto &Method : Record.Methods) {
|
||||
auto MethodPathComponentGuard = makePathComponentGuard(Method->Name);
|
||||
auto ObjCMethod = serializeAPIRecord(*Method);
|
||||
|
||||
if (!ObjCMethod)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*ObjCMethod));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Method, Record);
|
||||
}
|
||||
|
||||
// Record properties and that the properties are members of the container.
|
||||
for (const auto &Property : Record.Properties) {
|
||||
auto PropertyPathComponentGuard = makePathComponentGuard(Property->Name);
|
||||
auto ObjCProperty = serializeAPIRecord(*Property);
|
||||
|
||||
if (!ObjCProperty)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*ObjCProperty));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Property, Record);
|
||||
}
|
||||
serializeMembers(Record, Record.Ivars);
|
||||
serializeMembers(Record, Record.Methods);
|
||||
serializeMembers(Record, Record.Properties);
|
||||
|
||||
for (const auto &Protocol : Record.Protocols)
|
||||
// Record that Record conforms to Protocol.
|
||||
serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
|
||||
|
||||
if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record))
|
||||
if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
|
||||
if (!ObjCInterface->SuperClass.empty())
|
||||
// If Record is an Objective-C interface record and it has a super class,
|
||||
// record that Record is inherited from SuperClass.
|
||||
serializeRelationship(RelationshipKind::InheritsFrom, Record,
|
||||
ObjCInterface->SuperClass);
|
||||
|
||||
// Members of categories extending an interface are serialized as members of
|
||||
// the interface.
|
||||
for (const auto *Category : ObjCInterface->Categories) {
|
||||
serializeMembers(Record, Category->Ivars);
|
||||
serializeMembers(Record, Category->Methods);
|
||||
serializeMembers(Record, Category->Properties);
|
||||
|
||||
// Surface the protocols of the the category to the interface.
|
||||
for (const auto &Protocol : Category->Protocols)
|
||||
serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeMacroDefinitionRecord(
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/reference.output.json.in >> \
|
||||
// RUN: %t/reference.output.json
|
||||
// RUN: %clang -extract-api -x objective-c-header -target arm64-apple-macosx \
|
||||
// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s
|
||||
|
||||
// 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
|
||||
|
||||
// CHECK-NOT: error:
|
||||
// CHECK-NOT: warning:
|
||||
|
||||
//--- input.h
|
||||
@protocol Protocol;
|
||||
|
||||
@interface Interface
|
||||
@end
|
||||
|
||||
@interface Interface (Category) <Protocol>
|
||||
@property int Property;
|
||||
- (void)InstanceMethod;
|
||||
+ (void)ClassMethod;
|
||||
@end
|
||||
|
||||
//--- 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:objc(cs)Interface(im)InstanceMethod",
|
||||
"target": "c:objc(cs)Interface"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:objc(cs)Interface(cm)ClassMethod",
|
||||
"target": "c:objc(cs)Interface"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:objc(cs)Interface(py)Property",
|
||||
"target": "c:objc(cs)Interface"
|
||||
},
|
||||
{
|
||||
"kind": "conformsTo",
|
||||
"source": "c:objc(cs)Interface",
|
||||
"target": "c:objc(pl)Protocol"
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
{
|
||||
"accessLevel": "public",
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "@interface"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Interface"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Interface"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "objective-c.class"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 12,
|
||||
"line": 3
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Interface"
|
||||
}
|
||||
],
|
||||
"title": "Interface"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"accessLevel": "public",
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "- ("
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:v",
|
||||
"spelling": "void"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "InstanceMethod"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Interface(im)InstanceMethod"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Instance Method",
|
||||
"identifier": "objective-c.method"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 1,
|
||||
"line": 8
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "- "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "InstanceMethod"
|
||||
}
|
||||
],
|
||||
"title": "InstanceMethod"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Interface",
|
||||
"InstanceMethod"
|
||||
]
|
||||
},
|
||||
{
|
||||
"accessLevel": "public",
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "+ ("
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:v",
|
||||
"spelling": "void"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "ClassMethod"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Interface(cm)ClassMethod"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Type Method",
|
||||
"identifier": "objective-c.type.method"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 1,
|
||||
"line": 9
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "+ "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "ClassMethod"
|
||||
}
|
||||
],
|
||||
"title": "ClassMethod"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Interface",
|
||||
"ClassMethod"
|
||||
]
|
||||
},
|
||||
{
|
||||
"accessLevel": "public",
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "@property"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " ("
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "atomic"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ", "
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "assign"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ", "
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "unsafe_unretained"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ", "
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "readwrite"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:I",
|
||||
"spelling": "int"
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Property"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Interface(py)Property"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Instance Property",
|
||||
"identifier": "objective-c.property"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 15,
|
||||
"line": 7
|
||||
},
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Property"
|
||||
}
|
||||
],
|
||||
"title": "Property"
|
||||
},
|
||||
"pathComponents": [
|
||||
"Interface",
|
||||
"Property"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue