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

View File

@ -15,6 +15,8 @@
#ifndef 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/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
@ -24,20 +26,38 @@ using llvm::VersionTuple;
namespace clang {
namespace extractapi {
/// Stores availability attributes of a symbol.
/// Stores availability attributes of a symbol in a given domain.
struct AvailabilityInfo {
/// The domain for which this availability info item applies
std::string Domain;
VersionTuple Introduced;
VersionTuple Deprecated;
VersionTuple Obsoleted;
bool Unavailable{false};
bool UnconditionallyDeprecated{false};
bool UnconditionallyUnavailable{false};
/// Determine if this AvailabilityInfo represents the default availability.
bool isDefault() const { return *this == AvailabilityInfo(); }
AvailabilityInfo() = default;
/// Check if the symbol is unavailable.
bool isUnavailable() const { return Unavailable; }
AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
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.
///
@ -51,27 +71,10 @@ struct AvailabilityInfo {
return UnconditionallyUnavailable;
}
AvailabilityInfo() = default;
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);
/// Determine if this AvailabilitySet represents default availability.
bool isDefault() const { return Availabilities.empty(); }
};
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 clang

View File

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

View File

@ -264,7 +264,6 @@ public:
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))
@ -278,7 +277,7 @@ public:
DeclarationFragmentsBuilder::getSubHeading(Decl);
// 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);
return true;
}
@ -325,7 +324,6 @@ public:
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))
@ -341,8 +339,8 @@ public:
DeclarationFragmentsBuilder::getFunctionSignature(Decl);
// Add the function record to the API set.
API.addGlobalFunction(Name, USR, Loc, Availability, Linkage, Comment,
Declaration, SubHeading, Signature);
API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage,
Comment, Declaration, SubHeading, Signature);
return true;
}
@ -366,7 +364,6 @@ public:
StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -379,8 +376,8 @@ public:
DeclarationFragmentsBuilder::getSubHeading(Decl);
EnumRecord *EnumRecord =
API.addEnum(API.copyString(Name), USR, Loc, Availability, Comment,
Declaration, SubHeading);
API.addEnum(API.copyString(Name), USR, Loc, AvailabilitySet(Decl),
Comment, Declaration, SubHeading);
// Now collect information about the enumerators in this enum.
recordEnumConstants(EnumRecord, Decl->enumerators());
@ -407,7 +404,6 @@ public:
StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -419,8 +415,9 @@ public:
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
StructRecord *StructRecord = API.addStruct(
Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
StructRecord *StructRecord =
API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment,
Declaration, SubHeading);
// Now collect information about the fields in this struct.
recordStructFields(StructRecord, Decl->fields());
@ -441,7 +438,6 @@ public:
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))
@ -462,8 +458,8 @@ public:
}
ObjCInterfaceRecord *ObjCInterfaceRecord =
API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
Declaration, SubHeading, SuperClass);
API.addObjCInterface(Name, USR, Loc, AvailabilitySet(Decl), Linkage,
Comment, Declaration, SubHeading, SuperClass);
// Record all methods (selectors). This doesn't include automatically
// synthesized property methods.
@ -488,7 +484,6 @@ public:
StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -500,8 +495,9 @@ public:
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
ObjCProtocolRecord *ObjCProtocolRecord =
API.addObjCProtocol(Name, USR, Loc, AvailabilitySet(Decl), Comment,
Declaration, SubHeading);
recordObjCMethods(ObjCProtocolRecord, Decl->methods());
recordObjCProperties(ObjCProtocolRecord, Decl->properties());
@ -524,7 +520,6 @@ public:
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
StringRef Name = Decl->getName();
AvailabilityInfo Availability = getAvailability(Decl);
StringRef USR = API.recordUSR(Decl);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
@ -536,7 +531,7 @@ public:
TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
API);
API.addTypedef(Name, USR, Loc, Availability, Comment,
API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
@ -549,7 +544,6 @@ public:
StringRef USR = API.recordUSR(Decl);
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
AvailabilityInfo Availability = getAvailability(Decl);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -565,8 +559,8 @@ public:
API.recordUSR(InterfaceDecl));
ObjCCategoryRecord *ObjCCategoryRecord =
API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
SubHeading, Interface);
API.addObjCCategory(Name, USR, Loc, AvailabilitySet(Decl), Comment,
Declaration, SubHeading, Interface);
recordObjCMethods(ObjCCategoryRecord, Decl->methods());
recordObjCProperties(ObjCCategoryRecord, Decl->properties());
@ -577,37 +571,6 @@ public:
}
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
/// parent enum.
void recordEnumConstants(EnumRecord *EnumRecord,
@ -618,7 +581,6 @@ private:
StringRef USR = API.recordUSR(Constant);
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Constant->getLocation());
AvailabilityInfo Availability = getAvailability(Constant);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -630,8 +592,8 @@ private:
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Constant);
API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
Declaration, SubHeading);
API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
Comment, Declaration, SubHeading);
}
}
@ -645,7 +607,6 @@ private:
StringRef USR = API.recordUSR(Field);
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Field->getLocation());
AvailabilityInfo Availability = getAvailability(Field);
DocComment Comment;
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
@ -657,8 +618,8 @@ private:
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Field);
API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
Declaration, SubHeading);
API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
Comment, Declaration, SubHeading);
}
}
@ -675,7 +636,6 @@ private:
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(),
@ -689,8 +649,8 @@ private:
FunctionSignature Signature =
DeclarationFragmentsBuilder::getFunctionSignature(Method);
API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
Declaration, SubHeading, Signature,
API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
Comment, Declaration, SubHeading, Signature,
Method->isInstanceMethod());
}
}
@ -702,7 +662,6 @@ private:
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(),
@ -728,8 +687,8 @@ private:
Attributes |= ObjCPropertyRecord::Class;
API.addObjCProperty(
Container, Name, USR, Loc, Availability, Comment, Declaration,
SubHeading,
Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
Declaration, SubHeading,
static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
GetterName, SetterName, Property->isOptional());
}
@ -745,7 +704,6 @@ private:
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(),
@ -760,8 +718,9 @@ private:
ObjCInstanceVariableRecord::AccessControl Access =
Ivar->getCanonicalAccessControl();
API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
Comment, Declaration, SubHeading, Access);
API.addObjCInstanceVariable(Container, Name, USR, Loc,
AvailabilitySet(Ivar), Comment, Declaration,
SubHeading, Access);
}
}

