Merge pull request #18125 from nkcsgexi/extension-from-other
diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift
index 4cf3846..34e9637 100644
--- a/test/api-digester/Inputs/cake.swift
+++ b/test/api-digester/Inputs/cake.swift
@@ -36,4 +36,8 @@
case one
}
-public func foo3(_ a: [Int: String]) {}
\ No newline at end of file
+public func foo3(_ a: [Int: String]) {}
+
+public extension Int {
+ public func foo() {}
+}
\ No newline at end of file
diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json
index 0f604de..628565a 100644
--- a/test/api-digester/Outputs/cake.json
+++ b/test/api-digester/Outputs/cake.json
@@ -655,6 +655,59 @@
]
}
]
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "Int",
+ "printedName": "Int",
+ "declKind": "Struct",
+ "usr": "s:Si",
+ "location": "",
+ "moduleName": "Swift",
+ "conformingProtocols": [
+ "Comparable",
+ "SignedInteger",
+ "_ExpressibleByBuiltinIntegerLiteral",
+ "BinaryInteger",
+ "LosslessStringConvertible",
+ "SignedNumeric",
+ "Numeric",
+ "CustomStringConvertible",
+ "Strideable",
+ "ExpressibleByIntegerLiteral",
+ "FixedWidthInteger",
+ "Decodable",
+ "Encodable",
+ "Hashable",
+ "Equatable",
+ "_HasCustomAnyHashableRepresentation",
+ "CustomReflectable",
+ "_CustomPlaygroundQuickLookable",
+ "MirrorPath",
+ "CVarArg"
+ ],
+ "declAttributes": [
+ "fixedLayout"
+ ],
+ "children": [
+ {
+ "kind": "Function",
+ "name": "foo",
+ "printedName": "foo()",
+ "declKind": "Func",
+ "usr": "s:Si4cakeE3fooyyF",
+ "location": "",
+ "moduleName": "cake",
+ "parentExtensionReqs": [],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 5ab3780..e8d3101 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -1564,17 +1564,37 @@
}
static void addMembersToRoot(SDKContext &Ctx, SDKNode *Root,
- IterableDeclContext *Context);
+ IterableDeclContext *Context,
+ std::set<ExtensionDecl*> &HandledExts);
-static SDKNode *constructTypeDeclNode(SDKContext &Ctx, NominalTypeDecl *NTD) {
+static SDKNode *constructTypeDeclNode(SDKContext &Ctx, NominalTypeDecl *NTD,
+ std::set<ExtensionDecl*> &HandledExts) {
auto TypeNode = SDKNodeInitInfo(Ctx, NTD).createSDKNode(SDKNodeKind::DeclType);
- addMembersToRoot(Ctx, TypeNode, NTD);
+ addMembersToRoot(Ctx, TypeNode, NTD, HandledExts);
for (auto Ext : NTD->getExtensions()) {
- addMembersToRoot(Ctx, TypeNode, Ext);
+ HandledExts.insert(Ext);
+ addMembersToRoot(Ctx, TypeNode, Ext, HandledExts);
}
return TypeNode;
}
+/// Create a node for stand-alone extensions. In the sdk dump, we don't have
+/// a specific node for extension. Members in extensions are inlined to the
+/// extended types. If the extended types are from a different module, we have to
+/// synthesize this type node to include those extension members, since these
+/// extension members are legit members of the module.
+static SDKNode *constructExternalExtensionNode(SDKContext &Ctx, SDKNode *Root,
+ ExtensionDecl *Ext,
+ std::set<ExtensionDecl*> &HandledExts) {
+ auto *TypeNode = SDKNodeInitInfo(Ctx,
+ Ext->getAsNominalTypeOrNominalTypeExtensionContext()).
+ createSDKNode(SDKNodeKind::DeclType);
+
+ // The members of the extension are the only members of this synthesized type.
+ addMembersToRoot(Ctx, TypeNode, Ext, HandledExts);
+ return TypeNode;
+}
+
static SDKNode *constructVarNode(SDKContext &Ctx, ValueDecl *VD) {
auto Var = SDKNodeInitInfo(Ctx, VD).createSDKNode(SDKNodeKind::DeclVar);
TypeInitInfo TypeInfo;
@@ -1597,7 +1617,8 @@
}
static void addMembersToRoot(SDKContext &Ctx, SDKNode *Root,
- IterableDeclContext *Context) {
+ IterableDeclContext *Context,
+ std::set<ExtensionDecl*> &HandledExts) {
for (auto *Member : Context->getMembers()) {
if (shouldIgnore(Member, Context->getDecl()))
continue;
@@ -1612,7 +1633,7 @@
} else if (auto EED = dyn_cast<EnumElementDecl>(Member)) {
Root->addChild(constructVarNode(Ctx, EED));
} else if (auto NTD = dyn_cast<NominalTypeDecl>(Member)) {
- Root->addChild(constructTypeDeclNode(Ctx, NTD));
+ Root->addChild(constructTypeDeclNode(Ctx, NTD, HandledExts));
}
}
}
@@ -1626,10 +1647,11 @@
SDKContext &Ctx;
std::vector<std::unique_ptr<llvm::MemoryBuffer>> OwnedBuffers;
SDKNode *RootNode;
- llvm::DenseSet<ValueDecl*> KnownDecls;
+ llvm::DenseSet<Decl*> KnownDecls;
// Collected and sorted after we get all of them.
std::vector<ValueDecl *> ClangMacros;
+ std::set<ExtensionDecl*> HandledExtensions;
public:
void visitAllRoots(SDKNodeVisitor &Visitor) {
SDKNode::preorderVisit(RootNode, Visitor);
@@ -1666,10 +1688,15 @@
public:
void lookupVisibleDecls(ArrayRef<ModuleDecl *> Modules) {
- for (auto M : Modules) {
+ for (auto M: Modules) {
llvm::SmallVector<Decl*, 512> Decls;
M->getDisplayDecls(Decls);
for (auto D : Decls) {
+ if (shouldIgnore(D, nullptr))
+ continue;
+ if (KnownDecls.count(D))
+ continue;
+ KnownDecls.insert(D);
if (auto VD = dyn_cast<ValueDecl>(D))
foundDecl(VD, DeclVisibilityKind::DynamicLookup);
}
@@ -1686,16 +1713,24 @@
for (auto *VD : ClangMacros)
processDecl(VD);
+
+ // For all known decls, collect those unhandled extensions and handle them
+ // separately.
+ for (auto *D: KnownDecls) {
+ if (auto *Ext = dyn_cast<ExtensionDecl>(D)) {
+ if (HandledExtensions.find(Ext) == HandledExtensions.end()) {
+ RootNode->addChild(constructExternalExtensionNode(Ctx, RootNode, Ext,
+ HandledExtensions));
+ }
+ }
+ }
}
void processDecl(ValueDecl *VD) {
- if (shouldIgnore(VD, nullptr))
- return;
-
if (auto FD = dyn_cast<FuncDecl>(VD)) {
RootNode->addChild(constructFunctionNode(Ctx, FD, SDKNodeKind::DeclFunction));
} else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) {
- RootNode->addChild(constructTypeDeclNode(Ctx, NTD));
+ RootNode->addChild(constructTypeDeclNode(Ctx, NTD, HandledExtensions));
}
if (auto VAD = dyn_cast<VarDecl>(VD)) {
RootNode->addChild(constructVarNode(Ctx, VAD));
@@ -1706,10 +1741,6 @@
}
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
- if (KnownDecls.count(VD))
- return;
- KnownDecls.insert(VD);
-
if (VD->getClangMacro()) {
// Collect macros, we will sort them afterwards.
ClangMacros.push_back(VD);