Skip to content

Commit 318da9d

Browse files
committed
Import ObjC forward declarations by default
1 parent 5a7963f commit 318da9d

15 files changed

+267
-11
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ namespace swift {
785785

786786
/// If true, forward declarations will be imported using unavailable types
787787
/// instead of dropped altogether when possible.
788-
bool ImportForwardDeclarations = false;
788+
bool ImportForwardDeclarations = true;
789789

790790
/// If true ignore the swift bridged attribute.
791791
bool DisableSwiftBridgeAttr = false;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ def enable_experimental_eager_clang_module_diagnostics :
304304
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
305305
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;
306306

307+
def no_import_objc_forward_declarations :
308+
Flag<["-"], "no-import-objc-forward-declarations">,
309+
HelpText<"Do not attempt to import Objective-C forward declarations">;
310+
307311
def enable_experimental_pairwise_build_block :
308312
Flag<["-"], "enable-experimental-pairwise-build-block">,
309313
HelpText<"Enable experimental pairwise 'buildBlock' for result builders">;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4393,9 +4393,35 @@ namespace {
43934393
clangModule))
43944394
return native;
43954395

4396-
Impl.addImportDiagnostic(
4397-
decl, Diagnostic(diag::forward_declared_protocol_label, decl),
4398-
decl->getSourceRange().getBegin());
4396+
if (Impl.ImportForwardDeclarations) {
4397+
auto result = Impl.createDeclWithClangNode<ProtocolDecl>(
4398+
decl, AccessLevel::Public,
4399+
Impl.getClangModuleForDecl(decl->getCanonicalDecl(),
4400+
/*allowForwardDeclaration=*/true),
4401+
SourceLoc(), SourceLoc(), name,
4402+
ArrayRef<PrimaryAssociatedTypeName>(), None,
4403+
/*TrailingWhere=*/nullptr);
4404+
4405+
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4406+
result->setSuperclass(Impl.getNSObjectProtocolType());
4407+
result->setAddedImplicitInitializers(); // suppress all initializers
4408+
addObjCAttribute(result,
4409+
Impl.importIdentifier(decl->getIdentifier()));
4410+
SmallVector<InheritedEntry, 4> inheritedTypes = {
4411+
TypeLoc::withoutLoc(Impl.getNSObjectProtocolType())};
4412+
result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
4413+
result->setImplicit();
4414+
auto attr = AvailableAttr::createPlatformAgnostic(
4415+
Impl.SwiftContext,
4416+
"This Objective-C protocol has only been forward-declared; "
4417+
"import its owning module to use it");
4418+
result->getAttrs().add(attr);
4419+
return result;
4420+
} else {
4421+
Impl.addImportDiagnostic(
4422+
decl, Diagnostic(diag::forward_declared_protocol_label, decl),
4423+
decl->getSourceRange().getBegin());
4424+
}
43994425

44004426
forwardDeclaration = true;
44014427
return nullptr;
@@ -4464,7 +4490,7 @@ namespace {
44644490
nullptr, dc,
44654491
/*isActor*/false);
44664492
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4467-
result->setSuperclass(Type());
4493+
result->setSuperclass(Impl.getNSObjectType());
44684494
result->setAddedImplicitInitializers(); // suppress all initializers
44694495
result->setHasMissingVTableEntries(false);
44704496
addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier()));

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,9 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,
12721272
}
12731273

12741274
Opts.DumpClangDiagnostics |= Args.hasArg(OPT_dump_clang_diagnostics);
1275+
if (Args.hasArg(OPT_no_import_objc_forward_declarations)) {
1276+
Opts.ImportForwardDeclarations = false;
1277+
}
12751278

12761279
if (Args.hasArg(OPT_embed_bitcode))
12771280
Opts.Mode = ClangImporterOptions::Modes::EmbedBitcode;

test/APINotes/versioned-objc.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 5 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-5 %s
4-
// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s
3+
// RUN: not %target-swift-frontend -no-import-objc-forward-declarations -typecheck -F %S/Inputs/custom-frameworks -swift-version 5 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-5 %s
4+
// RUN: not %target-swift-frontend -no-import-objc-forward-declarations -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s
55

