Skip to content

Commit 6da7ec3

Browse files
authored
Merge pull request swiftlang#29255 from CodaFi/categorical-denials
Nail Down The Emergent Behaviors of the ClangImporter's Override Checking
2 parents e4277da + e79281d commit 6da7ec3

File tree

6 files changed

+83
-1
lines changed

6 files changed

+83
-1
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3726,6 +3726,9 @@ void ClangImporter::Implementation::lookupAllObjCMembers(
37263726
// deserialized before loading the named member of this class. This allows the
37273727
// decl members table to be warmed up and enables the correct identification of
37283728
// overrides.
3729+
//
3730+
// FIXME: Very low hanging fruit: Loading everything is extremely wasteful. We
3731+
// should be able to just load the name lazy member loading is asking for.
37293732
static void ensureSuperclassMembersAreLoaded(const ClassDecl *CD) {
37303733
if (!CD)
37313734
return;
@@ -3735,6 +3738,9 @@ static void ensureSuperclassMembersAreLoaded(const ClassDecl *CD) {
37353738
return;
37363739

37373740
CD->loadAllMembers();
3741+
3742+
for (auto *ED : const_cast<ClassDecl *>(CD)->getExtensions())
3743+
ED->loadAllMembers();
37383744
}
37393745

37403746
Optional<TinyPtrVector<ValueDecl *>>

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8443,7 +8443,7 @@ createUnavailableDecl(Identifier name, DeclContext *dc, Type type,
84438443
// deserialized before loading the members of this class. This allows the
84448444
// decl members table to be warmed up and enables the correct identification of
84458445
// overrides.
8446-
static void loadAllMembersOfSuperclassIfNeeded(const ClassDecl *CD) {
8446+
static void loadAllMembersOfSuperclassIfNeeded(ClassDecl *CD) {
84478447
if (!CD)
84488448
return;
84498449

@@ -8452,6 +8452,9 @@ static void loadAllMembersOfSuperclassIfNeeded(const ClassDecl *CD) {
84528452
return;
84538453

84548454
CD->loadAllMembers();
8455+
8456+
for (auto E : CD->getExtensions())
8457+
E->loadAllMembers();
84558458
}
84568459

84578460
void
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
__attribute__((objc_root_class))
2+
@interface Base
3+
- (nonnull instancetype)init;
4+
@end
5+
6+
@interface MyColor : Base
7+
@property (class, nonatomic, readonly) MyColor *systemRedColor;
8+
@end
9+
10+
@interface MyBaseClass : Base
11+
// @property (nonatomic, strong, nullable) Base *derivedMember;
12+
@end
13+
14+
@interface MyDerivedClass : MyBaseClass
15+
@property (nonatomic, strong, nullable) Base *derivedMember;
16+
@end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework module CategoryOverrides {
2+
umbrella header "CategoryOverrides.h"
3+
module * {
4+
export *
5+
}
6+
exclude header "Private.h"
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#import <CategoryOverrides/CategoryOverrides.h>
2+
3+
@interface MyBaseClass ()
4+
@property (nonatomic, strong, nullable) Base *derivedMember;
5+
@end
6+
7+
@interface MyColor ()
8+
+ (MyColor * _Null_unspecified) systemRedColor;
9+
@end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck -F %S/Inputs/frameworks %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PUBLIC %s
2+
3+
// RUN: echo '#import <CategoryOverrides/Private.h>' > %t.h
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.h %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s --allow-empty
5+
6+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -emit-pch -F %S/Inputs/frameworks -o %t.pch %t.h
7+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.pch %s 2>&1 | %FileCheck --allow-empty -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s
8+
// RUNT: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck --allow-empty -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s
9+
10+
import CategoryOverrides
11+
12+
// Nail down some emergent behaviors of the Clang Importer's override checking:
13+
14+
15+
// A category declared in a (private) header can happen to double-import a property
16+
// and a function with the same name - both before and after omit-needless-words -
17+
// as long as they have different contextual types.
18+
//
19+
// This configuration appears as an undiagnosed redeclaration of a property and
20+
// function, which is illegal.
21+
func colors() {
22+
let _ : MyColor = MyColor.systemRed
23+
let _ : MyColor = MyColor.systemRed()!
24+
}
25+
26+
// A category declared in a (private) header can introduce overrides of a property
27+
// that is otherwise not declared in a base class.
28+
//
29+
// This configuration appears as an undiagnosed override in a Swift extension,
30+
// which is illegal.
31+
func takesADerivedClass(_ x: MyDerivedClass) {
32+
// CHECK-PUBLIC-NOT: has no member 'derivedMember'
33+
// CHECK-PRIVATE-NOT: has no member 'derivedMember'
34+
x.derivedMember = Base()
35+
}
36+
37+
func takesABaseClass(_ x: MyBaseClass) {
38+
// CHECK-PUBLIC: has no member 'derivedMember'
39+
// CHECK-PRIVATE-NOT: has no member 'derivedMember'
40+
x.derivedMember = Base()
41+
}

0 commit comments

Comments
 (0)