Skip to content

Commit be1a2c3

Browse files
authored
Merge pull request #14813 from nkcsgexi/digester-extension-reqs
2 parents 3229b6c + 1aa7816 commit be1a2c3

File tree

5 files changed

+167
-8
lines changed

5 files changed

+167
-8
lines changed

include/swift/IDE/DigesterEnums.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ KEY(declAttributes)
8989
KEY(declKind)
9090
KEY(ownership)
9191
KEY(superclassUsr)
92+
KEY(parentExtensionReqs)
9293

9394
KNOWN_TYPE(Optional)
9495
KNOWN_TYPE(ImplicitlyUnwrappedOptional)

test/api-digester/Inputs/cake.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@ public struct S1 {
77
public func foo6() -> Void {}
88
}
99

10-
public class C0 {}
10+
public class C0<T1, T2, T3> {}
1111

12-
public class C1: C0 {
12+
public class C1: C0<S1, S1, S1> {
1313
open class func foo1() {}
1414
public weak var Ins : C1?
1515
public unowned var Ins2 : C1 = C1()
1616
}
17+
18+
public extension C0 where T1 == S1, T2 == S1, T3 == S1 {
19+
func conditionalFooExt() {}
20+
}
21+
22+
public extension C0 {
23+
func unconditionalFooExt() {}
24+
}

test/api-digester/Outputs/cake.json

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,69 @@
1717
"name": "init",
1818
"printedName": "init()",
1919
"declKind": "Constructor",
20-
"usr": "s:4cake2C0CACycfc",
20+
"usr": "s:4cake2C0CACyxq_q0_Gycfc",
2121
"location": "",
2222
"moduleName": "cake",
2323
"children": [
2424
{
2525
"kind": "TypeNominal",
2626
"name": "C0",
27-
"printedName": "C0"
27+
"printedName": "C0<T1, T2, T3>",
28+
"children": [
29+
{
30+
"kind": "TypeNominal",
31+
"name": "GenericTypeParam",
32+
"printedName": "T1"
33+
},
34+
{
35+
"kind": "TypeNominal",
36+
"name": "GenericTypeParam",
37+
"printedName": "T2"
38+
},
39+
{
40+
"kind": "TypeNominal",
41+
"name": "GenericTypeParam",
42+
"printedName": "T3"
43+
}
44+
]
45+
}
46+
]
47+
},
48+
{
49+
"kind": "Function",
50+
"name": "conditionalFooExt",
51+
"printedName": "conditionalFooExt()",
52+
"declKind": "Func",
53+
"usr": "s:4cake2C0CA2A2S1VRszAERs_AERs0_rlE17conditionalFooExtyyF",
54+
"location": "",
55+
"moduleName": "cake",
56+
"parentExtensionReqs": [
57+
"T1 == cake.S1",
58+
"T2 == cake.S1",
59+
"T3 == cake.S1"
60+
],
61+
"children": [
62+
{
63+
"kind": "TypeNominal",
64+
"name": "Void",
65+
"printedName": "()"
66+
}
67+
]
68+
},
69+
{
70+
"kind": "Function",
71+
"name": "unconditionalFooExt",
72+
"printedName": "unconditionalFooExt()",
73+
"declKind": "Func",
74+
"usr": "s:4cake2C0C19unconditionalFooExtyyF",
75+
"location": "",
76+
"moduleName": "cake",
77+
"parentExtensionReqs": [],
78+
"children": [
79+
{
80+
"kind": "TypeNominal",
81+
"name": "Void",
82+
"printedName": "()"
2883
}
2984
]
3085
}

test/api-digester/dump-module.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
// RUN: %api-digester -dump-sdk -module cake -o %t.dump.json -module-cache-path %t.module-cache -sdk %t.sdk -swift-version 3 -I %t.mod
66
// RUN: diff -u %S/Outputs/cake.json %t.dump.json
77
// RUN: %api-digester -diagnose-sdk --input-paths %t.dump.json -input-paths %S/Outputs/cake.json
8+
9+
// Round-trip testing:
10+
// RUN: %api-digester -deserialize-sdk --input-paths %S/Outputs/cake.json -o %t.dump.json
11+
// RUN: diff -u %S/Outputs/cake.json %t.dump.json

tools/swift-api-digester/swift-api-digester.cpp

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ namespace {
6767
DumpSwiftModules,
6868
CompareSDKs,
6969
DiagnoseSDKs,
70+
// The following two are for testing purposes
7071
DeserializeDiffItems,
72+
DeserializeSDK,
7173
};
7274
} // end anonymous namespace
7375