66
// REQUIRES: objc_interop
77

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@class ForwardDeclaredInterface;
4+
@protocol ForwardDeclaredProtocol;
5+
6+
@interface Bar : NSObject
7+
@property id<ForwardDeclaredProtocol> propertyUsingAForwardDeclaredProtocol;
8+
@property ForwardDeclaredInterface *propertyUsingAForwardDeclaredInterface;
9+
- (id)init;
10+
- (NSObject<ForwardDeclaredProtocol> *)methodReturningForwardDeclaredProtocol;
11+
- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface;
12+
- (void)methodTakingAForwardDeclaredProtocolAsAParameter:
13+
(id<ForwardDeclaredProtocol>)param1;
14+
- (void)methodTakingAForwardDeclaredInterfaceAsAParameter:
15+
(ForwardDeclaredInterface *)param1
16+
andAnother:
17+
(ForwardDeclaredInterface *)
18+
param2;
19+
@end
20+
21+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface();
22+
void CFunctionTakingAForwardDeclaredInterfaceAsAParameter(
23+
ForwardDeclaredInterface *param1);
24+
25+
NSObject<ForwardDeclaredProtocol> *CFunctionReturningAForwardDeclaredProtocol();
26+
void CFunctionTakingAForwardDeclaredProtocolAsAParameter(
27+
id<ForwardDeclaredProtocol> param1);
28+
29+
@interface CompleteInterface : NSObject
30+
- (id)init;
31+
- (void)doSomethingOnlyCompleteInterfaceChildrenCan;
32+
@end
33+
@protocol CompleteProtocol
34+
- (void)doSomethingOnlyCompleteProtocolConformersCan;
35+
@end
36+
37+
@interface Foo : NSObject
38+
@property id<CompleteProtocol> propertyUsingACompleteProtocol;
39+
@property CompleteInterface *propertyUsingACompleteInterface;
40+
- (NSObject<CompleteProtocol> *)methodReturningCompleteProtocol;
41+
- (CompleteInterface *)methodReturningCompleteInterface;
42+
- (void)methodTakingACompleteProtocolAsAParameter:(id<CompleteProtocol>)param1;
43+
- (void)methodTakingACompleteInterfaceAsAParameter:(CompleteInterface *)param1
44+
andAnother:(CompleteInterface *)param2;
45+
@end
46+
47+
CompleteInterface *CFunctionReturningACompleteInterface();
48+
void CFunctionTakingACompleteInterfaceAsAParameter(CompleteInterface *param1);
49+
50+
NSObject<CompleteProtocol> *CFunctionReturningACompleteProtocol();
51+
void CFunctionTakingACompleteProtocolAsAParameter(id<CompleteProtocol> param1);
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#import "forward-declarations.h"
2+
3+
@interface ForwardDeclaredInterface : NSObject
4+
- (id)init;
5+
- (void)doSomething;
6+
@end
7+
8+
@implementation ForwardDeclaredInterface
9+
- (id)init {
10+
return [super init];
11+
}
12+
- (void)doSomething {
13+
NSLog(@"ForwardDeclaredInterface doing something!");
14+
}
15+
@end
16+
17+
@protocol ForwardDeclaredProtocol
18+
- (void)doSomethingElse;
19+
@end
20+
21+
@interface TypeConformingToForwardDeclaredProtocol
22+
: NSObject <ForwardDeclaredProtocol>
23+
- (id)init;
24+
- (void)doSomethingElse;
25+
@end
26+
27+
@implementation TypeConformingToForwardDeclaredProtocol
28+
- (id)init {
29+
return [super init];
30+
}
31+
- (void)doSomethingElse {
32+
NSLog(@"ForwardDeclaredProtocol doing something else!");
33+
}
34+
@end
35+
36+
@implementation Bar
37+
- (id)init {
38+
return [super init];
39+
}
40+
- (NSObject<ForwardDeclaredProtocol> *)methodReturningForwardDeclaredProtocol {
41+
return [[TypeConformingToForwardDeclaredProtocol alloc] init];
42+
}
43+
- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface {
44+
return [[ForwardDeclaredInterface alloc] init];
45+
}
46+
- (void)methodTakingAForwardDeclaredProtocolAsAParameter:
47+
(id<ForwardDeclaredProtocol>)param1 {
48+
[param1 doSomethingElse];
49+
}
50+
- (void)methodTakingAForwardDeclaredInterfaceAsAParameter:
51+
(ForwardDeclaredInterface *)param1
52+
andAnother:
53+
(ForwardDeclaredInterface *)
54+
param2 {
55+
[param1 doSomething];
56+
[param2 doSomething];
57+
}
58+
@end
59+
60+
// TODO: Remove all Complete stuff that isn't strictly required, mostly we are
61+
// writting tests against the header
62+
63+
@interface TypeConformingToCompleteProtocol : NSObject <CompleteProtocol>
64+
- (id)init;
65+
- (void)doSomethingOnlyCompleteProtocolConformersCan;
66+
@end
67+
68+
@implementation TypeConformingToCompleteProtocol
69+
- (id)init {
70+
return [super init];
71+
}
72+
- (void)doSomethingOnlyCompleteProtocolConformersCan {
73+
NSLog(@"Doing something only complete protocol conformers can!");
74+
}
75+
@end
76+
77+
@implementation CompleteInterface
78+
- (id)init {
79+
return [super init];
80+
}
81+
- (void)doSomethingOnlyCompleteInterfaceChildrenCan {
82+
NSLog(@"Doing something only complete interface children can!");
83+
}
84+
@end
85+
86+
@implementation Foo
87+
- (NSObject<CompleteProtocol> *)methodReturningCompleteProtocol {
88+
return [[TypeConformingToCompleteProtocol alloc] init];
89+
}
90+
- (CompleteInterface *)methodReturningCompleteInterface {
91+
return [[CompleteInterface alloc] init];
92+
}
93+
- (void)methodTakingACompleteProtocolAsAParameter:(id<CompleteProtocol>)param1 {
94+
[param1 doSomethingOnlyCompleteProtocolConformersCan];
95+
}
96+
- (void)methodTakingACompleteInterfaceAsAParameter:(CompleteInterface *)param1
97+
andAnother:(CompleteInterface *)param2 {
98+
[param1 doSomethingOnlyCompleteInterfaceChildrenCan];
99+
[param2 doSomethingOnlyCompleteInterfaceChildrenCan];
100+
}
101+
@end
102+
103+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface() {
104+
return [[ForwardDeclaredInterface alloc] init];
105+
}
106+
107+
void CFunctionTakingAForwardDeclaredInterfaceAsAParameter(
108+
ForwardDeclaredInterface *param1) {
109+
[param1 doSomething];
110+
}
111+
112+
NSObject<ForwardDeclaredProtocol> *
113+
CFunctionReturningAForwardDeclaredProtocol() {
114+
return [[TypeConformingToForwardDeclaredProtocol alloc] init];
115+
}
116+
117+
void CFunctionTakingAForwardDeclaredProtocolAsAParameter(
118+
id<ForwardDeclaredProtocol> param1) {
119+
[param1 doSomethingElse];
120+
}
121+
122+
CompleteInterface *CFunctionReturningACompleteInterface() {
123+
return [[CompleteInterface alloc] init];
124+
}
125+
126+
void CFunctionTakingACompleteInterfaceAsAParameter(CompleteInterface *param1) {
127+
[param1 doSomethingOnlyCompleteInterfaceChildrenCan];
128+
}
129+
130+
NSObject<CompleteProtocol> *CFunctionReturningACompleteProtocol() {
131+
return [[TypeConformingToCompleteProtocol alloc] init];
132+
}
133+
134+
void CFunctionTakingACompleteProtocolAsAParameter(id<CompleteProtocol> param1) {
135+
[param1 doSomethingOnlyCompleteProtocolConformersCan];
136+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module ForwardDeclarations {
2+
header "forward-declarations.h"
3+
}

test/ClangImporter/experimental_clang_importer_diagnostics_bridging_header.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend -enable-objc-interop -import-objc-header %S/Inputs/experimental_clang_importer_diagnostics_bridging_header.h -typecheck %s 2>&1 | %FileCheck %s
1+
// RUN: not %target-swift-frontend -no-import-objc-forward-declarations -enable-objc-interop -import-objc-header %S/Inputs/experimental_clang_importer_diagnostics_bridging_header.h -typecheck %s 2>&1 | %FileCheck %s
22

33
let s: PartialImport
44
s.c = 5

test/ClangImporter/experimental_diagnostics_incomplete_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

test/ClangImporter/experimental_diagnostics_no_noise.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

test/ClangImporter/experimental_diagnostics_opt_out.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -disable-experimental-clang-importer-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -no-import-objc-forward-declarations -disable-experimental-clang-importer-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

33
// REQUIRES: objc_interop
44

test/ClangImporter/experimental_eager_diagnostics.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-eager-clang-module-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace
22

3+
// XFAIL: *
4+
35
// REQUIRES: objc_interop
46

57
import cfuncs
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-clang %S/Inputs/custom-modules/ForwardDeclarations/forward-declarations.m -c -o %t/forward-declarations.o
3+
// RUN: %target-build-swift -I %S/Inputs/custom-modules/ForwardDeclarations %s -Xlinker -framework -Xlinker Foundation -Xlinker %t/forward-declarations.o -o %t/a.out
4+
// RUN: %target-run %t/a.out 2>&1 | %FileCheck %s
5+
6+
// REQUIRES: executable_test
7+
// REQUIRES: OS=macosx
8+
9+
import ForwardDeclarations
10+
11+
// Interfaces
12+
let bar = Bar()!
13+
let a = bar.methodReturningForwardDeclaredInterface()!
14+
// CHECK: ForwardDeclaredInterface doing something!
15+
// CHECK: ForwardDeclaredInterface doing something!
16+
bar.methodTakingAForwardDeclaredInterface(asAParameter: a, andAnother: a)
17+
bar.propertyUsingAForwardDeclaredInterface = a
18+
_ = CFunctionReturningAForwardDeclaredInterface()
19+
// CHECK: ForwardDeclaredInterface doing something!
20+
CFunctionTakingAForwardDeclaredInterfaceAsAParameter(a)
21+
22+
// Protocols
23+
let b = bar.methodReturningForwardDeclaredProtocol()!
24+
// CHECK: ForwardDeclaredProtocol doing something else!
25+
bar.methodTakingAForwardDeclaredProtocol(asAParameter: b)
26+
bar.propertyUsingAForwardDeclaredProtocol = b
27+
_ = CFunctionReturningAForwardDeclaredProtocol()
28+
// CHECK: ForwardDeclaredProtocol doing something else!
29+
CFunctionTakingAForwardDeclaredProtocolAsAParameter(b)

test/IDE/print_clang_ObjectiveC.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// XFAIL: *
2+
13
// RUN: %empty-directory(%t)
24

35
// RUN: %target-swift-ide-test -print-module -source-filename %s -module-to-print=ObjectiveC.NSObject -function-definitions=false > %t/ObjectiveC.NSObject.printed.txt

0 commit comments

Comments
 (0)