Skip to content

Commit a320b6c

Browse files
committed
Clang importer: centralize the "suppress declaration import" logic.
The Swift name lookup tables and the complete Objective-C "container" to Swift DeclContext mapping code used similar-but-different logic to determine when to suppress a declaration (e.g., when suppressing the accessors for a property). Centralize the logic so we get the same behavior in both places.
1 parent 886b647 commit a320b6c

File tree

4 files changed

+72
-42
lines changed

4 files changed

+72
-42
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,6 +2984,27 @@ isAccessibilityConformingContext(const clang::DeclContext *ctx) {
29842984

29852985
}
29862986

2987+
/// Determine whether the given method potentially conflicts with the
2988+
/// setter for a property in the given protocol.
2989+
static bool
2990+
isPotentiallyConflictingSetter(const clang::ObjCProtocolDecl *proto,
2991+
const clang::ObjCMethodDecl *method) {
2992+
auto sel = method->getSelector();
2993+
if (sel.getNumArgs() != 1)
2994+
return false;
2995+
2996+
clang::IdentifierInfo *setterID = sel.getIdentifierInfoForSlot(0);
2997+
if (!setterID || !setterID->getName().startswith("set"))
2998+
return false;
2999+
3000+
for (auto *prop : proto->properties()) {
3001+
if (prop->getSetterName() == sel)
3002+
return true;
3003+
}
3004+
3005+
return false;
3006+
}
3007+
29873008
bool ClangImporter::Implementation::shouldSuppressDeclImport(
29883009
const clang::Decl *decl) {
29893010
if (auto objcMethod = dyn_cast<clang::ObjCMethodDecl>(decl)) {
@@ -2993,13 +3014,49 @@ bool ClangImporter::Implementation::shouldSuppressDeclImport(
29933014
//
29943015
// Note that this is suppressed for certain accessibility declarations,
29953016
// which are imported as getter/setter pairs and not properties.
2996-
return objcMethod->isPropertyAccessor() && !isAccessibilityDecl(objcMethod);
3017+
if (objcMethod->isPropertyAccessor()) {
3018+
// Suppress the import of this method when the corresponding
3019+
// property is not suppressed.
3020+
return !shouldSuppressDeclImport(
3021+
objcMethod->findPropertyDecl(/*checkOverrides=*/false));
3022+
}
3023+
3024+
// If the method was declared within a protocol, check that it
3025+
// does not conflict with the setter of a property.
3026+
if (auto proto = dyn_cast<clang::ObjCProtocolDecl>(decl->getDeclContext()))
3027+
return isPotentiallyConflictingSetter(proto, objcMethod);
3028+
3029+
return false;
29973030
}
29983031

29993032
if (auto objcProperty = dyn_cast<clang::ObjCPropertyDecl>(decl)) {
30003033
// Suppress certain accessibility properties; they're imported as
30013034
// getter/setter pairs instead.
3002-
return isAccessibilityDecl(objcProperty);
3035+
if (isAccessibilityDecl(objcProperty))
3036+
return true;
3037+
3038+
// Check whether there is a superclass method for the getter that
3039+
// is *not* suppressed, in which case we will need to suppress
3040+
// this property.
3041+
auto dc = objcProperty->getDeclContext();
3042+
auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(dc);
3043+
if (!objcClass) {
3044+
if (auto objcCategory = dyn_cast<clang::ObjCCategoryDecl>(dc))
3045+
objcClass = objcCategory->getClassInterface();
3046+
}
3047+
3048+
if (objcClass) {
3049+
if (auto objcSuperclass = objcClass->getSuperClass()) {
3050+
if (auto getterMethod
3051+
= objcSuperclass->lookupInstanceMethod(
3052+
objcProperty->getGetterName())) {
3053+
if (!shouldSuppressDeclImport(getterMethod))
3054+
return true;
3055+
}
3056+
}
3057+
}
3058+
3059+
return false;
30033060
}
30043061

30053062
return false;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4197,25 +4197,6 @@ namespace {
41974197
}
41984198
}
41994199

4200-
static bool
4201-
isPotentiallyConflictingSetter(const clang::ObjCProtocolDecl *proto,
4202-
const clang::ObjCMethodDecl *method) {
4203-
auto sel = method->getSelector();
4204-
if (sel.getNumArgs() != 1)
4205-
return false;
4206-
4207-
clang::IdentifierInfo *setterID = sel.getIdentifierInfoForSlot(0);
4208-
if (!setterID || !setterID->getName().startswith("set"))
4209-
return false;
4210-
4211-
for (auto *prop : proto->properties()) {
4212-
if (prop->getSetterName() == sel)
4213-
return true;
4214-
}
4215-
4216-
return false;
4217-
}
4218-
42194200
/// Import members of the given Objective-C container and add them to the
42204201
/// list of corresponding Swift members.
42214202
void importObjCMembers(const clang::ObjCContainerDecl *decl,
@@ -4251,27 +4232,9 @@ namespace {
42514232
members.push_back(alternate);
42524233
}
42534234

4254-
// Import explicit properties as instance properties, not as separate
4255-
// getter and setter methods.
4256-
if (!Impl.isAccessibilityDecl(objcMethod)) {
4257-
// If this member is a method that is a getter or setter for a
4258-
// propertythat was imported, don't add it to the list of members
4259-
// so it won't be found by name lookup. This eliminates the
4260-
// ambiguity between property names and getter names (by choosing
4261-
// to only have a variable).
4262-
if (objcMethod->isPropertyAccessor()) {
4263-
auto prop = objcMethod->findPropertyDecl(/*checkOverrides=*/false);
4264-
assert(prop);
4265-
(void)Impl.importDecl(const_cast<clang::ObjCPropertyDecl *>(prop));
4266-
// We may have attached this member to an existing property even
4267-
// if we've failed to import a new property.
4268-
if (cast<FuncDecl>(member)->isAccessor())
4269-
continue;
4270-
} else if (auto *proto = dyn_cast<clang::ObjCProtocolDecl>(decl)) {
4271-
if (isPotentiallyConflictingSetter(proto, objcMethod))
4272-
continue;
4273-
}
4274-
}
4235+
// If this declaration shouldn't be visible, don't add it to
4236+
// the list.
4237+
if (Impl.shouldSuppressDeclImport(objcMethod)) continue;
42754238
}
42764239

42774240
members.push_back(member);

test/IDE/Inputs/swift_name_objc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ SWIFT_NAME(SomeProtocol)
4545
@end
4646

4747
@protocol SNCollision
48+
@property (readonly,nonnull) id reqSetter;
49+
- (void)setReqSetter:(nonnull id)bar;
50+
51+
@property (readonly,nonnull) id optSetter;
52+
@optional
53+
- (void)setOptSetter:(nonnull id)bar;
4854
@end
4955

5056
@protocol NSAccessibility

test/IDE/dump_swift_lookup_tables_objc.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@
7171
// CHECK-NEXT: NSErrorImports: -[NSErrorImports methodWithFloat:error:]
7272
// CHECK-NEXT: objectAtIndexedSubscript:
7373
// CHECK-NEXT: SNSomeClass: -[SNSomeClass objectAtIndexedSubscript:]
74+
// CHECK-NEXT: optSetter:
75+
// CHECK-NEXT: SNCollision: SNCollision.optSetter
7476
// CHECK-NEXT: protoInstanceMethodWithX:
7577
// CHECK-NEXT: SNSomeProtocol: -[SNSomeProtocol protoInstanceMethodWithX:y:]
78+
// CHECK-NEXT: reqSetter:
79+
// CHECK-NEXT: SNCollision: SNCollision.reqSetter
7680
// CHECK-NEXT: setAccessibilityFloat:
7781
// CHECK-NEXT: NSAccessibility: -[NSAccessibility setAccessibilityFloat:]
7882
// CHECK-NEXT: subscript:

0 commit comments

Comments
 (0)