@@ -135,7 +137,10 @@ Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None),
135137
"Diagnose SDK content in JSON file"),
136138
clEnumValN(ActionType::DeserializeDiffItems,
137139
"deserialize-diff",
138-
"Deserialize diff items in a JSON file")));
140+
"Deserialize diff items in a JSON file"),
141+
clEnumValN(ActionType::DeserializeSDK,
142+
"deserialize-sdk",
143+
"Deserialize sdk digester in a JSON file")));
139144

140145
static llvm::cl::list<std::string>
141146
SDKJsonPaths("input-paths",
@@ -287,6 +292,22 @@ static raw_ostream &operator<<(raw_ostream &Out, const DeclKind Value) {
287292
llvm_unreachable("Unhandled DeclKind in switch.");
288293
}
289294

295+
/// We don't dump individual extension declaration in the digester. However,
296+
/// we still want to detect whether an extension's applicability changes. Therefore,
297+
/// by using ParentExtensionInfo, we keep track of extension's information in
298+
/// each member of the extension.
299+
class ParentExtensionInfo {
300+
friend struct SDKNodeInitInfo;
301+
friend class SDKNode;
302+
std::vector<StringRef> Requirements;
303+
304+
void *operator new(size_t Bytes, SDKContext &C) {
305+
return C.allocator().Allocate<ParentExtensionInfo>();
306+
}
307+
public:
308+
ArrayRef<StringRef> getGenericRequirements() const { return Requirements; }
309+
};
310+
290311
struct SDKNodeInitInfo {
291312
SDKContext &Ctx;
292313
StringRef Name;
@@ -303,6 +324,8 @@ struct SDKNodeInitInfo {
303324
std::vector<SDKDeclAttrKind> DeclAttrs;
304325
std::vector<TypeAttrKind> TypeAttrs;
305326
StringRef SuperclassUsr;
327+
ParentExtensionInfo *ExtInfo = nullptr;
328+
306329
SDKNodeInitInfo(SDKContext &Ctx) : Ctx(Ctx) {}
307330
SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD);
308331
SDKNodeInitInfo(SDKContext &Ctx, Type Ty,
@@ -372,12 +395,15 @@ class SDKNodeDecl : public SDKNode {
372395
bool IsStatic;
373396
uint8_t Ownership;
374397
bool hasDeclAttribute(SDKDeclAttrKind DAKind) const;
398+
// Non-null ExtInfo implies this decl is defined in an type extension.
399+
ParentExtensionInfo *ExtInfo;
375400

376401
protected:
377402
SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind) : SDKNode(Info, Kind),
378403
DKind(Info.DKind), Usr(Info.USR), Location(Info.Location),
379404
ModuleName(Info.ModuleName), DeclAttributes(Info.DeclAttrs),
380-
IsStatic(Info.IsStatic), Ownership(uint8_t(Info.Ownership)) {}
405+
IsStatic(Info.IsStatic), Ownership(uint8_t(Info.Ownership)),
406+
ExtInfo(Info.ExtInfo) {}
381407

382408
public:
383409
StringRef getUsr() const { return Usr; }
@@ -395,6 +421,11 @@ class SDKNodeDecl : public SDKNode {
395421
bool isSDKPrivate() const;
396422
bool isDeprecated() const;
397423
bool isStatic() const { return IsStatic; };
424+
bool isFromExtension() const { return ExtInfo; }
425+
const ParentExtensionInfo& getExtensionInfo() const {
426+
assert(isFromExtension());
427+
return *ExtInfo;
428+
}
398429
};
399430

400431
StringRef SDKNodeDecl::getHeaderName() const {
@@ -893,6 +924,14 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx,
893924
cast<llvm::yaml::MappingNode>(&Mapping)));
894925
}
895926
break;
927+
case KeyKind::KK_parentExtensionReqs: {
928+
assert(!Info.ExtInfo);
929+
Info.ExtInfo = new (Ctx) ParentExtensionInfo();
930+
for (auto &Req : *cast<llvm::yaml::SequenceNode>(Pair.getValue())) {
931+
Info.ExtInfo->Requirements.push_back(GetScalarString(&Req));
932+
}
933+
break;
934+
}
896935
case KeyKind::KK_printedName:
897936
Info.PrintedName = GetScalarString(Pair.getValue());
898937
break;
@@ -1194,7 +1233,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) : Ctx(Ctx),
11941233
ModuleName(VD->getModuleContext()->getName().str()),
11951234
IsThrowing(isFuncThrowing(VD)), IsMutating(isFuncMutating(VD)),
11961235
IsStatic(VD->isStatic()), SelfIndex(getSelfIndex(VD)),
1197-
Ownership(getOwnership(VD)) {
1236+
Ownership(getOwnership(VD)), ExtInfo(nullptr) {
11981237

11991238
// Calculate usr for its super class.
12001239
if (auto *CD = dyn_cast_or_null<ClassDecl>(VD)) {
@@ -1203,6 +1242,18 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) : Ctx(Ctx),
12031242
}
12041243
if (VD->getAttrs().getDeprecated(VD->getASTContext()))
12051244
DeclAttrs.push_back(SDKDeclAttrKind::DAK_deprecated);
1245+
1246+
// If the decl is declared in an extension, calculate the extension info.
1247+
if (auto *Ext = dyn_cast_or_null<ExtensionDecl>(VD->getDeclContext())) {
1248+
ExtInfo = new (Ctx) ParentExtensionInfo();
1249+
// Print each generic requirement to the extension info.
1250+
for (auto Req: Ext->getGenericRequirements()) {
1251+
llvm::SmallString<32> Result;
1252+
llvm::raw_svector_ostream OS(Result);
1253+
Req.print(OS, PrintOptions::printInterface());
1254+
ExtInfo->Requirements.emplace_back(Ctx.buffer(OS.str()));
1255+
}
1256+
}
12061257
}
12071258

