forked from OSchip/llvm-project
[clang][extract-api] Add Objective-C interface support
Add support for Objective-C interface declarations in ExtractAPI. Depends on D122495 Differential Revision: https://reviews.llvm.org/D122446
This commit is contained in:
parent
686dcbe8b0
commit
9b36e126fd
clang
include/clang/ExtractAPI
lib/ExtractAPI
test/ExtractAPI
|
@ -19,6 +19,7 @@
|
|||
#define LLVM_CLANG_EXTRACTAPI_API_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/RawCommentList.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/ExtractAPI/AvailabilityInfo.h"
|
||||
|
@ -77,6 +78,10 @@ struct APIRecord {
|
|||
RK_Enum,
|
||||
RK_StructField,
|
||||
RK_Struct,
|
||||
RK_ObjCProperty,
|
||||
RK_ObjCIvar,
|
||||
RK_ObjCMethod,
|
||||
RK_ObjCInterface,
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -201,6 +206,154 @@ private:
|
|||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// This holds information associated with Objective-C properties.
|
||||
struct ObjCPropertyRecord : APIRecord {
|
||||
/// The attributes associated with an Objective-C property.
|
||||
enum AttributeKind : unsigned {
|
||||
NoAttr = 0,
|
||||
ReadOnly = 1,
|
||||
Class = 1 << 1,
|
||||
Dynamic = 1 << 2,
|
||||
};
|
||||
|
||||
AttributeKind Attributes;
|
||||
StringRef GetterName;
|
||||
StringRef SetterName;
|
||||
bool IsOptional;
|
||||
|
||||
ObjCPropertyRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, AttributeKind Attributes,
|
||||
StringRef GetterName, StringRef SetterName,
|
||||
bool IsOptional)
|
||||
: APIRecord(RK_ObjCProperty, Name, USR, Loc, Availability,
|
||||
LinkageInfo::none(), Comment, Declaration, SubHeading),
|
||||
Attributes(Attributes), GetterName(GetterName), SetterName(SetterName),
|
||||
IsOptional(IsOptional) {}
|
||||
|
||||
bool isReadOnly() const { return Attributes & ReadOnly; }
|
||||
bool isDynamic() const { return Attributes & Dynamic; }
|
||||
bool isClassProperty() const { return Attributes & Class; }
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ObjCProperty;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// This holds information associated with Objective-C instance variables.
|
||||
struct ObjCInstanceVariableRecord : APIRecord {
|
||||
using AccessControl = ObjCIvarDecl::AccessControl;
|
||||
AccessControl Access;
|
||||
|
||||
ObjCInstanceVariableRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
AccessControl Access)
|
||||
: APIRecord(RK_ObjCIvar, Name, USR, Loc, Availability,
|
||||
LinkageInfo::none(), Comment, Declaration, SubHeading),
|
||||
Access(Access) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ObjCIvar;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// This holds information associated with Objective-C methods.
|
||||
struct ObjCMethodRecord : APIRecord {
|
||||
FunctionSignature Signature;
|
||||
bool IsInstanceMethod;
|
||||
|
||||
ObjCMethodRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, FunctionSignature Signature,
|
||||
bool IsInstanceMethod)
|
||||
: APIRecord(RK_ObjCMethod, Name, USR, Loc, Availability,
|
||||
LinkageInfo::none(), Comment, Declaration, SubHeading),
|
||||
Signature(Signature), IsInstanceMethod(IsInstanceMethod) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ObjCMethod;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// This represents a reference to another symbol that might come from external
|
||||
/// sources.
|
||||
struct SymbolReference {
|
||||
StringRef Name;
|
||||
StringRef USR;
|
||||
|
||||
/// The source project/module/product of the referred symbol.
|
||||
StringRef Source;
|
||||
|
||||
SymbolReference() = default;
|
||||
SymbolReference(StringRef Name, StringRef USR = "", StringRef Source = "")
|
||||
: Name(Name), USR(USR), Source(Source) {}
|
||||
SymbolReference(const APIRecord &Record)
|
||||
: Name(Record.Name), USR(Record.USR) {}
|
||||
|
||||
/// Determine if this SymbolReference is empty.
|
||||
///
|
||||
/// \returns true if and only if all \c Name, \c USR, and \c Source is empty.
|
||||
bool empty() const { return Name.empty() && USR.empty() && Source.empty(); }
|
||||
};
|
||||
|
||||
/// The base representation of an Objective-C container record. Holds common
|
||||
/// information associated with Objective-C containers.
|
||||
struct ObjCContainerRecord : APIRecord {
|
||||
SmallVector<std::unique_ptr<ObjCMethodRecord>> Methods;
|
||||
SmallVector<std::unique_ptr<ObjCPropertyRecord>> Properties;
|
||||
SmallVector<std::unique_ptr<ObjCInstanceVariableRecord>> Ivars;
|
||||
SmallVector<SymbolReference> Protocols;
|
||||
|
||||
ObjCContainerRecord() = delete;
|
||||
|
||||
ObjCContainerRecord(RecordKind Kind, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
LinkageInfo Linkage, const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading)
|
||||
: APIRecord(Kind, Name, USR, Loc, Availability, Linkage, Comment,
|
||||
Declaration, SubHeading) {}
|
||||
|
||||
virtual ~ObjCContainerRecord() = 0;
|
||||
};
|
||||
|
||||
/// This holds information associated with Objective-C interfaces/classes.
|
||||
struct ObjCInterfaceRecord : ObjCContainerRecord {
|
||||
SymbolReference SuperClass;
|
||||
|
||||
ObjCInterfaceRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, LinkageInfo Linkage,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
SymbolReference SuperClass)
|
||||
: ObjCContainerRecord(RK_ObjCInterface, Name, USR, Loc, Availability,
|
||||
Linkage, Comment, Declaration, SubHeading),
|
||||
SuperClass(SuperClass) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_ObjCInterface;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// APISet holds the set of API records collected from given inputs.
|
||||
class APISet {
|
||||
public:
|
||||
|
@ -292,6 +445,58 @@ public:
|
|||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading);
|
||||
|
||||
/// Create and add an Objective-C interface 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.
|
||||
ObjCInterfaceRecord *
|
||||
addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, LinkageInfo Linkage,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, SymbolReference SuperClass);
|
||||
|
||||
/// Create and add an Objective-C method 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.
|
||||
ObjCMethodRecord *
|
||||
addObjCMethod(ObjCContainerRecord *Container, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, FunctionSignature Signature,
|
||||
bool IsInstanceMethod);
|
||||
|
||||
/// Create and add an Objective-C property 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.
|
||||
ObjCPropertyRecord *
|
||||
addObjCProperty(ObjCContainerRecord *Container, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
ObjCPropertyRecord::AttributeKind Attributes,
|
||||
StringRef GetterName, StringRef SetterName, bool IsOptional);
|
||||
|
||||
/// Create and add an Objective-C instance variable 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.
|
||||
ObjCInstanceVariableRecord *addObjCInstanceVariable(
|
||||
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
ObjCInstanceVariableRecord::AccessControl Access);
|
||||
|
||||
/// A map to store the set of GlobalRecord%s with the declaration name as the
|
||||
/// key.
|
||||
using GlobalRecordMap =
|
||||
|
@ -306,6 +511,11 @@ public:
|
|||
using StructRecordMap =
|
||||
llvm::MapVector<StringRef, std::unique_ptr<StructRecord>>;
|
||||
|
||||
/// A map to store the set of ObjCInterfaceRecord%s with the declaration name
|
||||
/// as the key.
|
||||
using ObjCInterfaceRecordMap =
|
||||
llvm::MapVector<StringRef, std::unique_ptr<ObjCInterfaceRecord>>;
|
||||
|
||||
/// Get the target triple for the ExtractAPI invocation.
|
||||
const llvm::Triple &getTarget() const { return Target; }
|
||||
|
||||
|
@ -315,6 +525,9 @@ public:
|
|||
const GlobalRecordMap &getGlobals() const { return Globals; }
|
||||
const EnumRecordMap &getEnums() const { return Enums; }
|
||||
const StructRecordMap &getStructs() const { return Structs; }
|
||||
const ObjCInterfaceRecordMap &getObjCInterfaces() const {
|
||||
return ObjCInterfaces;
|
||||
}
|
||||
|
||||
/// Generate and store the USR of declaration \p D.
|
||||
///
|
||||
|
@ -343,6 +556,7 @@ private:
|
|||
GlobalRecordMap Globals;
|
||||
EnumRecordMap Enums;
|
||||
StructRecordMap Structs;
|
||||
ObjCInterfaceRecordMap ObjCInterfaces;
|
||||
};
|
||||
|
||||
} // namespace extractapi
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <vector>
|
||||
|
||||
|
@ -202,11 +203,34 @@ public:
|
|||
/// Build DeclarationFragments for a struct record declaration RecordDecl.
|
||||
static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an Objective-C interface declaration
|
||||
/// ObjCInterfaceDecl.
|
||||
static DeclarationFragments
|
||||
getFragmentsForObjCInterface(const ObjCInterfaceDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an Objective-C method declaration
|
||||
/// ObjCMethodDecl.
|
||||
static DeclarationFragments getFragmentsForObjCMethod(const ObjCMethodDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an Objective-C property declaration
|
||||
/// ObjCPropertyDecl.
|
||||
static DeclarationFragments
|
||||
getFragmentsForObjCProperty(const ObjCPropertyDecl *);
|
||||
|
||||
/// Build sub-heading fragments for a NamedDecl.
|
||||
static DeclarationFragments getSubHeading(const NamedDecl *);
|
||||
|
||||
/// Build FunctionSignature for a function declaration FunctionDecl.
|
||||
static FunctionSignature getFunctionSignature(const FunctionDecl *);
|
||||
/// Build sub-heading fragments for an Objective-C method.
|
||||
static DeclarationFragments getSubHeading(const ObjCMethodDecl *);
|
||||
|
||||
/// Build FunctionSignature for a function-like declaration \c FunctionT like
|
||||
/// FunctionDecl or ObjCMethodDecl.
|
||||
///
|
||||
/// The logic and implementation of building a signature for a FunctionDecl
|
||||
/// and an ObjCMethodDecl are exactly the same, but they do not share a common
|
||||
/// base. This template helps reuse the code.
|
||||
template <typename FunctionT>
|
||||
static FunctionSignature getFunctionSignature(const FunctionT *);
|
||||
|
||||
private:
|
||||
DeclarationFragmentsBuilder() = delete;
|
||||
|
|
|
@ -62,6 +62,13 @@ public:
|
|||
/// For example enum constants are members of the enum, class/instance
|
||||
/// methods are members of the class, etc.
|
||||
MemberOf,
|
||||
|
||||
/// The source symbol is inherited from the target symbol.
|
||||
InheritsFrom,
|
||||
|
||||
/// The source symbol conforms to the target symbol.
|
||||
/// For example Objective-C protocol conformances.
|
||||
ConformsTo,
|
||||
};
|
||||
|
||||
/// Get the string representation of the relationship kind.
|
||||
|
@ -101,8 +108,8 @@ private:
|
|||
///
|
||||
/// Record the relationship between the two symbols in
|
||||
/// SymbolGraphSerializer::Relationships.
|
||||
void serializeRelationship(RelationshipKind Kind, const APIRecord &Source,
|
||||
const APIRecord &Target);
|
||||
void serializeRelationship(RelationshipKind Kind, SymbolReference Source,
|
||||
SymbolReference Target);
|
||||
|
||||
/// Serialize a global record.
|
||||
void serializeGlobalRecord(const GlobalRecord &Record);
|
||||
|
@ -113,6 +120,9 @@ private:
|
|||
/// Serialize a struct record.
|
||||
void serializeStructRecord(const StructRecord &Record);
|
||||
|
||||
/// Serialize an Objective-C container record.
|
||||
void serializeObjCContainerRecord(const ObjCContainerRecord &Record);
|
||||
|
||||
public:
|
||||
SymbolGraphSerializer(const APISet &API, StringRef ProductName,
|
||||
APISerializerOption Options = {})
|
||||
|
|
|
@ -109,6 +109,58 @@ StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
|
|||
return Result.first->second.get();
|
||||
}
|
||||
|
||||
ObjCInterfaceRecord *APISet::addObjCInterface(
|
||||
StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, LinkageInfo Linkage,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, SymbolReference SuperClass) {
|
||||
auto Result = ObjCInterfaces.insert({Name, nullptr});
|
||||
if (Result.second) {
|
||||
// Create the record if it does not already exist.
|
||||
auto Record = std::make_unique<ObjCInterfaceRecord>(
|
||||
Name, USR, Loc, Availability, Linkage, Comment, Declaration, SubHeading,
|
||||
SuperClass);
|
||||
Result.first->second = std::move(Record);
|
||||
}
|
||||
return Result.first->second.get();
|
||||
}
|
||||
|
||||
ObjCMethodRecord *APISet::addObjCMethod(
|
||||
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading, FunctionSignature Signature,
|
||||
bool IsInstanceMethod) {
|
||||
auto Record = std::make_unique<ObjCMethodRecord>(
|
||||
Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Signature,
|
||||
IsInstanceMethod);
|
||||
return Container->Methods.emplace_back(std::move(Record)).get();
|
||||
}
|
||||
|
||||
ObjCPropertyRecord *APISet::addObjCProperty(
|
||||
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
|
||||
StringRef SetterName, bool IsOptional) {
|
||||
auto Record = std::make_unique<ObjCPropertyRecord>(
|
||||
Name, USR, Loc, Availability, Comment, Declaration, SubHeading,
|
||||
Attributes, GetterName, SetterName, IsOptional);
|
||||
return Container->Properties.emplace_back(std::move(Record)).get();
|
||||
}
|
||||
|
||||
ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
|
||||
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
|
||||
PresumedLoc Loc, const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment, DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading,
|
||||
ObjCInstanceVariableRecord::AccessControl Access) {
|
||||
auto Record = std::make_unique<ObjCInstanceVariableRecord>(
|
||||
Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Access);
|
||||
return Container->Ivars.emplace_back(std::move(Record)).get();
|
||||
}
|
||||
|
||||
StringRef APISet::recordUSR(const Decl *D) {
|
||||
SmallString<128> USR;
|
||||
index::generateUSRForDecl(D, USR);
|
||||
|
@ -130,8 +182,14 @@ StringRef APISet::copyString(StringRef String) {
|
|||
|
||||
APIRecord::~APIRecord() {}
|
||||
|
||||
ObjCContainerRecord::~ObjCContainerRecord() {}
|
||||
|
||||
void GlobalRecord::anchor() {}
|
||||
void EnumConstantRecord::anchor() {}
|
||||
void EnumRecord::anchor() {}
|
||||
void StructFieldRecord::anchor() {}
|
||||
void StructRecord::anchor() {}
|
||||
void ObjCPropertyRecord::anchor() {}
|
||||
void ObjCInstanceVariableRecord::anchor() {}
|
||||
void ObjCMethodRecord::anchor() {}
|
||||
void ObjCInterfaceRecord::anchor() {}
|
||||
|
|
|
@ -245,6 +245,22 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
|
|||
// unqualified base type.
|
||||
QualType Base = T->getCanonicalTypeUnqualified();
|
||||
|
||||
// Render Objective-C `id`/`instancetype` as keywords.
|
||||
if (T->isObjCIdType())
|
||||
return Fragments.append(Base.getAsString(),
|
||||
DeclarationFragments::FragmentKind::Keyword);
|
||||
|
||||
// If the base type is an ObjCInterfaceType, use the underlying
|
||||
// ObjCInterfaceDecl for the true USR.
|
||||
if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) {
|
||||
const auto *Decl = ObjCIT->getDecl();
|
||||
SmallString<128> USR;
|
||||
index::generateUSRForDecl(Decl, USR);
|
||||
return Fragments.append(Decl->getName(),
|
||||
DeclarationFragments::FragmentKind::TypeIdentifier,
|
||||
USR);
|
||||
}
|
||||
|
||||
// Default fragment builder for other kinds of types (BuiltinType etc.)
|
||||
SmallString<128> USR;
|
||||
clang::index::generateUSRForType(Base, Context, USR);
|
||||
|
@ -454,27 +470,183 @@ DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
|
|||
return Fragments;
|
||||
}
|
||||
|
||||
FunctionSignature
|
||||
DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *Func) {
|
||||
FunctionSignature Signature;
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface(
|
||||
const ObjCInterfaceDecl *Interface) {
|
||||
DeclarationFragments Fragments;
|
||||
// Build the base of the Objective-C interface declaration.
|
||||
Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
|
||||
.appendSpace()
|
||||
.append(Interface->getName(),
|
||||
DeclarationFragments::FragmentKind::Identifier);
|
||||
|
||||
for (const auto *Param : Func->parameters()) {
|
||||
StringRef Name = Param->getName();
|
||||
DeclarationFragments Fragments = getFragmentsForParam(Param);
|
||||
|
||||
Signature.addParameter(Name, Fragments);
|
||||
// Build the inheritance part of the declaration.
|
||||
if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) {
|
||||
SmallString<128> SuperUSR;
|
||||
index::generateUSRForDecl(SuperClass, SuperUSR);
|
||||
Fragments.append(" : ", DeclarationFragments::FragmentKind::Text)
|
||||
.append(SuperClass->getName(),
|
||||
DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR);
|
||||
}
|
||||
|
||||
DeclarationFragments After;
|
||||
DeclarationFragments Returns =
|
||||
getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After)
|
||||
.append(std::move(After));
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
Signature.setReturnType(Returns);
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod(
|
||||
const ObjCMethodDecl *Method) {
|
||||
DeclarationFragments Fragments, After;
|
||||
// Build the instance/class method indicator.
|
||||
if (Method->isClassMethod())
|
||||
Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
|
||||
else if (Method->isInstanceMethod())
|
||||
Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
|
||||
|
||||
// Build the return type.
|
||||
Fragments.append("(", DeclarationFragments::FragmentKind::Text)
|
||||
.append(getFragmentsForType(Method->getReturnType(),
|
||||
Method->getASTContext(), After))
|
||||
.append(std::move(After))
|
||||
.append(")", DeclarationFragments::FragmentKind::Text);
|
||||
|
||||
// Build the selector part.
|
||||
Selector Selector = Method->getSelector();
|
||||
if (Selector.getNumArgs() == 0)
|
||||
// For Objective-C methods that don't take arguments, the first (and only)
|
||||
// slot of the selector is the method name.
|
||||
Fragments.appendSpace().append(
|
||||
Selector.getNameForSlot(0),
|
||||
DeclarationFragments::FragmentKind::Identifier);
|
||||
|
||||
// For Objective-C methods that take arguments, build the selector slots.
|
||||
for (unsigned i = 0, end = Method->param_size(); i != end; ++i) {
|
||||
Fragments.appendSpace()
|
||||
.append(Selector.getNameForSlot(i),
|
||||
// The first slot is the name of the method, record as an
|
||||
// identifier, otherwise as exteranl parameters.
|
||||
i == 0 ? DeclarationFragments::FragmentKind::Identifier
|
||||
: DeclarationFragments::FragmentKind::ExternalParam)
|
||||
.append(":", DeclarationFragments::FragmentKind::Text);
|
||||
|
||||
// Build the internal parameter.
|
||||
const ParmVarDecl *Param = Method->getParamDecl(i);
|
||||
Fragments.append(getFragmentsForParam(Param));
|
||||
}
|
||||
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
|
||||
const ObjCPropertyDecl *Property) {
|
||||
DeclarationFragments Fragments, After;
|
||||
|
||||
// Build the Objective-C property keyword.
|
||||
Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword);
|
||||
|
||||
const auto Attributes = Property->getPropertyAttributes();
|
||||
// Build the attributes if there is any associated with the property.
|
||||
if (Attributes != ObjCPropertyAttribute::kind_noattr) {
|
||||
// No leading comma for the first attribute.
|
||||
bool First = true;
|
||||
Fragments.append(" (", DeclarationFragments::FragmentKind::Text);
|
||||
// Helper function to render the attribute.
|
||||
auto RenderAttribute =
|
||||
[&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling,
|
||||
StringRef Arg = "",
|
||||
DeclarationFragments::FragmentKind ArgKind =
|
||||
DeclarationFragments::FragmentKind::Identifier) {
|
||||
// Check if the `Kind` attribute is set for this property.
|
||||
if ((Attributes & Kind) && !Spelling.empty()) {
|
||||
// Add a leading comma if this is not the first attribute rendered.
|
||||
if (!First)
|
||||
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
|
||||
// Render the spelling of this attribute `Kind` as a keyword.
|
||||
Fragments.append(Spelling,
|
||||
DeclarationFragments::FragmentKind::Keyword);
|
||||
// If this attribute takes in arguments (e.g. `getter=getterName`),
|
||||
// render the arguments.
|
||||
if (!Arg.empty())
|
||||
Fragments.append("=", DeclarationFragments::FragmentKind::Text)
|
||||
.append(Arg, ArgKind);
|
||||
First = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Go through all possible Objective-C property attributes and render set
|
||||
// ones.
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_class, "class");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained,
|
||||
"unsafe_unretained");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly");
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter",
|
||||
Property->getGetterName().getAsString());
|
||||
RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter",
|
||||
Property->getSetterName().getAsString());
|
||||
|
||||
// Render nullability attributes.
|
||||
if (Attributes & ObjCPropertyAttribute::kind_nullability) {
|
||||
QualType Type = Property->getType();
|
||||
if (const auto Nullability =
|
||||
AttributedType::stripOuterNullability(Type)) {
|
||||
if (!First)
|
||||
Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
|
||||
if (*Nullability == NullabilityKind::Unspecified &&
|
||||
(Attributes & ObjCPropertyAttribute::kind_null_resettable))
|
||||
Fragments.append("null_resettable",
|
||||
DeclarationFragments::FragmentKind::Keyword);
|
||||
else
|
||||
Fragments.append(
|
||||
getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true),
|
||||
DeclarationFragments::FragmentKind::Keyword);
|
||||
First = false;
|
||||
}
|
||||
}
|
||||
|
||||
Fragments.append(")", DeclarationFragments::FragmentKind::Text);
|
||||
}
|
||||
|
||||
// Build the property type and name, and return the completed fragments.
|
||||
return Fragments.appendSpace()
|
||||
.append(getFragmentsForType(Property->getType(),
|
||||
Property->getASTContext(), After))
|
||||
.append(Property->getName(),
|
||||
DeclarationFragments::FragmentKind::Identifier)
|
||||
.append(std::move(After));
|
||||
}
|
||||
|
||||
template <typename FunctionT>
|
||||
FunctionSignature
|
||||
DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
|
||||
FunctionSignature Signature;
|
||||
|
||||
DeclarationFragments ReturnType, After;
|
||||
ReturnType
|
||||
.append(getFragmentsForType(Function->getReturnType(),
|
||||
Function->getASTContext(), After))
|
||||
.append(std::move(After));
|
||||
Signature.setReturnType(ReturnType);
|
||||
|
||||
for (const auto *Param : Function->parameters())
|
||||
Signature.addParameter(Param->getName(), getFragmentsForParam(Param));
|
||||
|
||||
return Signature;
|
||||
}
|
||||
|
||||
// Instantiate template for FunctionDecl.
|
||||
template FunctionSignature
|
||||
DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *);
|
||||
|
||||
// Instantiate template for ObjCMethodDecl.
|
||||
template FunctionSignature
|
||||
DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *);
|
||||
|
||||
// Subheading of a symbol defaults to its name.
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
|
||||
|
@ -484,3 +656,17 @@ DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
|
|||
DeclarationFragments::FragmentKind::Identifier);
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
// Subheading of an Objective-C method is a `+` or `-` sign indicating whether
|
||||
// it's a class method or an instance method, followed by the selector name.
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) {
|
||||
DeclarationFragments Fragments;
|
||||
if (Method->isClassMethod())
|
||||
Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
|
||||
else if (Method->isInstanceMethod())
|
||||
Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
|
||||
|
||||
return Fragments.append(Method->getNameAsString(),
|
||||
DeclarationFragments::FragmentKind::Identifier);
|
||||
}
|
||||
|
|
|
@ -216,6 +216,50 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
|
||||
// Skip forward declaration for classes (@class)
|
||||
if (!Decl->isThisDeclarationADefinition())
|
||||
return true;
|
||||
|
||||
// Collect symbol information.
|
||||
StringRef Name = Decl->getName();
|
||||
StringRef USR = API.recordUSR(Decl);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Decl);
|
||||
LinkageInfo Linkage = Decl->getLinkageAndVisibility();
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
|
||||
// Build declaration fragments and sub-heading for the interface.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Decl);
|
||||
|
||||
// Collect super class information.
|
||||
SymbolReference SuperClass;
|
||||
if (const auto *SuperClassDecl = Decl->getSuperClass()) {
|
||||
SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
|
||||
SuperClass.USR = API.recordUSR(SuperClassDecl);
|
||||
}
|
||||
|
||||
ObjCInterfaceRecord *ObjCInterfaceRecord =
|
||||
API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
|
||||
Declaration, SubHeading, SuperClass);
|
||||
|
||||
// Record all methods (selectors). This doesn't include automatically
|
||||
// synthesized property methods.
|
||||
recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
|
||||
recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
|
||||
recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
|
||||
recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Get availability information of the declaration \p D.
|
||||
AvailabilityInfo getAvailability(const Decl *D) const {
|
||||
|
@ -302,6 +346,116 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
/// Collect API information for the Objective-C methods and associate with the
|
||||
/// parent container.
|
||||
void recordObjCMethods(ObjCContainerRecord *Container,
|
||||
const ObjCContainerDecl::method_range Methods) {
|
||||
for (const auto *Method : Methods) {
|
||||
// Don't record selectors for properties.
|
||||
if (Method->isPropertyAccessor())
|
||||
continue;
|
||||
|
||||
StringRef Name = API.copyString(Method->getSelector().getAsString());
|
||||
StringRef USR = API.recordUSR(Method);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Method->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Method);
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
|
||||
// Build declaration fragments, sub-heading, and signature for the method.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Method);
|
||||
FunctionSignature Signature =
|
||||
DeclarationFragmentsBuilder::getFunctionSignature(Method);
|
||||
|
||||
API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
|
||||
Declaration, SubHeading, Signature,
|
||||
Method->isInstanceMethod());
|
||||
}
|
||||
}
|
||||
|
||||
void recordObjCProperties(ObjCContainerRecord *Container,
|
||||
const ObjCContainerDecl::prop_range Properties) {
|
||||
for (const auto *Property : Properties) {
|
||||
StringRef Name = Property->getName();
|
||||
StringRef USR = API.recordUSR(Property);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Property->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Property);
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
|
||||
// Build declaration fragments and sub-heading for the property.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Property);
|
||||
|
||||
StringRef GetterName =
|
||||
API.copyString(Property->getGetterName().getAsString());
|
||||
StringRef SetterName =
|
||||
API.copyString(Property->getSetterName().getAsString());
|
||||
|
||||
// Get the attributes for property.
|
||||
unsigned Attributes = ObjCPropertyRecord::NoAttr;
|
||||
if (Property->getPropertyAttributes() &
|
||||
ObjCPropertyAttribute::kind_readonly)
|
||||
Attributes |= ObjCPropertyRecord::ReadOnly;
|
||||
if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
|
||||
Attributes |= ObjCPropertyRecord::Class;
|
||||
|
||||
API.addObjCProperty(
|
||||
Container, Name, USR, Loc, Availability, Comment, Declaration,
|
||||
SubHeading,
|
||||
static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
|
||||
GetterName, SetterName, Property->isOptional());
|
||||
}
|
||||
}
|
||||
|
||||
void recordObjCInstanceVariables(
|
||||
ObjCContainerRecord *Container,
|
||||
const llvm::iterator_range<
|
||||
DeclContext::specific_decl_iterator<ObjCIvarDecl>>
|
||||
Ivars) {
|
||||
for (const auto *Ivar : Ivars) {
|
||||
StringRef Name = Ivar->getName();
|
||||
StringRef USR = API.recordUSR(Ivar);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Ivar);
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
|
||||
// Build declaration fragments and sub-heading for the instance variable.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Ivar);
|
||||
|
||||
ObjCInstanceVariableRecord::AccessControl Access =
|
||||
Ivar->getCanonicalAccessControl();
|
||||
|
||||
API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
|
||||
Comment, Declaration, SubHeading, Access);
|
||||
}
|
||||
}
|
||||
|
||||
void recordObjCProtocols(ObjCContainerRecord *Container,
|
||||
ObjCInterfaceDecl::protocol_range Protocols) {
|
||||
for (const auto *Protocol : Protocols)
|
||||
Container->Protocols.emplace_back(Protocol->getName(),
|
||||
API.recordUSR(Protocol));
|
||||
}
|
||||
|
||||
ASTContext &Context;
|
||||
APISet API;
|
||||
};
|
||||
|
|
|
@ -372,6 +372,27 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
|
|||
Kind["identifier"] = AddLangPrefix("struct");
|
||||
Kind["displayName"] = "Structure";
|
||||
break;
|
||||
case APIRecord::RK_ObjCIvar:
|
||||
Kind["identifier"] = AddLangPrefix("ivar");
|
||||
Kind["displayName"] = "Instance Variable";
|
||||
break;
|
||||
case APIRecord::RK_ObjCMethod:
|
||||
if (dyn_cast<ObjCMethodRecord>(&Record)->IsInstanceMethod) {
|
||||
Kind["identifier"] = AddLangPrefix("method");
|
||||
Kind["displayName"] = "Instance Method";
|
||||
} else {
|
||||
Kind["identifier"] = AddLangPrefix("type.method");
|
||||
Kind["displayName"] = "Type Method";
|
||||
}
|
||||
break;
|
||||
case APIRecord::RK_ObjCProperty:
|
||||
Kind["identifier"] = AddLangPrefix("property");
|
||||
Kind["displayName"] = "Instance Property";
|
||||
break;
|
||||
case APIRecord::RK_ObjCInterface:
|
||||
Kind["identifier"] = AddLangPrefix("class");
|
||||
Kind["displayName"] = "Class";
|
||||
break;
|
||||
}
|
||||
|
||||
return Kind;
|
||||
|
@ -435,13 +456,17 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
|
|||
switch (Kind) {
|
||||
case RelationshipKind::MemberOf:
|
||||
return "memberOf";
|
||||
case RelationshipKind::InheritsFrom:
|
||||
return "inheritsFrom";
|
||||
case RelationshipKind::ConformsTo:
|
||||
return "conformsTo";
|
||||
}
|
||||
llvm_unreachable("Unhandled relationship kind");
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
|
||||
const APIRecord &Source,
|
||||
const APIRecord &Target) {
|
||||
SymbolReference Source,
|
||||
SymbolReference Target) {
|
||||
Object Relationship;
|
||||
Relationship["source"] = Source.USR;
|
||||
Relationship["target"] = Target.USR;
|
||||
|
@ -496,6 +521,57 @@ void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
|
|||
}
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeObjCContainerRecord(
|
||||
const ObjCContainerRecord &Record) {
|
||||
auto ObjCContainer = serializeAPIRecord(Record);
|
||||
if (!ObjCContainer)
|
||||
return;
|
||||
|
||||
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 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 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 ObjCProperty = serializeAPIRecord(*Property);
|
||||
if (!ObjCProperty)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*ObjCProperty));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Property, Record);
|
||||
}
|
||||
|
||||
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 (!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);
|
||||
}
|
||||
|
||||
Object SymbolGraphSerializer::serialize() {
|
||||
Object Root;
|
||||
serializeObject(Root, "metadata", serializeMetadata());
|
||||
|
@ -513,6 +589,10 @@ Object SymbolGraphSerializer::serialize() {
|
|||
for (const auto &Struct : API.getStructs())
|
||||
serializeStructRecord(*Struct.second);
|
||||
|
||||
// Serialize Objective-C interface records in the API set.
|
||||
for (const auto &ObjCInterface : API.getObjCInterfaces())
|
||||
serializeObjCContainerRecord(*ObjCInterface.second);
|
||||
|
||||
Root["symbols"] = std::move(Symbols);
|
||||
Root["relationhips"] = std::move(Relationships);
|
||||
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
// 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 Super <Protocol>
|
||||
@property(readonly, getter=getProperty) unsigned Property;
|
||||
+ (id)getWithProperty:(unsigned) Property;
|
||||
@end
|
||||
|
||||
@interface Derived : Super {
|
||||
char Ivar;
|
||||
}
|
||||
- (char)getIvar;
|
||||
@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"
|
||||
}
|
||||
},
|
||||
"relationhips": [
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:objc(cs)Super(cm)getWithProperty:",
|
||||
"target": "c:objc(cs)Super"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:objc(cs)Super(py)Property",
|
||||
"target": "c:objc(cs)Super"
|
||||
},
|
||||
{
|
||||
"kind": "conformsTo",
|
||||
"source": "c:objc(cs)Super",
|
||||
"target": "c:objc(pl)Protocol"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:objc(cs)Derived@Ivar",
|
||||
"target": "c:objc(cs)Derived"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:objc(cs)Derived(im)getIvar",
|
||||
"target": "c:objc(cs)Derived"
|
||||
},
|
||||
{
|
||||
"kind": "inheritsFrom",
|
||||
"source": "c:objc(cs)Derived",
|
||||
"target": "c:objc(cs)Super"
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "@interface"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Super"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Super"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "objective-c.class"
|
||||
},
|
||||
"location": {
|
||||
"character": 12,
|
||||
"line": 3,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Super"
|
||||
}
|
||||
],
|
||||
"title": "Super"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "+ ("
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "id"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "getWithProperty"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ":"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "("
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:i",
|
||||
"spelling": "unsigned int"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "internalParam",
|
||||
"spelling": "Property"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Super(cm)getWithProperty:"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Type Method",
|
||||
"identifier": "objective-c.type.method"
|
||||
},
|
||||
"location": {
|
||||
"character": 1,
|
||||
"line": 5,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "+ "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "getWithProperty:"
|
||||
}
|
||||
],
|
||||
"title": "getWithProperty:"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "@property"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " ("
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "atomic"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ", "
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "readonly"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ", "
|
||||
},
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "getter"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "="
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "getProperty"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:i",
|
||||
"spelling": "unsigned int"
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Property"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Super(py)Property"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Instance Property",
|
||||
"identifier": "objective-c.property"
|
||||
},
|
||||
"location": {
|
||||
"character": 50,
|
||||
"line": 4,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Property"
|
||||
}
|
||||
],
|
||||
"title": "Property"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "@interface"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Derived"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " : "
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:objc(cs)Super",
|
||||
"spelling": "Super"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Derived"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class",
|
||||
"identifier": "objective-c.class"
|
||||
},
|
||||
"location": {
|
||||
"character": 12,
|
||||
"line": 8,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Derived"
|
||||
}
|
||||
],
|
||||
"title": "Derived"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:C",
|
||||
"spelling": "char"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Ivar"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Derived@Ivar"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Instance Variable",
|
||||
"identifier": "objective-c.ivar"
|
||||
},
|
||||
"location": {
|
||||
"character": 8,
|
||||
"line": 9,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Ivar"
|
||||
}
|
||||
],
|
||||
"title": "Ivar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "- ("
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:C",
|
||||
"spelling": "char"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ")"
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "getIvar"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cs)Derived(im)getIvar"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Instance Method",
|
||||
"identifier": "objective-c.method"
|
||||
},
|
||||
"location": {
|
||||
"character": 1,
|
||||
"line": 11,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": "- "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "getIvar"
|
||||
}
|
||||
],
|
||||
"title": "getIvar"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue