Skip to content

Commit 8037f87

Browse files
Nuri AmariNuriAmari
authored andcommitted
Import objc forward declarations
1 parent 1f3e159 commit 8037f87

22 files changed

+600
-220
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;

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2733,7 +2733,8 @@ static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
27332733
// Handle redeclarable Clang decls by checking each redeclaration.
27342734
bool IsTagDecl = isa<clang::TagDecl>(D);
27352735
if (!(IsTagDecl || isa<clang::FunctionDecl>(D) || isa<clang::VarDecl>(D) ||
2736-
isa<clang::TypedefNameDecl>(D) || isa<clang::NamespaceDecl>(D))) {
2736+
isa<clang::TypedefNameDecl>(D) || isa<clang::NamespaceDecl>(D) ||
2737+
isa<clang::ObjCInterfaceDecl>(D) || isa<clang::ObjCProtocolDecl>(D))) {
27372738
return false;
27382739
}
27392740

lib/ClangImporter/ImportDecl.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4393,12 +4393,33 @@ 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+
return result;
4415+
} else {
4416+
Impl.addImportDiagnostic(
4417+
decl, Diagnostic(diag::forward_declared_protocol_label, decl),
4418+
decl->getSourceRange().getBegin());
43994419

4400-
forwardDeclaration = true;
4401-
return nullptr;
4420+
forwardDeclaration = true;
4421+
return nullptr;
4422+
}
44024423
}
44034424

44044425
decl = decl->getDefinition();
@@ -4464,7 +4485,7 @@ namespace {
44644485
nullptr, dc,
44654486
/*isActor*/false);
44664487
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4467-
result->setSuperclass(Type());
4488+
result->setSuperclass(Impl.getNSObjectType());
44684489
result->setAddedImplicitInitializers(); // suppress all initializers
44694490
result->setHasMissingVTableEntries(false);
44704491
addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier()));
@@ -4518,15 +4539,23 @@ namespace {
45184539
}
45194540

