Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions lib/IDE/ModuleInterfacePrinting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,6 @@ static bool printModuleInterfaceDecl(Decl *D,
Printer.callAvoidPrintDeclPost(D);
return false;
}
if (auto Ext = dyn_cast<ExtensionDecl>(D)) {
// Clang extensions (categories) are always printed in source order.
// Swift extensions are printed with their associated type unless it's
// a cross-module extension.
if (!extensionHasClangNode(Ext)) {
auto ExtendedNominal = Ext->getExtendedNominal();
if (!ExtendedNominal ||
Ext->getModuleContext() == ExtendedNominal->getModuleContext())
return false;
}
}

// It'd be nice to avoid cloning the options here, but that would require
// SynthesizedExtensionAnalyzer to promise to stay within the lifetime of
Expand Down Expand Up @@ -677,6 +666,14 @@ void swift::ide::printModuleInterface(
addToClangDecls(Ext, extensionGetClangNode(Ext));
continue;
}

// Swift extensions are printed with their associated type unless it's
// a cross-module extension.
if (auto extendedTy = Ext->getExtendedNominal()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a check in printModuleInterfaceDecl for extensions, which seems like dead code after this change? It currently skips printing extensions if they don't have a clang node and are part of the same module:

  if (auto Ext = dyn_cast<ExtensionDecl>(D)) {
    // Clang extensions (categories) are always printed in source order.
    // Swift extensions are printed with their associated type unless it's
    // a cross-module extension.
    if (!extensionHasClangNode(Ext)) {
      auto ExtendedNominal = Ext->getExtendedNominal();
      if (!ExtendedNominal ||
          Ext->getModuleContext() == ExtendedNominal->getModuleContext())
        return false;
    }
  }

Though that also means we're skipping more than before. Does this change prevent printing of categories for pure ObjC imports (no Swift)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I forgot to remove this condition which is not no-op and for ObjC categories - they are added to clang decls and would be printed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the old check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change prevent printing of categories for pure ObjC imports (no Swift)?

Note the check above this means we're only looking at Swift extensions specifically here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the check above this means we're only looking at Swift extensions specifically here

Which check 🤔?

Copy link
Contributor

@hamishknight hamishknight Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

      if (extensionHasClangNode(Ext)) {
        addToClangDecls(Ext, extensionGetClangNode(Ext));
        continue;
      }

if (TargetMod->isSameModuleLookingThroughOverlays(
extendedTy->getModuleContext()))
continue;
}
}

if (!IsSubmodule) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@interface MyType
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 6.2
// swift-module-flags: -target arm64-apple-macos10.13 -enable-library-evolution -swift-version 5 -module-name TestExt

@_exported import TestExt

extension MyType {
public struct MyInnerType {
public func test() {}
}
}

extension Int {
public struct OtherInnerType {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
framework module TestExt {
header "MyType.h"
export *
}
20 changes: 20 additions & 0 deletions test/SynthesizeInterfaceTool/test-swift-extension-printing.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %target-swift-synthesize-interface -module-name TestExt -F %S/Inputs/Frameworks -o - | %FileCheck %s

// REQUIRES: OS=macosx && CPU=arm64

// CHECK: open class MyType

// CHECK: extension MyType {
// CHECK: public struct MyInnerType {
// CHECK: public func test()
// CHECK: }
// CHECK: }

// CHECK-NOT: public struct MyInnerType

// CHECK: extension Int {
// CHECK: public struct OtherInnerType {
// CHECK: }
// CHECK: }

// CHECK-NOT: public struct MyInnerType