Skip to content

Commit 57c9780

Browse files
[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
1 parent 89aaae5 commit 57c9780

File tree

8 files changed

+731
-241
lines changed

8 files changed

+731
-241
lines changed

clang/include/clang/ExtractAPI/API.h

Lines changed: 66 additions & 70 deletions
Large diffs are not rendered by default.

clang/include/clang/ExtractAPI/AvailabilityInfo.h

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#ifndef LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H
1616
#define LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H
1717

18+
#include "clang/AST/Decl.h"
19+
#include "llvm/ADT/SmallVector.h"
1820
#include "llvm/Support/Error.h"
1921
#include "llvm/Support/VersionTuple.h"
2022
#include "llvm/Support/raw_ostream.h"
@@ -24,20 +26,38 @@ using llvm::VersionTuple;
2426
namespace clang {
2527
namespace extractapi {
2628

27-
/// Stores availability attributes of a symbol.
29+
/// Stores availability attributes of a symbol in a given domain.
2830
struct AvailabilityInfo {
31+
/// The domain for which this availability info item applies
32+
std::string Domain;
2933
VersionTuple Introduced;
3034
VersionTuple Deprecated;
3135
VersionTuple Obsoleted;
32-
bool Unavailable{false};
33-
bool UnconditionallyDeprecated{false};
34-
bool UnconditionallyUnavailable{false};
3536

36-
/// Determine if this AvailabilityInfo represents the default availability.
37-
bool isDefault() const { return *this == AvailabilityInfo(); }
37+
AvailabilityInfo() = default;
38+
39+
AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
40+
VersionTuple O)
41+
: Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O) {}
42+
};
43+
44+
class AvailabilitySet {
45+
private:
46+
using AvailabilityList = llvm::SmallVector<AvailabilityInfo, 4>;
47+
AvailabilityList Availabilities;
48+
49+
bool UnconditionallyDeprecated = false;
50+
bool UnconditionallyUnavailable = false;
51+
52+
public:
53+
AvailabilitySet(const Decl *Decl);
54+
AvailabilitySet() = default;
3855

39-
/// Check if the symbol is unavailable.
40-
bool isUnavailable() const { return Unavailable; }
56+
AvailabilityList::const_iterator begin() const {
57+
return Availabilities.begin();
58+
}
59+
60+
AvailabilityList::const_iterator end() const { return Availabilities.end(); }
4161

4262
/// Check if the symbol is unconditionally deprecated.
4363
///
@@ -51,27 +71,10 @@ struct AvailabilityInfo {
5171
return UnconditionallyUnavailable;
5272
}
5373

54-
AvailabilityInfo() = default;
55-
56-
AvailabilityInfo(VersionTuple I, VersionTuple D, VersionTuple O, bool U,
57-
bool UD, bool UU)
58-
: Introduced(I), Deprecated(D), Obsoleted(O), Unavailable(U),
59-
UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {}
60-
61-
friend bool operator==(const AvailabilityInfo &Lhs,
62-
const AvailabilityInfo &Rhs);
74+
/// Determine if this AvailabilitySet represents default availability.
75+
bool isDefault() const { return Availabilities.empty(); }
6376
};
6477

65-
inline bool operator==(const AvailabilityInfo &Lhs,
66-
const AvailabilityInfo &Rhs) {
67-
return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted,
68-
Lhs.Unavailable, Lhs.UnconditionallyDeprecated,
69-
Lhs.UnconditionallyUnavailable) ==
70-
std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted,
71-
Rhs.Unavailable, Rhs.UnconditionallyDeprecated,
72-
Rhs.UnconditionallyUnavailable);
73-
}
74-
7578
} // namespace extractapi
7679
} // namespace clang
7780

