[clang][ExtractAPI] Record availability information on all platforms

Currently ExtractAPI only emits availability information for the
current platform. This makes it easy for clients to get all availability
information for a given symbol in one invocation as opposed to having to invoke
clang once per-platform and then merge the symbol-graphs.

Differential Revision: https://reviews.llvm.org/D130918
This commit is contained in:
Daniel Grumberg 2022-08-01 14:55:08 +01:00
parent 89aaae57ea
commit 57c9780d60
8 changed files with 731 additions and 241 deletions

View File

@ -58,7 +58,7 @@ struct APIRecord {
StringRef USR; StringRef USR;
StringRef Name; StringRef Name;
PresumedLoc Location; PresumedLoc Location;
AvailabilityInfo Availability; AvailabilitySet Availabilities;
LinkageInfo Linkage; LinkageInfo Linkage;
/// Documentation comment lines attached to this symbol declaration. /// Documentation comment lines attached to this symbol declaration.
@ -102,12 +102,13 @@ public:
APIRecord() = delete; APIRecord() = delete;
APIRecord(RecordKind Kind, StringRef USR, StringRef Name, APIRecord(RecordKind Kind, StringRef USR, StringRef Name,
PresumedLoc Location, const AvailabilityInfo &Availability, PresumedLoc Location, AvailabilitySet Availabilities,
LinkageInfo Linkage, const DocComment &Comment, LinkageInfo Linkage, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading) DeclarationFragments Declaration, DeclarationFragments SubHeading)
: USR(USR), Name(Name), Location(Location), Availability(Availability), : USR(USR), Name(Name), Location(Location),
Linkage(Linkage), Comment(Comment), Declaration(Declaration), Availabilities(std::move(Availabilities)), Linkage(Linkage),
SubHeading(SubHeading), Kind(Kind) {} Comment(Comment), Declaration(Declaration), SubHeading(SubHeading),
Kind(Kind) {}
// Pure virtual destructor to make APIRecord abstract // Pure virtual destructor to make APIRecord abstract
virtual ~APIRecord() = 0; virtual ~APIRecord() = 0;
@ -118,13 +119,13 @@ struct GlobalFunctionRecord : APIRecord {
FunctionSignature Signature; FunctionSignature Signature;
GlobalFunctionRecord(StringRef USR, StringRef Name, PresumedLoc Loc, GlobalFunctionRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, LinkageInfo Linkage,
LinkageInfo Linkage, const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,
FunctionSignature Signature) FunctionSignature Signature)
: APIRecord(RK_GlobalFunction, USR, Name, Loc, Availability, Linkage, : APIRecord(RK_GlobalFunction, USR, Name, Loc, std::move(Availabilities),
Comment, Declaration, SubHeading), Linkage, Comment, Declaration, SubHeading),
Signature(Signature) {} Signature(Signature) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -138,12 +139,12 @@ private:
/// This holds information associated with global functions. /// This holds information associated with global functions.
struct GlobalVariableRecord : APIRecord { struct GlobalVariableRecord : APIRecord {
GlobalVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc, GlobalVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, LinkageInfo Linkage,
LinkageInfo Linkage, const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: APIRecord(RK_GlobalVariable, USR, Name, Loc, Availability, Linkage, : APIRecord(RK_GlobalVariable, USR, Name, Loc, std::move(Availabilities),
Comment, Declaration, SubHeading) {} Linkage, Comment, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_GlobalVariable; return Record->getKind() == RK_GlobalVariable;
@ -156,11 +157,10 @@ private:
/// This holds information associated with enum constants. /// This holds information associated with enum constants.
struct EnumConstantRecord : APIRecord { struct EnumConstantRecord : APIRecord {
EnumConstantRecord(StringRef USR, StringRef Name, PresumedLoc Loc, EnumConstantRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: APIRecord(RK_EnumConstant, USR, Name, Loc, Availability, : APIRecord(RK_EnumConstant, USR, Name, Loc, std::move(Availabilities),
LinkageInfo::none(), Comment, Declaration, SubHeading) {} LinkageInfo::none(), Comment, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -176,10 +176,10 @@ struct EnumRecord : APIRecord {
SmallVector<std::unique_ptr<EnumConstantRecord>> Constants; SmallVector<std::unique_ptr<EnumConstantRecord>> Constants;
EnumRecord(StringRef USR, StringRef Name, PresumedLoc Loc, EnumRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, const DocComment &Comment, AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading) DeclarationFragments Declaration, DeclarationFragments SubHeading)
: APIRecord(RK_Enum, USR, Name, Loc, Availability, LinkageInfo::none(), : APIRecord(RK_Enum, USR, Name, Loc, std::move(Availabilities),
Comment, Declaration, SubHeading) {} LinkageInfo::none(), Comment, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_Enum; return Record->getKind() == RK_Enum;
@ -192,10 +192,10 @@ private:
/// This holds information associated with struct fields. /// This holds information associated with struct fields.
struct StructFieldRecord : APIRecord { struct StructFieldRecord : APIRecord {
StructFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, StructFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: APIRecord(RK_StructField, USR, Name, Loc, Availability, : APIRecord(RK_StructField, USR, Name, Loc, std::move(Availabilities),
LinkageInfo::none(), Comment, Declaration, SubHeading) {} LinkageInfo::none(), Comment, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -211,11 +211,11 @@ struct StructRecord : APIRecord {
SmallVector<std::unique_ptr<StructFieldRecord>> Fields; SmallVector<std::unique_ptr<StructFieldRecord>> Fields;
StructRecord(StringRef USR, StringRef Name, PresumedLoc Loc, StructRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, const DocComment &Comment, AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: APIRecord(RK_Struct, USR, Name, Loc, Availability, LinkageInfo::none(), : APIRecord(RK_Struct, USR, Name, Loc, std::move(Availabilities),
Comment, Declaration, SubHeading) {} LinkageInfo::none(), Comment, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_Struct; return Record->getKind() == RK_Struct;
@ -241,13 +241,12 @@ struct ObjCPropertyRecord : APIRecord {
bool IsOptional; bool IsOptional;
ObjCPropertyRecord(StringRef USR, StringRef Name, PresumedLoc Loc, ObjCPropertyRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, AttributeKind Attributes, DeclarationFragments SubHeading, AttributeKind Attributes,
StringRef GetterName, StringRef SetterName, StringRef GetterName, StringRef SetterName,
bool IsOptional) bool IsOptional)
: APIRecord(RK_ObjCProperty, USR, Name, Loc, Availability, : APIRecord(RK_ObjCProperty, USR, Name, Loc, std::move(Availabilities),
LinkageInfo::none(), Comment, Declaration, SubHeading), LinkageInfo::none(), Comment, Declaration, SubHeading),
Attributes(Attributes), GetterName(GetterName), SetterName(SetterName), Attributes(Attributes), GetterName(GetterName), SetterName(SetterName),
IsOptional(IsOptional) {} IsOptional(IsOptional) {}
@ -270,12 +269,12 @@ struct ObjCInstanceVariableRecord : APIRecord {
AccessControl Access; AccessControl Access;
ObjCInstanceVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc, ObjCInstanceVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,
AccessControl Access) AccessControl Access)
: APIRecord(RK_ObjCIvar, USR, Name, Loc, Availability, : APIRecord(RK_ObjCIvar, USR, Name, Loc, std::move(Availabilities),
LinkageInfo::none(), Comment, Declaration, SubHeading), LinkageInfo::none(), Comment, Declaration, SubHeading),
Access(Access) {} Access(Access) {}
@ -293,11 +292,11 @@ struct ObjCMethodRecord : APIRecord {
bool IsInstanceMethod; bool IsInstanceMethod;
ObjCMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, ObjCMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature, DeclarationFragments SubHeading, FunctionSignature Signature,
bool IsInstanceMethod) bool IsInstanceMethod)
: APIRecord(RK_ObjCMethod, USR, Name, Loc, Availability, : APIRecord(RK_ObjCMethod, USR, Name, Loc, std::move(Availabilities),
LinkageInfo::none(), Comment, Declaration, SubHeading), LinkageInfo::none(), Comment, Declaration, SubHeading),
Signature(Signature), IsInstanceMethod(IsInstanceMethod) {} Signature(Signature), IsInstanceMethod(IsInstanceMethod) {}
@ -341,12 +340,12 @@ struct ObjCContainerRecord : APIRecord {
ObjCContainerRecord() = delete; ObjCContainerRecord() = delete;
ObjCContainerRecord(RecordKind Kind, StringRef USR, StringRef Name, ObjCContainerRecord(RecordKind Kind, StringRef USR, StringRef Name,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availabilities,
LinkageInfo Linkage, const DocComment &Comment, LinkageInfo Linkage, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: APIRecord(Kind, USR, Name, Loc, Availability, Linkage, Comment, : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities), Linkage,
Declaration, SubHeading) {} Comment, Declaration, SubHeading) {}
virtual ~ObjCContainerRecord() = 0; virtual ~ObjCContainerRecord() = 0;
}; };
@ -356,13 +355,12 @@ struct ObjCCategoryRecord : ObjCContainerRecord {
SymbolReference Interface; SymbolReference Interface;
ObjCCategoryRecord(StringRef USR, StringRef Name, PresumedLoc Loc, ObjCCategoryRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, SymbolReference Interface) DeclarationFragments SubHeading, SymbolReference Interface)
: ObjCContainerRecord(RK_ObjCCategory, USR, Name, Loc, Availability, : ObjCContainerRecord(RK_ObjCCategory, USR, Name, Loc,
LinkageInfo::none(), Comment, Declaration, std::move(Availabilities), LinkageInfo::none(),
SubHeading), Comment, Declaration, SubHeading),
Interface(Interface) {} Interface(Interface) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -380,13 +378,14 @@ struct ObjCInterfaceRecord : ObjCContainerRecord {
SmallVector<ObjCCategoryRecord *> Categories; SmallVector<ObjCCategoryRecord *> Categories;
ObjCInterfaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc, ObjCInterfaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,
SymbolReference SuperClass) SymbolReference SuperClass)
: ObjCContainerRecord(RK_ObjCInterface, USR, Name, Loc, Availability, : ObjCContainerRecord(RK_ObjCInterface, USR, Name, Loc,
Linkage, Comment, Declaration, SubHeading), std::move(Availabilities), Linkage, Comment,
Declaration, SubHeading),
SuperClass(SuperClass) {} SuperClass(SuperClass) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -400,13 +399,12 @@ private:
/// This holds information associated with Objective-C protocols. /// This holds information associated with Objective-C protocols.
struct ObjCProtocolRecord : ObjCContainerRecord { struct ObjCProtocolRecord : ObjCContainerRecord {
ObjCProtocolRecord(StringRef USR, StringRef Name, PresumedLoc Loc, ObjCProtocolRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: ObjCContainerRecord(RK_ObjCProtocol, USR, Name, Loc, Availability, : ObjCContainerRecord(RK_ObjCProtocol, USR, Name, Loc,
LinkageInfo::none(), Comment, Declaration, std::move(Availabilities), LinkageInfo::none(),
SubHeading) {} Comment, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
return Record->getKind() == RK_ObjCProtocol; return Record->getKind() == RK_ObjCProtocol;
@ -421,7 +419,7 @@ struct MacroDefinitionRecord : APIRecord {
MacroDefinitionRecord(StringRef USR, StringRef Name, PresumedLoc Loc, MacroDefinitionRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) DeclarationFragments SubHeading)
: APIRecord(RK_MacroDefinition, USR, Name, Loc, AvailabilityInfo(), : APIRecord(RK_MacroDefinition, USR, Name, Loc, AvailabilitySet(),
LinkageInfo(), {}, Declaration, SubHeading) {} LinkageInfo(), {}, Declaration, SubHeading) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -441,11 +439,11 @@ struct TypedefRecord : APIRecord {
SymbolReference UnderlyingType; SymbolReference UnderlyingType;
TypedefRecord(StringRef USR, StringRef Name, PresumedLoc Loc, TypedefRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
const AvailabilityInfo &Availability, const DocComment &Comment, AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, SymbolReference UnderlyingType) DeclarationFragments SubHeading, SymbolReference UnderlyingType)
: APIRecord(RK_Typedef, USR, Name, Loc, Availability, LinkageInfo(), : APIRecord(RK_Typedef, USR, Name, Loc, std::move(Availabilities),
Comment, Declaration, SubHeading), LinkageInfo(), Comment, Declaration, SubHeading),
UnderlyingType(UnderlyingType) {} UnderlyingType(UnderlyingType) {}
static bool classof(const APIRecord *Record) { static bool classof(const APIRecord *Record) {
@ -478,7 +476,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
GlobalVariableRecord * GlobalVariableRecord *
addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration, const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading); DeclarationFragments SubHeading);
@ -490,7 +488,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
GlobalFunctionRecord * GlobalFunctionRecord *
addGlobalFunction(StringRef Name, StringRef USR, PresumedLoc Loc, addGlobalFunction(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration, const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,
FunctionSignature Signature); FunctionSignature Signature);
@ -503,7 +501,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
EnumConstantRecord *addEnumConstant(EnumRecord *Enum, StringRef Name, EnumConstantRecord *addEnumConstant(EnumRecord *Enum, StringRef Name,
StringRef USR, PresumedLoc Loc, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading); DeclarationFragments SubHeading);
@ -515,8 +513,7 @@ public:
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method /// 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. /// to generate the USR for \c D and keep it alive in APISet.
EnumRecord *addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, EnumRecord *addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability, const DocComment &Comment,
const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading); DeclarationFragments SubHeading);
@ -528,7 +525,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
StructFieldRecord *addStructField(StructRecord *Struct, StringRef Name, StructFieldRecord *addStructField(StructRecord *Struct, StringRef Name,
StringRef USR, PresumedLoc Loc, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading); DeclarationFragments SubHeading);
@ -540,7 +537,7 @@ public:
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method /// 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. /// to generate the USR for \c D and keep it alive in APISet.
StructRecord *addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, StructRecord *addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading); DeclarationFragments SubHeading);
@ -553,8 +550,8 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
ObjCCategoryRecord * ObjCCategoryRecord *
addObjCCategory(StringRef Name, StringRef USR, PresumedLoc Loc, addObjCCategory(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, SymbolReference Interface); DeclarationFragments SubHeading, SymbolReference Interface);
/// Create and add an Objective-C interface record into the API set. /// Create and add an Objective-C interface record into the API set.
@ -565,7 +562,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
ObjCInterfaceRecord * ObjCInterfaceRecord *
addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availability, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration, const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, SymbolReference SuperClass); DeclarationFragments SubHeading, SymbolReference SuperClass);
@ -577,7 +574,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
ObjCMethodRecord * ObjCMethodRecord *
addObjCMethod(ObjCContainerRecord *Container, StringRef Name, StringRef USR, addObjCMethod(ObjCContainerRecord *Container, StringRef Name, StringRef USR,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availability,
const DocComment &Comment, DeclarationFragments Declaration, const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, FunctionSignature Signature, DeclarationFragments SubHeading, FunctionSignature Signature,
bool IsInstanceMethod); bool IsInstanceMethod);
@ -590,7 +587,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
ObjCPropertyRecord * ObjCPropertyRecord *
addObjCProperty(ObjCContainerRecord *Container, StringRef Name, StringRef USR, addObjCProperty(ObjCContainerRecord *Container, StringRef Name, StringRef USR,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availability,
const DocComment &Comment, DeclarationFragments Declaration, const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,
ObjCPropertyRecord::AttributeKind Attributes, ObjCPropertyRecord::AttributeKind Attributes,
@ -604,9 +601,8 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
ObjCInstanceVariableRecord *addObjCInstanceVariable( ObjCInstanceVariableRecord *addObjCInstanceVariable(
ObjCContainerRecord *Container, StringRef Name, StringRef USR, ObjCContainerRecord *Container, StringRef Name, StringRef USR,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration, DeclarationFragments SubHeading,
DeclarationFragments SubHeading,
ObjCInstanceVariableRecord::AccessControl Access); ObjCInstanceVariableRecord::AccessControl Access);
/// Create and add an Objective-C protocol record into the API set. /// Create and add an Objective-C protocol record into the API set.
@ -617,7 +613,7 @@ public:
/// to generate the USR for \c D and keep it alive in APISet. /// to generate the USR for \c D and keep it alive in APISet.
ObjCProtocolRecord *addObjCProtocol(StringRef Name, StringRef USR, ObjCProtocolRecord *addObjCProtocol(StringRef Name, StringRef USR,
PresumedLoc Loc, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading); DeclarationFragments SubHeading);
@ -641,7 +637,7 @@ public:
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method /// 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. /// to generate the USR for \c D and keep it alive in APISet.
TypedefRecord *addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, TypedefRecord *addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availability,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,

View File

@ -15,6 +15,8 @@
#ifndef LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H #ifndef LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H
#define LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H #define LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include "llvm/Support/VersionTuple.h" #include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
@ -24,20 +26,38 @@ using llvm::VersionTuple;
namespace clang { namespace clang {
namespace extractapi { namespace extractapi {
/// Stores availability attributes of a symbol. /// Stores availability attributes of a symbol in a given domain.
struct AvailabilityInfo { struct AvailabilityInfo {
/// The domain for which this availability info item applies
std::string Domain;
VersionTuple Introduced; VersionTuple Introduced;
VersionTuple Deprecated; VersionTuple Deprecated;
VersionTuple Obsoleted; VersionTuple Obsoleted;
bool Unavailable{false};
bool UnconditionallyDeprecated{false};
bool UnconditionallyUnavailable{false};
/// Determine if this AvailabilityInfo represents the default availability. AvailabilityInfo() = default;
bool isDefault() const { return *this == AvailabilityInfo(); }
/// Check if the symbol is unavailable. AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
bool isUnavailable() const { return Unavailable; } VersionTuple O)
: Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O) {}
};
class AvailabilitySet {
private:
using AvailabilityList = llvm::SmallVector<AvailabilityInfo, 4>;
AvailabilityList Availabilities;
bool UnconditionallyDeprecated = false;
bool UnconditionallyUnavailable = false;
public:
AvailabilitySet(const Decl *Decl);
AvailabilitySet() = default;
AvailabilityList::const_iterator begin() const {
return Availabilities.begin();
}
AvailabilityList::const_iterator end() const { return Availabilities.end(); }
/// Check if the symbol is unconditionally deprecated. /// Check if the symbol is unconditionally deprecated.
/// ///
@ -51,27 +71,10 @@ struct AvailabilityInfo {
return UnconditionallyUnavailable; return UnconditionallyUnavailable;
} }
AvailabilityInfo() = default; /// Determine if this AvailabilitySet represents default availability.
bool isDefault() const { return Availabilities.empty(); }
AvailabilityInfo(VersionTuple I, VersionTuple D, VersionTuple O, bool U,
bool UD, bool UU)
: Introduced(I), Deprecated(D), Obsoleted(O), Unavailable(U),
UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {}
friend bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs);
}; };
inline bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs) {
return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted,
Lhs.Unavailable, Lhs.UnconditionallyDeprecated,
Lhs.UnconditionallyUnavailable) ==
std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted,
Rhs.Unavailable, Rhs.UnconditionallyDeprecated,
Rhs.UnconditionallyUnavailable);
}
} // namespace extractapi } // namespace extractapi
} // namespace clang } // namespace clang

View File

@ -43,68 +43,77 @@ RecordTy *addTopLevelRecord(APISet::RecordMap<RecordTy> &RecordMap,
GlobalVariableRecord * GlobalVariableRecord *
APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Fragments, const DocComment &Comment, DeclarationFragments Fragments,
DeclarationFragments SubHeading) { DeclarationFragments SubHeading) {
return addTopLevelRecord(GlobalVariables, USR, Name, Loc, Availability, return addTopLevelRecord(GlobalVariables, USR, Name, Loc,
Linkage, Comment, Fragments, SubHeading); std::move(Availabilities), Linkage, Comment,
Fragments, SubHeading);
} }
GlobalFunctionRecord *APISet::addGlobalFunction( GlobalFunctionRecord *APISet::addGlobalFunction(
StringRef Name, StringRef USR, PresumedLoc Loc, StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Fragments, const DocComment &Comment, DeclarationFragments Fragments,
DeclarationFragments SubHeading, FunctionSignature Signature) { DeclarationFragments SubHeading, FunctionSignature Signature) {
return addTopLevelRecord(GlobalFunctions, USR, Name, Loc, Availability, return addTopLevelRecord(GlobalFunctions, USR, Name, Loc,
Linkage, Comment, Fragments, SubHeading, Signature); std::move(Availabilities), Linkage, Comment,
Fragments, SubHeading, Signature);
} }
EnumConstantRecord *APISet::addEnumConstant( EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, const DocComment &Comment, AvailabilitySet Availabilities,
DeclarationFragments Declaration, DeclarationFragments SubHeading) { const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading) {
auto Record = std::make_unique<EnumConstantRecord>( auto Record = std::make_unique<EnumConstantRecord>(
USR, Name, Loc, Availability, Comment, Declaration, SubHeading); USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
SubHeading);
return Enum->Constants.emplace_back(std::move(Record)).get(); return Enum->Constants.emplace_back(std::move(Record)).get();
} }
EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) { DeclarationFragments SubHeading) {
return addTopLevelRecord(Enums, USR, Name, Loc, Availability, Comment, return addTopLevelRecord(Enums, USR, Name, Loc, std::move(Availabilities),
Declaration, SubHeading); Comment, Declaration, SubHeading);
} }
StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name, StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
StringRef USR, PresumedLoc Loc, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) { DeclarationFragments SubHeading) {
auto Record = std::make_unique<StructFieldRecord>( auto Record = std::make_unique<StructFieldRecord>(
USR, Name, Loc, Availability, Comment, Declaration, SubHeading); USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
SubHeading);
return Struct->Fields.emplace_back(std::move(Record)).get(); return Struct->Fields.emplace_back(std::move(Record)).get();
} }
StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading) { DeclarationFragments SubHeading) {
return addTopLevelRecord(Structs, USR, Name, Loc, Availability, Comment, return addTopLevelRecord(Structs, USR, Name, Loc, std::move(Availabilities),
Declaration, SubHeading); Comment, Declaration, SubHeading);
} }
ObjCCategoryRecord *APISet::addObjCCategory( ObjCCategoryRecord *APISet::addObjCCategory(StringRef Name, StringRef USR,
StringRef Name, StringRef USR, PresumedLoc Loc, PresumedLoc Loc,
const AvailabilityInfo &Availability, const DocComment &Comment, AvailabilitySet Availabilities,
DeclarationFragments Declaration, DeclarationFragments SubHeading, const DocComment &Comment,
SymbolReference Interface) { DeclarationFragments Declaration,
DeclarationFragments SubHeading,
SymbolReference Interface) {
// Create the category record. // Create the category record.
auto *Record = addTopLevelRecord(ObjCCategories, USR, Name, Loc, Availability, auto *Record = addTopLevelRecord(ObjCCategories, USR, Name, Loc,
Comment, Declaration, SubHeading, Interface); std::move(Availabilities), Comment,
Declaration, SubHeading, Interface);
// If this category is extending a known interface, associate it with the // If this category is extending a known interface, associate it with the
// ObjCInterfaceRecord. // ObjCInterfaceRecord.
@ -117,56 +126,57 @@ ObjCCategoryRecord *APISet::addObjCCategory(
ObjCInterfaceRecord *APISet::addObjCInterface( ObjCInterfaceRecord *APISet::addObjCInterface(
StringRef Name, StringRef USR, PresumedLoc Loc, StringRef Name, StringRef USR, PresumedLoc Loc,
const AvailabilityInfo &Availability, LinkageInfo Linkage, AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Declaration, const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, SymbolReference SuperClass) { DeclarationFragments SubHeading, SymbolReference SuperClass) {
return addTopLevelRecord(ObjCInterfaces, USR, Name, Loc, Availability, return addTopLevelRecord(ObjCInterfaces, USR, Name, Loc,
Linkage, Comment, Declaration, SubHeading, std::move(Availabilities), Linkage, Comment,
SuperClass); Declaration, SubHeading, SuperClass);
} }
ObjCMethodRecord *APISet::addObjCMethod( ObjCMethodRecord *APISet::addObjCMethod(
ObjCContainerRecord *Container, StringRef Name, StringRef USR, ObjCContainerRecord *Container, StringRef Name, StringRef USR,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration, DeclarationFragments SubHeading,
DeclarationFragments SubHeading, FunctionSignature Signature, FunctionSignature Signature, bool IsInstanceMethod) {
bool IsInstanceMethod) {
auto Record = std::make_unique<ObjCMethodRecord>( auto Record = std::make_unique<ObjCMethodRecord>(
USR, Name, Loc, Availability, Comment, Declaration, SubHeading, Signature, USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
IsInstanceMethod); SubHeading, Signature, IsInstanceMethod);
return Container->Methods.emplace_back(std::move(Record)).get(); return Container->Methods.emplace_back(std::move(Record)).get();
} }
ObjCPropertyRecord *APISet::addObjCProperty( ObjCPropertyRecord *APISet::addObjCProperty(
ObjCContainerRecord *Container, StringRef Name, StringRef USR, ObjCContainerRecord *Container, StringRef Name, StringRef USR,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration, DeclarationFragments SubHeading,
DeclarationFragments SubHeading,
ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
StringRef SetterName, bool IsOptional) { StringRef SetterName, bool IsOptional) {
auto Record = std::make_unique<ObjCPropertyRecord>( auto Record = std::make_unique<ObjCPropertyRecord>(
USR, Name, Loc, Availability, Comment, Declaration, SubHeading, USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
Attributes, GetterName, SetterName, IsOptional); SubHeading, Attributes, GetterName, SetterName, IsOptional);
return Container->Properties.emplace_back(std::move(Record)).get(); return Container->Properties.emplace_back(std::move(Record)).get();
} }
ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
ObjCContainerRecord *Container, StringRef Name, StringRef USR, ObjCContainerRecord *Container, StringRef Name, StringRef USR,
PresumedLoc Loc, const AvailabilityInfo &Availability, PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments Declaration, DeclarationFragments SubHeading,
DeclarationFragments SubHeading,
ObjCInstanceVariableRecord::AccessControl Access) { ObjCInstanceVariableRecord::AccessControl Access) {
auto Record = std::make_unique<ObjCInstanceVariableRecord>( auto Record = std::make_unique<ObjCInstanceVariableRecord>(
USR, Name, Loc, Availability, Comment, Declaration, SubHeading, Access); USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
SubHeading, Access);
return Container->Ivars.emplace_back(std::move(Record)).get(); return Container->Ivars.emplace_back(std::move(Record)).get();
} }
ObjCProtocolRecord *APISet::addObjCProtocol( ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
StringRef Name, StringRef USR, PresumedLoc Loc, PresumedLoc Loc,
const AvailabilityInfo &Availability, const DocComment &Comment, AvailabilitySet Availabilities,
DeclarationFragments Declaration, DeclarationFragments SubHeading) { const DocComment &Comment,
return addTopLevelRecord(ObjCProtocols, USR, Name, Loc, Availability, Comment, DeclarationFragments Declaration,
Declaration, SubHeading); DeclarationFragments SubHeading) {
return addTopLevelRecord(ObjCProtocols, USR, Name, Loc,
std::move(Availabilities), Comment, Declaration,
SubHeading);
} }
MacroDefinitionRecord * MacroDefinitionRecord *
@ -178,13 +188,13 @@ APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR, TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
PresumedLoc Loc, PresumedLoc Loc,
const AvailabilityInfo &Availability, AvailabilitySet Availabilities,
const DocComment &Comment, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments Declaration,
DeclarationFragments SubHeading, DeclarationFragments SubHeading,
SymbolReference UnderlyingType) { SymbolReference UnderlyingType) {
return addTopLevelRecord(Typedefs, USR, Name, Loc, Availability, Comment, return addTopLevelRecord(Typedefs, USR, Name, Loc, std::move(Availabilities),
Declaration, SubHeading, UnderlyingType); Comment, Declaration, SubHeading, UnderlyingType);
} }
StringRef APISet::recordUSR(const Decl *D) { StringRef APISet::recordUSR(const Decl *D) {

View File

@ -0,0 +1,50 @@
#include "clang/ExtractAPI/AvailabilityInfo.h"
#include "clang/AST/Attr.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace extractapi;
AvailabilitySet::AvailabilitySet(const Decl *Decl) {
// Collect availability attributes from all redeclrations.
for (const auto *RD : Decl->redecls()) {
if (const auto *A = RD->getAttr<UnavailableAttr>()) {
if (!A->isImplicit()) {
this->Availabilities.clear();
UnconditionallyUnavailable = true;
}
}
if (const auto *A = RD->getAttr<DeprecatedAttr>()) {
if (!A->isImplicit()) {
this->Availabilities.clear();
UnconditionallyDeprecated = true;
}
}
for (const auto *Attr : RD->specific_attrs<AvailabilityAttr>()) {
StringRef Domain = Attr->getPlatform()->getName();
auto *Availability =
llvm::find_if(Availabilities, [Domain](const AvailabilityInfo &Info) {
return Domain.equals(Info.Domain);
});
if (Availability != Availabilities.end()) {
// Get the highest introduced version for all redeclarations.
if (Availability->Introduced < Attr->getIntroduced())
Availability->Introduced = Attr->getIntroduced();
// Get the lowest deprecated version for all redeclarations.
if (Availability->Deprecated > Attr->getDeprecated())
Availability->Deprecated = Attr->getDeprecated();
// Get the lowest obsoleted version for all redeclarations.
if (Availability->Obsoleted > Attr->getObsoleted())
Availability->Obsoleted = Attr->getObsoleted();
} else {
Availabilities.emplace_back(Domain, Attr->getIntroduced(),
Attr->getDeprecated(),
Attr->getObsoleted());
}
}
}
}

View File

@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangExtractAPI add_clang_library(clangExtractAPI
API.cpp API.cpp
AvailabilityInfo.cpp
ExtractAPIConsumer.cpp ExtractAPIConsumer.cpp
DeclarationFragments.cpp DeclarationFragments.cpp
Serialization/SerializerBase.cpp Serialization/SerializerBase.cpp

View File

@ -264,7 +264,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
LinkageInfo Linkage = Decl->getLinkageAndVisibility(); LinkageInfo Linkage = Decl->getLinkageAndVisibility();
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
@ -278,7 +277,7 @@ public:
DeclarationFragmentsBuilder::getSubHeading(Decl); DeclarationFragmentsBuilder::getSubHeading(Decl);
// Add the global variable record to the API set. // Add the global variable record to the API set.
API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
Declaration, SubHeading); Declaration, SubHeading);
return true; return true;
} }
@ -325,7 +324,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
LinkageInfo Linkage = Decl->getLinkageAndVisibility(); LinkageInfo Linkage = Decl->getLinkageAndVisibility();
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
@ -341,8 +339,8 @@ public:
DeclarationFragmentsBuilder::getFunctionSignature(Decl); DeclarationFragmentsBuilder::getFunctionSignature(Decl);
// Add the function record to the API set. // Add the function record to the API set.
API.addGlobalFunction(Name, USR, Loc, Availability, Linkage, Comment, API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage,
Declaration, SubHeading, Signature); Comment, Declaration, SubHeading, Signature);
return true; return true;
} }
@ -366,7 +364,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -379,8 +376,8 @@ public:
DeclarationFragmentsBuilder::getSubHeading(Decl); DeclarationFragmentsBuilder::getSubHeading(Decl);
EnumRecord *EnumRecord = EnumRecord *EnumRecord =
API.addEnum(API.copyString(Name), USR, Loc, Availability, Comment, API.addEnum(API.copyString(Name), USR, Loc, AvailabilitySet(Decl),
Declaration, SubHeading); Comment, Declaration, SubHeading);
// Now collect information about the enumerators in this enum. // Now collect information about the enumerators in this enum.
recordEnumConstants(EnumRecord, Decl->enumerators()); recordEnumConstants(EnumRecord, Decl->enumerators());
@ -407,7 +404,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -419,8 +415,9 @@ public:
DeclarationFragments SubHeading = DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl); DeclarationFragmentsBuilder::getSubHeading(Decl);
StructRecord *StructRecord = API.addStruct( StructRecord *StructRecord =
Name, USR, Loc, Availability, Comment, Declaration, SubHeading); API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment,
Declaration, SubHeading);
// Now collect information about the fields in this struct. // Now collect information about the fields in this struct.
recordStructFields(StructRecord, Decl->fields()); recordStructFields(StructRecord, Decl->fields());
@ -441,7 +438,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
LinkageInfo Linkage = Decl->getLinkageAndVisibility(); LinkageInfo Linkage = Decl->getLinkageAndVisibility();
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
@ -462,8 +458,8 @@ public:
} }
ObjCInterfaceRecord *ObjCInterfaceRecord = ObjCInterfaceRecord *ObjCInterfaceRecord =
API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment, API.addObjCInterface(Name, USR, Loc, AvailabilitySet(Decl), Linkage,
Declaration, SubHeading, SuperClass); Comment, Declaration, SubHeading, SuperClass);
// Record all methods (selectors). This doesn't include automatically // Record all methods (selectors). This doesn't include automatically
// synthesized property methods. // synthesized property methods.
@ -488,7 +484,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -500,8 +495,9 @@ public:
DeclarationFragments SubHeading = DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl); DeclarationFragmentsBuilder::getSubHeading(Decl);
ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( ObjCProtocolRecord *ObjCProtocolRecord =
Name, USR, Loc, Availability, Comment, Declaration, SubHeading); API.addObjCProtocol(Name, USR, Loc, AvailabilitySet(Decl), Comment,
Declaration, SubHeading);
recordObjCMethods(ObjCProtocolRecord, Decl->methods()); recordObjCMethods(ObjCProtocolRecord, Decl->methods());
recordObjCProperties(ObjCProtocolRecord, Decl->properties()); recordObjCProperties(ObjCProtocolRecord, Decl->properties());
@ -524,7 +520,6 @@ public:
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
StringRef Name = Decl->getName(); StringRef Name = Decl->getName();
AvailabilityInfo Availability = getAvailability(Decl);
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
@ -536,7 +531,7 @@ public:
TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
API); API);
API.addTypedef(Name, USR, Loc, Availability, Comment, API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef); DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
@ -549,7 +544,6 @@ public:
StringRef USR = API.recordUSR(Decl); StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation()); Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -565,8 +559,8 @@ public:
API.recordUSR(InterfaceDecl)); API.recordUSR(InterfaceDecl));
ObjCCategoryRecord *ObjCCategoryRecord = ObjCCategoryRecord *ObjCCategoryRecord =
API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration, API.addObjCCategory(Name, USR, Loc, AvailabilitySet(Decl), Comment,
SubHeading, Interface); Declaration, SubHeading, Interface);
recordObjCMethods(ObjCCategoryRecord, Decl->methods()); recordObjCMethods(ObjCCategoryRecord, Decl->methods());
recordObjCProperties(ObjCCategoryRecord, Decl->properties()); recordObjCProperties(ObjCCategoryRecord, Decl->properties());
@ -577,37 +571,6 @@ public:
} }
private: private:
/// Get availability information of the declaration \p D.
AvailabilityInfo getAvailability(const Decl *D) const {
StringRef PlatformName = Context.getTargetInfo().getPlatformName();
AvailabilityInfo Availability;
// Collect availability attributes from all redeclarations.
for (const auto *RD : D->redecls()) {
for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
if (A->getPlatform()->getName() != PlatformName)
continue;
Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
A->getObsoleted(), A->getUnavailable(),
/* UnconditionallyDeprecated */ false,
/* UnconditionallyUnavailable */ false);
break;
}
if (const auto *A = RD->getAttr<UnavailableAttr>())
if (!A->isImplicit()) {
Availability.Unavailable = true;
Availability.UnconditionallyUnavailable = true;
}
if (const auto *A = RD->getAttr<DeprecatedAttr>())
if (!A->isImplicit())
Availability.UnconditionallyDeprecated = true;
}
return Availability;
}
/// Collect API information for the enum constants and associate with the /// Collect API information for the enum constants and associate with the
/// parent enum. /// parent enum.
void recordEnumConstants(EnumRecord *EnumRecord, void recordEnumConstants(EnumRecord *EnumRecord,
@ -618,7 +581,6 @@ private:
StringRef USR = API.recordUSR(Constant); StringRef USR = API.recordUSR(Constant);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Constant->getLocation()); Context.getSourceManager().getPresumedLoc(Constant->getLocation());
AvailabilityInfo Availability = getAvailability(Constant);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -630,8 +592,8 @@ private:
DeclarationFragments SubHeading = DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Constant); DeclarationFragmentsBuilder::getSubHeading(Constant);
API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment, API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
Declaration, SubHeading); Comment, Declaration, SubHeading);
} }
} }
@ -645,7 +607,6 @@ private:
StringRef USR = API.recordUSR(Field); StringRef USR = API.recordUSR(Field);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Field->getLocation()); Context.getSourceManager().getPresumedLoc(Field->getLocation());
AvailabilityInfo Availability = getAvailability(Field);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -657,8 +618,8 @@ private:
DeclarationFragments SubHeading = DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Field); DeclarationFragmentsBuilder::getSubHeading(Field);
API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment, API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
Declaration, SubHeading); Comment, Declaration, SubHeading);
} }
} }
@ -675,7 +636,6 @@ private:
StringRef USR = API.recordUSR(Method); StringRef USR = API.recordUSR(Method);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Method->getLocation()); Context.getSourceManager().getPresumedLoc(Method->getLocation());
AvailabilityInfo Availability = getAvailability(Method);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -689,8 +649,8 @@ private:
FunctionSignature Signature = FunctionSignature Signature =
DeclarationFragmentsBuilder::getFunctionSignature(Method); DeclarationFragmentsBuilder::getFunctionSignature(Method);
API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment, API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
Declaration, SubHeading, Signature, Comment, Declaration, SubHeading, Signature,
Method->isInstanceMethod()); Method->isInstanceMethod());
} }
} }
@ -702,7 +662,6 @@ private:
StringRef USR = API.recordUSR(Property); StringRef USR = API.recordUSR(Property);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Property->getLocation()); Context.getSourceManager().getPresumedLoc(Property->getLocation());
AvailabilityInfo Availability = getAvailability(Property);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -728,8 +687,8 @@ private:
Attributes |= ObjCPropertyRecord::Class; Attributes |= ObjCPropertyRecord::Class;
API.addObjCProperty( API.addObjCProperty(
Container, Name, USR, Loc, Availability, Comment, Declaration, Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
SubHeading, Declaration, SubHeading,
static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
GetterName, SetterName, Property->isOptional()); GetterName, SetterName, Property->isOptional());
} }
@ -745,7 +704,6 @@ private:
StringRef USR = API.recordUSR(Ivar); StringRef USR = API.recordUSR(Ivar);
PresumedLoc Loc = PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
AvailabilityInfo Availability = getAvailability(Ivar);
DocComment Comment; DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
Comment = RawComment->getFormattedLines(Context.getSourceManager(), Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -760,8 +718,9 @@ private:
ObjCInstanceVariableRecord::AccessControl Access = ObjCInstanceVariableRecord::AccessControl Access =
Ivar->getCanonicalAccessControl(); Ivar->getCanonicalAccessControl();
API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability, API.addObjCInstanceVariable(Container, Name, USR, Loc,
Comment, Declaration, SubHeading, Access); AvailabilitySet(Ivar), Comment, Declaration,
SubHeading, Access);
} }
} }

