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 =
|
using MirroredMethodEntry =
|
||||||
std::pair<const clang::ObjCMethodDecl*, ProtocolDecl*>;
|
std::pair<const clang::ObjCMethodDecl*, ProtocolDecl*>;
|
||||||
|
|
||||||
@@ -3681,6 +3698,14 @@ namespace {
|
|||||||
if (forceClassMethod && decl->hasRelatedResultType())
|
if (forceClassMethod && decl->hasRelatedResultType())
|
||||||
return nullptr;
|
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.
|
// Add the implicit 'self' parameter patterns.
|
||||||
bool isInstance = decl->isInstanceMethod() && !forceClassMethod;
|
bool isInstance = decl->isInstanceMethod() && !forceClassMethod;
|
||||||
SmallVector<ParameterList *, 4> bodyParams;
|
SmallVector<ParameterList *, 4> bodyParams;
|
||||||
@@ -7114,15 +7139,10 @@ void ClangImporter::Implementation::importAttributes(
|
|||||||
// Hack: mark any method named "print" with less than two parameters as
|
// Hack: mark any method named "print" with less than two parameters as
|
||||||
// warn_unqualified_access.
|
// warn_unqualified_access.
|
||||||
if (auto MD = dyn_cast<FuncDecl>(MappedDecl)) {
|
if (auto MD = dyn_cast<FuncDecl>(MappedDecl)) {
|
||||||
if (!MD->getName().empty() && MD->getName().str() == "print" &&
|
if (isPrintLikeMethod(MD->getFullName(), MD->getDeclContext())) {
|
||||||
MD->getDeclContext()->isTypeContext()) {
|
// Use a non-implicit attribute so it shows up in the generated
|
||||||
auto *formalParams = MD->getParameterList(1);
|
// interface.
|
||||||
if (formalParams->size() <= 1) {
|
MD->getAttrs().add(new (C) WarnUnqualifiedAccessAttr(/*implicit*/false));
|
||||||
// Use a non-implicit attribute so it shows up in the generated
|
|
||||||
// interface.
|
|
||||||
MD->getAttrs().add(
|
|
||||||
new (C) WarnUnqualifiedAccessAttr(/*implicit*/false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,31 @@ Name: APINotesFrameworkTest
|
|||||||
Classes:
|
Classes:
|
||||||
- Name: A
|
- Name: A
|
||||||
SwiftObjCMembers: true
|
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
|
- Name: TestProperties
|
||||||
Properties:
|
Properties:
|
||||||
- Name: accessorsOnly
|
- Name: accessorsOnly
|
||||||
@@ -43,6 +68,31 @@ Tags:
|
|||||||
SwiftVersions:
|
SwiftVersions:
|
||||||
- Version: 3.0
|
- Version: 3.0
|
||||||
Classes:
|
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
|
- Name: TestProperties
|
||||||
Methods:
|
Methods:
|
||||||
- Selector: accessorsOnlyRenamedRetyped
|
- Selector: accessorsOnlyRenamedRetyped
|
||||||
|
|||||||
@@ -17,5 +17,20 @@
|
|||||||
@property (nullable) id importantInstanceProperty __attribute__((swift_name("finalInstanceProperty")));
|
@property (nullable) id importantInstanceProperty __attribute__((swift_name("finalInstanceProperty")));
|
||||||
@end
|
@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
|
#pragma clang assume_nonnull end
|
||||||
#endif // __OBJC__
|
#endif // __OBJC__
|
||||||
|
|||||||
@@ -140,4 +140,46 @@ func testRenamedProtocolMembers(obj: ProtoWithManyRenames) {
|
|||||||
// CHECK-DIAGS-4-NOT: :[[@LINE-1]]:{{[0-9]+}}:
|
// 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
|
let unrelatedDiagnostic: Int = nil
|
||||||
|
|||||||
Reference in New Issue
Block a user