45204541
if (Impl.ImportForwardDeclarations) {
4521-
// Fake it by making an unavailable opaque @objc root class.
4522-
auto result = createFakeRootClass(name);
4542+
auto result = Impl.createDeclWithClangNode<ClassDecl>(
4543+
decl, AccessLevel::Public, SourceLoc(), name, SourceLoc(), None,
4544+
nullptr,
4545+
Impl.getClangModuleForDecl(decl->getCanonicalDecl(),
4546+
/*allowForwardDeclaration=*/true),
4547+
/*isActor*/ false);
4548+
Type superclassType = Impl.getNSObjectType();
4549+
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4550+
SmallVector<InheritedEntry, 4> inheritedTypes{
4551+
TypeLoc::withoutLoc(superclassType)};
4552+
result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
4553+
result->setSuperclass(superclassType);
4554+
result->setAddedImplicitInitializers(); // suppress all initializers
4555+
result->setHasMissingVTableEntries(false);
4556+
addObjCAttribute(result,
4557+
Impl.importIdentifier(decl->getIdentifier()));
45234558
result->setImplicit();
4524-
auto attr = AvailableAttr::createPlatformAgnostic(Impl.SwiftContext,
4525-
"This Objective-C class has only been forward-declared; "
4526-
"import its owning module to use it");
4527-
result->getAttrs().add(attr);
4528-
result->getAttrs().add(
4529-
new (Impl.SwiftContext) ForbidSerializingReferenceAttr(true));
45304559
return result;
45314560
} else {
45324561
Impl.addImportDiagnostic(
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: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#import "IncompleteTypes.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(@"TypeConformingToForwardDeclaredProtocol 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+
@interface TypeConformingToCompleteProtocol : NSObject <CompleteProtocol>
61+
- (id)init;
62+
- (void)doSomethingOnlyCompleteProtocolConformersCan;
63+
@end
64+
65+
@implementation TypeConformingToCompleteProtocol
66+
- (id)init {
67+
return [super init];
68+
}
69+
- (void)doSomethingOnlyCompleteProtocolConformersCan {
70+
NSLog(@"Doing something only complete protocol conformers can!");
71+
}
72+
@end
73+
74+
@implementation CompleteInterface
75+
- (id)init {
76+
return [super init];
77+
}
78+
- (void)doSomethingOnlyCompleteInterfaceChildrenCan {
79+
NSLog(@"Doing something only complete interface children can!");
80+
}
81+
@end
82+
83+
@implementation Foo
84+
- (NSObject<CompleteProtocol> *)methodReturningCompleteProtocol {
85+
return [[TypeConformingToCompleteProtocol alloc] init];
86+
}
87+
- (CompleteInterface *)methodReturningCompleteInterface {
88+
return [[CompleteInterface alloc] init];
89+
}
90+
- (void)methodTakingACompleteProtocolAsAParameter:(id<CompleteProtocol>)param1 {
91+
[param1 doSomethingOnlyCompleteProtocolConformersCan];
92+
}
93+
- (void)methodTakingACompleteInterfaceAsAParameter:(CompleteInterface *)param1
94+
andAnother:(CompleteInterface *)param2 {
95+
[param1 doSomethingOnlyCompleteInterfaceChildrenCan];
96+
[param2 doSomethingOnlyCompleteInterfaceChildrenCan];
97+
}
98+
@end
99+
100+
ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface() {
101+
return [[ForwardDeclaredInterface alloc] init];
102+
}
103+
104+
void CFunctionTakingAForwardDeclaredInterfaceAsAParameter(
105+
ForwardDeclaredInterface *param1) {
106+
[param1 doSomething];
107+
}
108+
109+
NSObject<ForwardDeclaredProtocol> *
110+
CFunctionReturningAForwardDeclaredProtocol() {
111+
return [[TypeConformingToForwardDeclaredProtocol alloc] init];
112+
}
113+
114+
void CFunctionTakingAForwardDeclaredProtocolAsAParameter(
115+
id<ForwardDeclaredProtocol> param1) {
116+
[param1 doSomethingElse];
117+
}
118+
119+
CompleteInterface *CFunctionReturningACompleteInterface() {
120+
return [[CompleteInterface alloc] init];
121+
}
122+
123+
void CFunctionTakingACompleteInterfaceAsAParameter(CompleteInterface *param1) {
124+
[param1 doSomethingOnlyCompleteInterfaceChildrenCan];
125+
}
126+
127+
NSObject<CompleteProtocol> *CFunctionReturningACompleteProtocol() {
128+
return [[TypeConformingToCompleteProtocol alloc] init];
129+
}
130+
131+
void CFunctionTakingACompleteProtocolAsAParameter(id<CompleteProtocol> param1) {
132+
[param1 doSomethingOnlyCompleteProtocolConformersCan];
133+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@class Foo;
4+
5+
@interface Consumer1 : NSObject
6+
@property(strong) Foo *propertyUsingAFoo;
7+
- (Consumer1 *)init;
8+
- (Foo *)methodReturningAFoo1;
9+
- (void)methodTakingAFoo1:(Foo *)foo;
10+
@end
11+
12+
Foo *CFunctionReturningAFoo1();
13+
void CFunctionTakingAFoo1(Foo *foo);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#import "foo-bar-consumer-1.h"
2+
#import "foo-bar.h"
3+
4+
@implementation Consumer1
5+
- (id)init {
6+
if (self = [super init]) {
7+
return self;
8+
} else
9+
return nil;
10+
}
11+
- (Foo *)methodReturningAFoo1 {
12+
Foo *foo = [[Foo alloc] init];
13+
[foo sayHelloFrom:@"methodReturningAFoo1"];
14+
return foo;
15+
}
16+
- (void)methodTakingAFoo1:(Foo *)foo {
17+
[foo sayHelloFrom:@"methodTakingAFoo1"];
18+
}
19+
@end
20+
21+
Foo *CFunctionReturningAFoo1() {
22+
Foo *foo = [[Foo alloc] init];
23+
[foo sayHelloFrom:@"CFunctionReturningAFoo1"];
24+
return foo;
25+
}
26+
void CFunctionTakingAFoo1(Foo *foo) {
27+
[foo sayHelloFrom:@"CFunctionTakingAFoo1"];
28+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@class Foo;
4+
5+
@interface Consumer2 : NSObject
6+
@property(strong) Foo *propertyUsingAFoo2;
7+
- (Consumer2 *)init;
8+
- (Foo *)methodReturningAFoo2;
9+
- (void)methodTakingAFoo2:(Foo *)foo;
10+
@end
11+
12+
Foo *CFunctionReturningAFoo2();
13+
void CFunctionTakingAFoo2(Foo *foo);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#import "foo-bar-consumer-2.h"
2+
#import "foo-bar.h"
3+
4+
@implementation Consumer2
5+
- (id)init {
6+
if (self = [super init]) {
7+
return self;
8+
} else
9+
return nil;
10+
}
11+
- (Foo *)methodReturningAFoo2 {
12+
Foo *foo = [[Foo alloc] init];
13+
[foo sayHelloFrom:@"methodReturningAFoo2"];
14+
return foo;
15+
}
16+
- (void)methodTakingAFoo2:(Foo *)foo {
17+
[foo sayHelloFrom:@"methodTakingAFoo2"];
18+
}
19+
@end
20+
21+
Foo *CFunctionReturningAFoo2() {
22+
Foo *foo = [[Foo alloc] init];
23+
[foo sayHelloFrom:@"CFunctionReturningAFoo2"];
24+
return foo;
25+
}
26+
void CFunctionTakingAFoo2(Foo *foo) {
27+
[foo sayHelloFrom:@"CFunctionTakingAFoo2"];
28+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface Foo : NSObject
4+
- (id)init;
5+
- (void)sayHello;
6+
- (void)sayHelloFrom:(NSString *)source;
7+
@end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#import "foo-bar.h"
2+
3+
@implementation Foo
4+
- (id)init {
5+
return [super init];
6+
}
7+
8+
- (void)sayHello {
9+
NSLog(@"Hello!");
10+
}
11+
12+
- (void)sayHelloFrom:(NSString *)source {
13+
NSLog(@"%@", [NSString stringWithFormat:@"Hello from %@", source]);
14+
}
15+
@end

0 commit comments

Comments
 (0)