View File

@ -135,30 +135,42 @@ Object serializeSourceRange(const PresumedLoc &BeginLoc,
/// Serialize the availability attributes of a symbol. /// Serialize the availability attributes of a symbol.
/// ///
/// Availability information contains the introduced, deprecated, and obsoleted /// Availability information contains the introduced, deprecated, and obsoleted
/// versions of the symbol as semantic versions, if not default. /// versions of the symbol for a given domain (roughly corresponds to a
/// Availability information also contains flags to indicate if the symbol is /// platform) as semantic versions, if not default. Availability information
/// unconditionally unavailable or deprecated, /// also contains flags to indicate if the symbol is unconditionally unavailable
/// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). /// or deprecated, i.e. \c __attribute__((unavailable)) and \c
/// __attribute__((deprecated)).
/// ///
/// \returns \c None if the symbol has default availability attributes, or /// \returns \c None if the symbol has default availability attributes, or
/// an \c Object containing the formatted availability information. /// an \c Array containing the formatted availability information.
Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) { Optional<Array> serializeAvailability(const AvailabilitySet &Availabilities) {
if (Avail.isDefault()) if (Availabilities.isDefault())
return None; return None;
Object Availability; Array AvailabilityArray;
serializeObject(Availability, "introducedVersion",
serializeSemanticVersion(Avail.Introduced));
serializeObject(Availability, "deprecatedVersion",
serializeSemanticVersion(Avail.Deprecated));
serializeObject(Availability, "obsoletedVersion",
serializeSemanticVersion(Avail.Obsoleted));
if (Avail.isUnavailable())
Availability["isUnconditionallyUnavailable"] = true;
if (Avail.isUnconditionallyDeprecated())
Availability["isUnconditionallyDeprecated"] = true;
return Availability; if (Availabilities.isUnconditionallyDeprecated()) {
Object UnconditionallyDeprecated;
UnconditionallyDeprecated["domain"] = "*";
UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
}
// Note unconditionally unavailable records are skipped.
for (const auto &AvailInfo : Availabilities) {
Object Availability;
Availability["domain"] = AvailInfo.Domain;
serializeObject(Availability, "introducedVersion",
serializeSemanticVersion(AvailInfo.Introduced));
serializeObject(Availability, "deprecatedVersion",
serializeSemanticVersion(AvailInfo.Deprecated));
serializeObject(Availability, "obsoletedVersion",
serializeSemanticVersion(AvailInfo.Obsoleted));
AvailabilityArray.emplace_back(std::move(Availability));
}
return AvailabilityArray;
} }
/// Get the language name string for interface language references. /// Get the language name string for interface language references.
@ -469,7 +481,7 @@ Object SymbolGraphSerializer::serializeModule() const {
bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
// Skip unconditionally unavailable symbols // Skip unconditionally unavailable symbols
if (Record.Availability.isUnconditionallyUnavailable()) if (Record.Availabilities.isUnconditionallyUnavailable())
return true; return true;
// Filter out symbols prefixed with an underscored as they are understood to // Filter out symbols prefixed with an underscored as they are understood to
@ -494,8 +506,8 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
serializeObject( serializeObject(
Obj, "location", Obj, "location",
serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
serializeObject(Obj, "availability", serializeArray(Obj, "availability",
serializeAvailability(Record.Availability)); serializeAvailability(Record.Availabilities));
serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
serializeArray(Obj, "declarationFragments", serializeArray(Obj, "declarationFragments",
serializeDeclarationFragments(Record.Declaration)); serializeDeclarationFragments(Record.Declaration));

View File

@ -0,0 +1,459 @@
// 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 --product-name=Availability -triple arm64-apple-macosx -x c-header %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
// CHECK-NOT: error:
// CHECK-NOT: warning:
//--- input.h
void a(void);
void b(void) __attribute__((availability(macos, introduced=12.0)));
void c(void) __attribute__((availability(macos, introduced=11.0, deprecated=12.0, obsoleted=20.0)));
void d(void) __attribute__((availability(macos, introduced=11.0, deprecated=12.0, obsoleted=20.0))) __attribute__((availability(ios, introduced=13.0)));
void e(void) __attribute__((deprecated)) __attribute__((availability(macos, introduced=11.0)));
void f(void) __attribute__((unavailable)) __attribute__((availability(macos, introduced=11.0)));
void d(void) __attribute__((availability(tvos, introduced=15.0)));
///expected-no-diagnostics
//--- reference.output.json.in
{
"metadata": {
"formatVersion": {
"major": 0,
"minor": 5,
"patch": 3
},
"generator": "?"
},
"module": {
"name": "Availability",
"platform": {
"architecture": "arm64",
"operatingSystem": {
"minimumVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"name": "macosx"
},
"vendor": "apple"
}
},
"relationships": [],
"symbols": [
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "a"
},
{
"kind": "text",
"spelling": "()"
}
],
"functionSignature": {
"returns": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
}
]
},
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@F@a"
},
"kind": {
"displayName": "Function",
"identifier": "c.func"
},
"location": {
"position": {
"character": 6,
"line": 1
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "a"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "a"
}
],
"title": "a"
},
"pathComponents": [
"a"
]
},
{
"accessLevel": "public",
"availability": [
{
"domain": "macos",
"introducedVersion": {
"major": 12,
"minor": 0,
"patch": 0
}
}
],
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "b"
},
{
"kind": "text",
"spelling": "()"
}
],
"functionSignature": {
"returns": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
}
]
},
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@F@b"
},
"kind": {
"displayName": "Function",
"identifier": "c.func"
},
"location": {
"position": {
"character": 6,
"line": 3
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "b"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "b"
}
],
"title": "b"
},
"pathComponents": [
"b"
]
},
{
"accessLevel": "public",
"availability": [
{
"deprecatedVersion": {
"major": 12,
"minor": 0,
"patch": 0
},
"domain": "macos",
"introducedVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"obsoletedVersion": {
"major": 20,
"minor": 0,
"patch": 0
}
}
],
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "c"
},
{
"kind": "text",
"spelling": "()"
}
],
"functionSignature": {
"returns": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
}
]
},
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@F@c"
},
"kind": {
"displayName": "Function",
"identifier": "c.func"
},
"location": {
"position": {
"character": 6,
"line": 5
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "c"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "c"
}
],
"title": "c"
},
"pathComponents": [
"c"
]
},
{
"accessLevel": "public",
"availability": [
{
"deprecatedVersion": {
"major": 12,
"minor": 0,
"patch": 0
},
"domain": "macos",
"introducedVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"obsoletedVersion": {
"major": 20,
"minor": 0,
"patch": 0
}
},
{
"domain": "ios",
"introducedVersion": {
"major": 13,
"minor": 0,
"patch": 0
}
},
{
"domain": "tvos",
"introducedVersion": {
"major": 15,
"minor": 0,
"patch": 0
}
}
],
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "d"
},
{
"kind": "text",
"spelling": "()"
}
],
"functionSignature": {
"returns": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
}
]
},
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@F@d"
},
"kind": {
"displayName": "Function",
"identifier": "c.func"
},
"location": {
"position": {
"character": 6,
"line": 7
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "d"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "d"
}
],
"title": "d"
},
"pathComponents": [
"d"
]
},
{
"accessLevel": "public",
"availability": [
{
"domain": "*",
"isUnconditionallyDeprecated": true
},
{
"domain": "macos",
"introducedVersion": {
"major": 11,
"minor": 0,
"patch": 0
}
}
],
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "e"
},
{
"kind": "text",
"spelling": "()"
}
],
"functionSignature": {
"returns": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:v",
"spelling": "void"
}
]
},
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@F@e"
},
"kind": {
"displayName": "Function",
"identifier": "c.func"
},
"location": {
"position": {
"character": 6,
"line": 9
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "e"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "e"
}
],
"title": "e"
},
"pathComponents": [
"e"
]
}
]
}