clang/lib/ExtractAPI/API.cpp

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,68 +43,77 @@ RecordTy *addTopLevelRecord(APISet::RecordMap<RecordTy> &RecordMap,
4343

4444
GlobalVariableRecord *
4545
APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
46-
const AvailabilityInfo &Availability, LinkageInfo Linkage,
46+
AvailabilitySet Availabilities, LinkageInfo Linkage,
4747
const DocComment &Comment, DeclarationFragments Fragments,
4848
DeclarationFragments SubHeading) {
49-
return addTopLevelRecord(GlobalVariables, USR, Name, Loc, Availability,
50-
Linkage, Comment, Fragments, SubHeading);
49+
return addTopLevelRecord(GlobalVariables, USR, Name, Loc,
50+
std::move(Availabilities), Linkage, Comment,
51+
Fragments, SubHeading);
5152
}
5253

5354
GlobalFunctionRecord *APISet::addGlobalFunction(
5455
StringRef Name, StringRef USR, PresumedLoc Loc,
55-
const AvailabilityInfo &Availability, LinkageInfo Linkage,
56+
AvailabilitySet Availabilities, LinkageInfo Linkage,
5657
const DocComment &Comment, DeclarationFragments Fragments,
5758
DeclarationFragments SubHeading, FunctionSignature Signature) {
58-
return addTopLevelRecord(GlobalFunctions, USR, Name, Loc, Availability,
59-
Linkage, Comment, Fragments, SubHeading, Signature);
59+
return addTopLevelRecord(GlobalFunctions, USR, Name, Loc,
60+
std::move(Availabilities), Linkage, Comment,
61+
Fragments, SubHeading, Signature);
6062
}
6163

62-
EnumConstantRecord *APISet::addEnumConstant(
63-
EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc,
64-
const AvailabilityInfo &Availability, const DocComment &Comment,
65-
DeclarationFragments Declaration, DeclarationFragments SubHeading) {
64+
EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
65+
StringRef USR, PresumedLoc Loc,
66+
AvailabilitySet Availabilities,
67+
const DocComment &Comment,
68+
DeclarationFragments Declaration,
69+
DeclarationFragments SubHeading) {
6670
auto Record = std::make_unique<EnumConstantRecord>(
67-
USR, Name, Loc, Availability, Comment, Declaration, SubHeading);
71+
USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
72+
SubHeading);
6873
return Enum->Constants.emplace_back(std::move(Record)).get();
6974
}
7075

7176
EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
72-
const AvailabilityInfo &Availability,
77+
AvailabilitySet Availabilities,
7378
const DocComment &Comment,
7479
DeclarationFragments Declaration,
7580
DeclarationFragments SubHeading) {
76-
return addTopLevelRecord(Enums, USR, Name, Loc, Availability, Comment,
77-
Declaration, SubHeading);
81+
return addTopLevelRecord(Enums, USR, Name, Loc, std::move(Availabilities),
82+
Comment, Declaration, SubHeading);
7883
}
7984

8085
StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
8186
StringRef USR, PresumedLoc Loc,
82-
const AvailabilityInfo &Availability,
87+
AvailabilitySet Availabilities,
8388
const DocComment &Comment,
8489
DeclarationFragments Declaration,
8590
DeclarationFragments SubHeading) {
8691
auto Record = std::make_unique<StructFieldRecord>(
87-
USR, Name, Loc, Availability, Comment, Declaration, SubHeading);
92+
USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
93+
SubHeading);
8894
return Struct->Fields.emplace_back(std::move(Record)).get();
8995
}
9096

9197
StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
92-
const AvailabilityInfo &Availability,
98+
AvailabilitySet Availabilities,
9399
const DocComment &Comment,
94100
DeclarationFragments Declaration,
95101
DeclarationFragments SubHeading) {
96-
return addTopLevelRecord(Structs, USR, Name, Loc, Availability, Comment,
97-
Declaration, SubHeading);
102+
return addTopLevelRecord(Structs, USR, Name, Loc, std::move(Availabilities),
103+
Comment, Declaration, SubHeading);
98104
}
99105

