mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ClangImporter] Don't import compatibility methods named 'print'. (#10928)
...because they make things harder for people trying to use
Swift.print. Before:
error: 'print' has been renamed to 'printDocument(_:)'
After:
error: use of 'print' nearly matches global function
'print(_:separator:terminator:)' in module 'Swift'
rather than instance method 'print(_:extra:)'
(This actually occurs with AppKit's NSDocument, so it's not just a
hypothetical concern.)
rdar://problem/32839733
This commit is contained in:
@@ -1868,6 +1868,23 @@ applyPropertyOwnership(VarDecl *prop,
|
||||
}
|
||||
}
|
||||
|
||||
/// Does this name refer to a method that might shadow Swift.print?
|
||||
///
|
||||
/// As a heuristic, methods that have a base name of 'print' but more than
|
||||
/// one argument are left alone. These can still shadow Swift.print but are
|
||||
/// less likely to be confused for it, at least.
|
||||
static bool isPrintLikeMethod(DeclName name, const DeclContext *dc) {
|
||||
if (!name || name.isSpecial() || name.isSimpleName())
|
||||
return false;
|
||||
if (name.getBaseIdentifier().str() != "print")
|
||||
return false;
|
||||
if (!dc->isTypeContext())
|
||||
return false;
|
||||
if (name.getArgumentNames().size() > 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
using MirroredMethodEntry =
|
||||
std::pair<const clang::ObjCMethodDecl*, ProtocolDecl*>;
|
||||
|
||||
@@ -3681,6 +3698,14 @@ namespace {
|
||||
if (forceClassMethod && decl->hasRelatedResultType())
|
||||
return nullptr;
|
||||
|
||||
// Hack: avoid importing methods named "print" that aren't available in
|
||||
// the current version of Swift. We'd rather just let the user use
|
||||
// Swift.print in that case.
|
||||
if (!isActiveSwiftVersion() &&
|
||||
isPrintLikeMethod(importedName.getDeclName(), dc)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add the implicit 'self' parameter patterns.
|
||||
bool isInstance = decl->isInstanceMethod() && !forceClassMethod;
|
||||
SmallVector<ParameterList *, 4> bodyParams;
|
||||
@@ -7114,15 +7139,10 @@ void ClangImporter::Implementation::importAttributes(
|
||||
// Hack: mark any method named "print" with less than two parameters as
|
||||
// warn_unqualified_access.
|
||||
if (auto MD = dyn_cast<FuncDecl>(MappedDecl)) {
|
||||
if (!MD->getName().empty() && MD->getName().str() == "print" &&
|
||||
MD->getDeclContext()->isTypeContext()) {
|
||||
auto *formalParams = MD->getParameterList(1);
|
||||
if (formalParams->size() <= 1) {
|
||||
if (isPrintLikeMethod(MD->getFullName(), MD->getDeclContext())) {
|
||||
// Use a non-implicit attribute so it shows up in the generated
|
||||
// interface.
|
||||
MD->getAttrs().add(
|
||||
new (C) WarnUnqualifiedAccessAttr(/*implicit*/false));
|
||||
}
|
||||
MD->getAttrs().add(new (C) WarnUnqualifiedAccessAttr(/*implicit*/false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,31 @@ Name: APINotesFrameworkTest
|
||||
Classes:
|
||||
- Name: A
|
||||
SwiftObjCMembers: true
|
||||
- Name: PrintingInterference
|
||||
Methods:
|
||||
- Selector: 'print:'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'printDocument(_:)'
|
||||
- Name: PrintingRenamed
|
||||
Methods:
|
||||
- Selector: 'print'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'printDocument()'
|
||||
- Selector: 'print:'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'printDocument(_:)'
|
||||
- Selector: 'print:options:'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'printDocument(_:options:)'
|
||||
- Selector: 'print'
|
||||
MethodKind: Class
|
||||
SwiftName: 'printDocument()'
|
||||
- Selector: 'print:'
|
||||
MethodKind: Class
|
||||
SwiftName: 'printDocument(_:)'
|
||||
- Selector: 'print:options:'
|
||||
MethodKind: Class
|
||||
SwiftName: 'printDocument(_:options:)'
|
||||
- Name: TestProperties
|
||||
Properties:
|
||||
- Name: accessorsOnly
|
||||
@@ -43,6 +68,31 @@ Tags:
|
||||
SwiftVersions:
|
||||
- Version: 3.0
|
||||
Classes:
|
||||
- Name: PrintingInterference
|
||||
Methods:
|
||||
- Selector: 'print:'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'print(_:)'
|
||||
- Name: PrintingRenamed
|
||||
Methods:
|
||||
- Selector: 'print'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'print()'
|
||||
- Selector: 'print:'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'print(_:)'
|
||||
- Selector: 'print:options:'
|
||||
MethodKind: Instance
|
||||
SwiftName: 'print(_:options:)'
|
||||
- Selector: 'print'
|
||||
MethodKind: Class
|
||||
SwiftName: 'print()'
|
||||
- Selector: 'print:'
|
||||
MethodKind: Class
|
||||
SwiftName: 'print(_:)'
|
||||
- Selector: 'print:options:'
|
||||
MethodKind: Class
|
||||
SwiftName: 'print(_:options:)'
|
||||
- Name: TestProperties
|
||||
Methods:
|
||||
- Selector: accessorsOnlyRenamedRetyped
|
||||
|
||||
@@ -17,5 +17,20 @@
|
||||
@property (nullable) id importantInstanceProperty __attribute__((swift_name("finalInstanceProperty")));
|
||||
@end
|
||||
|
||||
@interface PrintingRenamed : Base
|
||||
- (void)print;
|
||||
- (void)print:(id)thing;
|
||||
- (void)print:(id)thing options:(id)options;
|
||||
|
||||
+ (void)print;
|
||||
+ (void)print:(id)thing;
|
||||
+ (void)print:(id)thing options:(id)options;
|
||||
@end
|
||||
|
||||
@interface PrintingInterference : Base
|
||||
- (void)print:(id)thing; // Only this one gets renamed.
|
||||
- (void)print:(id)thing extra:(id)options;
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
#endif // __OBJC__
|
||||
|
||||
@@ -140,4 +140,46 @@ func testRenamedProtocolMembers(obj: ProtoWithManyRenames) {
|
||||
// CHECK-DIAGS-4-NOT: :[[@LINE-1]]:{{[0-9]+}}:
|
||||
}
|
||||
|
||||
extension PrintingRenamed {
|
||||
func testDroppingRenamedPrints() {
|
||||
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: warning: use of 'print' treated as a reference to instance method
|
||||
print()
|
||||
// CHECK-DIAGS-4-NOT: [[@LINE-1]]:{{[0-9]+}}:
|
||||
|
||||
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: warning: use of 'print' treated as a reference to instance method
|
||||
print(self)
|
||||
// CHECK-DIAGS-4-NOT: [[@LINE-1]]:{{[0-9]+}}:
|
||||
|
||||
// CHECK-DIAGS-3-NOT: [[@LINE+1]]:{{[0-9]+}}:
|
||||
print(self, options: self)
|
||||
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: argument labels '(_:, options:)' do not match any available overloads
|
||||
}
|
||||
|
||||
static func testDroppingRenamedPrints() {
|
||||
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: warning: use of 'print' treated as a reference to class method
|
||||
print()
|
||||
// CHECK-DIAGS-4-NOT: [[@LINE-1]]:{{[0-9]+}}:
|
||||
|
||||
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: warning: use of 'print' treated as a reference to class method
|
||||
print(self)
|
||||
// CHECK-DIAGS-4-NOT: [[@LINE-1]]:{{[0-9]+}}:
|
||||
|
||||
// CHECK-DIAGS-3-NOT: [[@LINE+1]]:{{[0-9]+}}:
|
||||
print(self, options: self)
|
||||
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: argument labels '(_:, options:)' do not match any available overloads
|
||||
}
|
||||
}
|
||||
|
||||
extension PrintingInterference {
|
||||
func testDroppingRenamedPrints() {
|
||||
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: warning: use of 'print' treated as a reference to instance method
|
||||
print(self)
|
||||
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: use of 'print' nearly matches global function 'print(_:separator:terminator:)' in module 'Swift' rather than instance method 'print(_:extra:)'
|
||||
|
||||
// CHECK-DIAGS-3-NOT: [[@LINE+1]]:{{[0-9]+}}:
|
||||
print(self, extra: self)
|
||||
// CHECK-DIAGS-4-NOT: [[@LINE-1]]:{{[0-9]+}}:
|
||||
}
|
||||
}
|
||||
|
||||
let unrelatedDiagnostic: Int = nil
|
||||
|
||||
Reference in New Issue
Block a user