diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h --- a/clang/include/clang/ExtractAPI/API.h +++ b/clang/include/clang/ExtractAPI/API.h @@ -58,7 +58,7 @@ StringRef USR; StringRef Name; PresumedLoc Location; - AvailabilityInfo Availability; + AvailabilitySet Availabilities; LinkageInfo Linkage; /// Documentation comment lines attached to this symbol declaration. @@ -102,12 +102,13 @@ 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 @@ 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 @@ /// 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 @@ /// 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 @@ SmallVector> 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 @@ /// 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 @@ SmallVector> 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ SmallVector 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 @@ /// 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 @@ 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 @@ 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 @@ /// 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 --- 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 @@ 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; + 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 @@ 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 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -43,68 +43,77 @@ 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( - 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( - 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 @@ 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( - 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( - 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( - 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 @@ 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 --- /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()) { + if (!A->isImplicit()) { + this->Availabilities.clear(); + UnconditionallyUnavailable = true; + } + } + + if (const auto *A = RD->getAttr()) { + if (!A->isImplicit()) { + this->Availabilities.clear(); + UnconditionallyDeprecated = true; + } + } + + for (const auto *Attr : RD->specific_attrs()) { + 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 --- a/clang/lib/ExtractAPI/CMakeLists.txt +++ b/clang/lib/ExtractAPI/CMakeLists.txt @@ -4,6 +4,7 @@ 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 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -264,7 +264,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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()) { - 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()) - if (!A->isImplicit()) { - Availability.Unavailable = true; - Availability.UnconditionallyUnavailable = true; - } - - if (const auto *A = RD->getAttr()) - 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ Attributes |= ObjCPropertyRecord::Class; API.addObjCProperty( - Container, Name, USR, Loc, Availability, Comment, Declaration, - SubHeading, + Container, Name, USR, Loc, AvailabilitySet(Property), Comment, + Declaration, SubHeading, static_cast(Attributes), GetterName, SetterName, Property->isOptional()); } @@ -745,7 +704,6 @@ 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 @@ 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 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -135,30 +135,42 @@ /// 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 serializeAvailability(const AvailabilityInfo &Avail) { - if (Avail.isDefault()) +/// an \c Array containing the formatted availability information. +Optional 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 @@ 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 @@ 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 --- /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@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" + ] + } + ] +}