100-
ObjCCategoryRecord *APISet::addObjCCategory(
101-
StringRef Name, StringRef USR, PresumedLoc Loc,
102-
const AvailabilityInfo &Availability, const DocComment &Comment,
103-
DeclarationFragments Declaration, DeclarationFragments SubHeading,
104-
SymbolReference Interface) {
106+
ObjCCategoryRecord *APISet::addObjCCategory(StringRef Name, StringRef USR,
107+
PresumedLoc Loc,
108+
AvailabilitySet Availabilities,
109+
const DocComment &Comment,
110+
DeclarationFragments Declaration,
111+
DeclarationFragments SubHeading,
112+
SymbolReference Interface) {
105113
// Create the category record.
106-
auto *Record = addTopLevelRecord(ObjCCategories, USR, Name, Loc, Availability,
107-
Comment, Declaration, SubHeading, Interface);
114+
auto *Record = addTopLevelRecord(ObjCCategories, USR, Name, Loc,
115+
std::move(Availabilities), Comment,
116+
Declaration, SubHeading, Interface);
108117

109118
// If this category is extending a known interface, associate it with the
110119
// ObjCInterfaceRecord.
@@ -117,56 +126,57 @@ ObjCCategoryRecord *APISet::addObjCCategory(
117126

118127
ObjCInterfaceRecord *APISet::addObjCInterface(
119128
StringRef Name, StringRef USR, PresumedLoc Loc,
120-
const AvailabilityInfo &Availability, LinkageInfo Linkage,
129+
AvailabilitySet Availabilities, LinkageInfo Linkage,
121130
const DocComment &Comment, DeclarationFragments Declaration,
122131
DeclarationFragments SubHeading, SymbolReference SuperClass) {
123-
return addTopLevelRecord(ObjCInterfaces, USR, Name, Loc, Availability,
124-
Linkage, Comment, Declaration, SubHeading,
125-
SuperClass);
132+
return addTopLevelRecord(ObjCInterfaces, USR, Name, Loc,
133+
std::move(Availabilities), Linkage, Comment,
134+
Declaration, SubHeading, SuperClass);
126135
}
127136

128137
ObjCMethodRecord *APISet::addObjCMethod(
129138
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
130-
PresumedLoc Loc, const AvailabilityInfo &Availability,
131-
const DocComment &Comment, DeclarationFragments Declaration,
132-
DeclarationFragments SubHeading, FunctionSignature Signature,
133-
bool IsInstanceMethod) {
139+
PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
140+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
141+
FunctionSignature Signature, bool IsInstanceMethod) {
134142
auto Record = std::make_unique<ObjCMethodRecord>(
135-
USR, Name, Loc, Availability, Comment, Declaration, SubHeading, Signature,
136-
IsInstanceMethod);
143+
USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
144+
SubHeading, Signature, IsInstanceMethod);
137145
return Container->Methods.emplace_back(std::move(Record)).get();
138146
}
139147

140148
ObjCPropertyRecord *APISet::addObjCProperty(
141149
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
142-
PresumedLoc Loc, const AvailabilityInfo &Availability,
143-
const DocComment &Comment, DeclarationFragments Declaration,
144-
DeclarationFragments SubHeading,
150+
PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
151+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
145152
ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
146153
StringRef SetterName, bool IsOptional) {
147154
auto Record = std::make_unique<ObjCPropertyRecord>(
148-
USR, Name, Loc, Availability, Comment, Declaration, SubHeading,
149-
Attributes, GetterName, SetterName, IsOptional);
155+
USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
156+
SubHeading, Attributes, GetterName, SetterName, IsOptional);
150157
return Container->Properties.emplace_back(std::move(Record)).get();
151158
}
152159

153160
ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
154161
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
155-
PresumedLoc Loc, const AvailabilityInfo &Availability,
156-
const DocComment &Comment, DeclarationFragments Declaration,
157-
DeclarationFragments SubHeading,
162+
PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
163+
DeclarationFragments Declaration, DeclarationFragments SubHeading,
158164
ObjCInstanceVariableRecord::AccessControl Access) {
159165
auto Record = std::make_unique<ObjCInstanceVariableRecord>(
160-
USR, Name, Loc, Availability, Comment, Declaration, SubHeading, Access);
166+
USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
167+
SubHeading, Access);
161168
return Container->Ivars.emplace_back(std::move(Record)).get();
162169
}
163170