View File

@ -135,30 +135,42 @@ Object serializeSourceRange(const PresumedLoc &BeginLoc,
/// Serialize the availability attributes of a symbol.
///
/// Availability information contains the introduced, deprecated, and obsoleted
/// versions of the symbol as semantic versions, if not default.
/// Availability information also contains flags to indicate if the symbol is
/// unconditionally unavailable or deprecated,
/// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
/// versions of the symbol for a given domain (roughly corresponds to a
/// platform) as semantic versions, if not default. Availability information
/// also contains flags to indicate if the symbol is unconditionally unavailable
/// or deprecated, i.e. \c __attribute__((unavailable)) and \c
/// __attribute__((deprecated)).
///
/// \returns \c None if the symbol has default availability attributes, or
/// an \c Object containing the formatted availability information.
Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) {
if (Avail.isDefault())
/// an \c Array containing the formatted availability information.
Optional<Array> serializeAvailability(const AvailabilitySet &Availabilities) {
if (Availabilities.isDefault())
return None;
Object Availability;
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;
Array AvailabilityArray;
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.
@ -469,7 +481,7 @@ Object SymbolGraphSerializer::serializeModule() const {
bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
// Skip unconditionally unavailable symbols
if (Record.Availability.isUnconditionallyUnavailable())
if (Record.Availabilities.isUnconditionallyUnavailable())
return true;
// Filter out symbols prefixed with an underscored as they are understood to
@ -494,8 +506,8 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
serializeObject(
Obj, "location",
serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
serializeObject(Obj, "availability",
serializeAvailability(Record.Availability));
serializeArray(Obj, "availability",
serializeAvailability(Record.Availabilities));
serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
serializeArray(Obj, "declarationFragments",
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"
]
}
]
}