[clang] 57c9780 - [clang][ExtractAPI] Record availability information on all platforms
Daniel Grumberg via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 19 14:55:06 PDT 2022
Author: Daniel Grumberg
Date: 2022-08-19T14:54:52-07:00
New Revision: 57c9780d60b15baf0eba4393857affce47f60aa7
URL: https://github.com/llvm/llvm-project/commit/57c9780d60b15baf0eba4393857affce47f60aa7
DIFF: https://github.com/llvm/llvm-project/commit/57c9780d60b15baf0eba4393857affce47f60aa7.diff
LOG: [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
Added:
clang/lib/ExtractAPI/AvailabilityInfo.cpp
clang/test/ExtractAPI/availability.c
Modified:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/AvailabilityInfo.h
clang/lib/ExtractAPI/API.cpp
clang/lib/ExtractAPI/CMakeLists.txt
clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index 53db46ca44c13..b77d76d500df6 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -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 @@ struct APIRecord {
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 @@ struct GlobalFunctionRecord : APIRecord {
/// 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 @@ struct GlobalVariableRecord : APIRecord {
/// 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 @@ struct EnumRecord : APIRecord {
/// 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 @@ struct ObjCInterfaceRecord : ObjCContainerRecord {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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 @@ class APISet {
/// 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,
diff --git a/clang/include/clang/ExtractAPI/AvailabilityInfo.h b/clang/include/clang/ExtractAPI/AvailabilityInfo.h
index f5f85bd576120..a258bc52c125d 100644
--- a/clang/include/clang/ExtractAPI/AvailabilityInfo.h
+++ b/clang/include/clang/ExtractAPI/AvailabilityInfo.h
@@ -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;
+
+ 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;
- /// Check if the symbol is unavailable.
- bool isUnavailable() const { return Unavailable; }
+ 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
diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp
index 073e36f320d37..8ab03a833e3c2 100644
--- a/clang/lib/ExtractAPI/API.cpp
+++ b/clang/lib/ExtractAPI/API.cpp
@@ -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) {
diff --git a/clang/lib/ExtractAPI/AvailabilityInfo.cpp b/clang/lib/ExtractAPI/AvailabilityInfo.cpp
new file mode 100644
index 0000000000000..ada64cfb92e64
--- /dev/null
+++ b/clang/lib/ExtractAPI/AvailabilityInfo.cpp
@@ -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());
+ }
+ }
+ }
+}
diff --git a/clang/lib/ExtractAPI/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt
index ed79282c14906..904321ba33a58 100644
--- a/clang/lib/ExtractAPI/CMakeLists.txt
+++ b/clang/lib/ExtractAPI/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangExtractAPI
API.cpp
+ AvailabilityInfo.cpp
ExtractAPIConsumer.cpp
DeclarationFragments.cpp
Serialization/SerializerBase.cpp
diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index 1a785182e3634..969ee772fa063 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -264,7 +264,6 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
}
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
}
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
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);
}
}
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index d1bf83c8674f2..0810dec91b49b 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -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));
diff --git a/clang/test/ExtractAPI/availability.c b/clang/test/ExtractAPI/availability.c
new file mode 100644
index 0000000000000..54dbf5a6cac95
--- /dev/null
+++ b/clang/test/ExtractAPI/availability.c
@@ -0,0 +1,459 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s at 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 at 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 at 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 at 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 at 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 at 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"
+ ]
+ }
+ ]
+}
More information about the cfe-commits
mailing list