164-
ObjCProtocolRecord *APISet::addObjCProtocol(
165-
StringRef Name, StringRef USR, PresumedLoc Loc,
166-
const AvailabilityInfo &Availability, const DocComment &Comment,
167-
DeclarationFragments Declaration, DeclarationFragments SubHeading) {
168-
return addTopLevelRecord(ObjCProtocols, USR, Name, Loc, Availability, Comment,
169-
Declaration, SubHeading);
171+
ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
172+
PresumedLoc Loc,
173+
AvailabilitySet Availabilities,
174+
const DocComment &Comment,
175+
DeclarationFragments Declaration,
176+
DeclarationFragments SubHeading) {
177+
return addTopLevelRecord(ObjCProtocols, USR, Name, Loc,
178+
std::move(Availabilities), Comment, Declaration,
179+
SubHeading);
170180
}
171181

172182
MacroDefinitionRecord *
@@ -178,13 +188,13 @@ APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
178188

179189
TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
180190
PresumedLoc Loc,
181-
const AvailabilityInfo &Availability,
191+
AvailabilitySet Availabilities,
182192
const DocComment &Comment,
183193
DeclarationFragments Declaration,
184194
DeclarationFragments SubHeading,
185195
SymbolReference UnderlyingType) {
186-
return addTopLevelRecord(Typedefs, USR, Name, Loc, Availability, Comment,
187-
Declaration, SubHeading, UnderlyingType);
196+
return addTopLevelRecord(Typedefs, USR, Name, Loc, std::move(Availabilities),
197+
Comment, Declaration, SubHeading, UnderlyingType);
188198
}
189199

190200
StringRef APISet::recordUSR(const Decl *D) {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "clang/ExtractAPI/AvailabilityInfo.h"
2+
#include "clang/AST/Attr.h"
3+
#include "llvm/ADT/STLExtras.h"
4+
5+
using namespace clang;
6+
using namespace extractapi;
7+
8+
AvailabilitySet::AvailabilitySet(const Decl *Decl) {
9+
// Collect availability attributes from all redeclrations.
10+
for (const auto *RD : Decl->redecls()) {
11+
if (const auto *A = RD->getAttr<UnavailableAttr>()) {
12+
if (!A->isImplicit()) {
13+
this->Availabilities.clear();
14+
UnconditionallyUnavailable = true;
15+
}
16+
}
17+
18+
if (const auto *A = RD->getAttr<DeprecatedAttr>()) {
19+
if (!A->isImplicit()) {
20+
this->Availabilities.clear();
21+
UnconditionallyDeprecated = true;
22+
}
23+
}
24+
25+
for (const auto *Attr : RD->specific_attrs<AvailabilityAttr>()) {
26+
StringRef Domain = Attr->getPlatform()->getName();
27+
auto *Availability =
28+
llvm::find_if(Availabilities, [Domain](const AvailabilityInfo &Info) {
29+
return Domain.equals(Info.Domain);
30+
});
31+
if (Availability != Availabilities.end()) {
32+
// Get the highest introduced version for all redeclarations.
33+
if (Availability->Introduced < Attr->getIntroduced())
34+
Availability->Introduced = Attr->getIntroduced();
35+
36+
// Get the lowest deprecated version for all redeclarations.
37+
if (Availability->Deprecated > Attr->getDeprecated())
38+
Availability->Deprecated = Attr->getDeprecated();
39+
40+
// Get the lowest obsoleted version for all redeclarations.
41+
if (Availability->Obsoleted > Attr->getObsoleted())
42+
Availability->Obsoleted = Attr->getObsoleted();
43+
} else {
44+
Availabilities.emplace_back(Domain, Attr->getIntroduced(),
45+
Attr->getDeprecated(),
46+
Attr->getObsoleted());
47+
}
48+
}
49+
}
50+
}

clang/lib/ExtractAPI/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
44

55
add_clang_library(clangExtractAPI
66
API.cpp
7+
AvailabilityInfo.cpp
78
ExtractAPIConsumer.cpp
89
DeclarationFragments.cpp
910
Serialization/SerializerBase.cpp

0 commit comments

Comments
 (0)