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);