12081259
SDKNode *SDKNodeInitInfo::createSDKNode(SDKNodeKind Kind) {
@@ -1576,6 +1627,15 @@ namespace swift {
15761627
Super);
15771628
}
15781629
}
1630+
if (D->isFromExtension()) {
1631+
// Even if we don't have any requirements on this parent extension,
1632+
// we still want to have this key present to indicate the member
1633+
// is from an extension.
1634+
auto Reqs = D->getExtensionInfo().getGenericRequirements();
1635+
out.mapRequired(getKeyContent(Ctx,
1636+
KeyKind::KK_parentExtensionReqs).data(),
1637+
Reqs);
1638+
}
15791639
auto Attributes = D->getDeclAttributes();
15801640
if (!Attributes.empty())
15811641
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_declAttributes).data(),
@@ -1630,6 +1690,16 @@ namespace swift {
16301690
return const_cast<SDKDeclAttrKind&>(seq[index]);
16311691
}
16321692
};
1693+
template<>
1694+
struct ArrayTraits<ArrayRef<StringRef>> {
1695+
static size_t size(Output &out, ArrayRef<StringRef> &seq) {
1696+
return seq.size();
1697+
}
1698+
static StringRef& element(Output &, ArrayRef<StringRef> &seq,
1699+
size_t index) {
1700+
return const_cast<StringRef&>(seq[index]);
1701+
}
1702+
};
16331703
} // namespace json
16341704
} // namespace swift
16351705

@@ -3497,6 +3567,23 @@ static int deserializeDiffItems(StringRef DiffPath, StringRef OutputPath) {
34973567
return 0;
34983568
}
34993569

3570+
/// Mostly for testing purposes, this function de-serializes the SDK dump in
3571+
/// dumpPath and re-serialize them to OutputPath. If the tool performs correctly,
3572+
/// the contents in dumpPath and OutputPath should be identical.
3573+
static int deserializeSDKDump(StringRef dumpPath, StringRef OutputPath) {
3574+
std::error_code EC;
3575+
llvm::raw_fd_ostream FS(OutputPath, EC, llvm::sys::fs::F_None);
3576+
if (!fs::exists(dumpPath)) {
3577+
llvm::errs() << dumpPath << " does not exist\n";
3578+
return 1;
3579+
}
3580+
SDKContext Ctx;
3581+
SwiftDeclCollector Collector(Ctx);
3582+
Collector.deSerialize(dumpPath);
3583+
Collector.serialize(OutputPath);
3584+
return 0;
3585+
}
3586+
35003587
int main(int argc, char *argv[]) {
35013588
INITIALIZE_LLVM(argc, argv);
35023589

@@ -3532,12 +3619,16 @@ int main(int argc, char *argv[]) {
35323619
else
35333620
return diagnoseModuleChange(options::SDKJsonPaths[0],
35343621
options::SDKJsonPaths[1]);
3622+
case ActionType::DeserializeSDK:
35353623
case ActionType::DeserializeDiffItems: {
35363624
if (options::SDKJsonPaths.size() != 1) {
35373625
llvm::cl::PrintHelpMessage();
35383626
return 1;
35393627
}
3540-
return deserializeDiffItems(options::SDKJsonPaths[0], options::OutputFile);
3628+
if (options::Action == ActionType::DeserializeDiffItems)
3629+
return deserializeDiffItems(options::SDKJsonPaths[0], options::OutputFile);
3630+
else
3631+
return deserializeSDKDump(options::SDKJsonPaths[0], options::OutputFile);
35413632
}
35423633
case ActionType::None:
35433634
llvm::errs() << "Action required\n";

0 commit comments

Comments
 (0)