Skip to content

Commit ccd7ca2

Browse files
bitjammerDave Abrahams
authored andcommitted
Allow make_decl_objc diagnostic note into the FixitApplyDiagnosticConsumer
This allows the migrator to pick up fix-its from notes such as: “Argument of #selector refers to instance method '___' that is not exposed to Objective-C” Add some more testing for minimal/complete workflows, and upstream the cross-file fix-it test. rdar://problem/32228948
1 parent 18ab2f8 commit ccd7ca2

12 files changed

+137
-11
lines changed

include/swift/Migrator/FixitApplyDiagnosticConsumer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/DiagnosticConsumer.h"
2121
#include "swift/Migrator/FixitFilter.h"
2222
#include "clang/Rewrite/Core/RewriteBuffer.h"
23+
#include "llvm/ADT/DenseSet.h"
2324

2425
namespace swift {
2526

@@ -45,6 +46,9 @@ class FixitApplyDiagnosticConsumer final
4546
/// determine whether to call `printResult`.
4647
unsigned NumFixitsApplied;
4748

49+
/// Tracks whether a SourceLoc already got an `@objc` insertion.
50+
llvm::SmallPtrSet<const void *, 32> AddedObjC;
51+
4852
public:
4953
FixitApplyDiagnosticConsumer(const StringRef Text,
5054
const StringRef BufferName);

include/swift/Migrator/FixitFilter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ struct FixitFilter {
127127
Info.ID == diag::objc_inference_swift3_objc_derived.ID ||
128128
Info.ID == diag::missing_several_cases.ID ||
129129
Info.ID == diag::missing_particular_case.ID ||
130-
Info.ID == diag::paren_void_probably_void.ID)
130+
Info.ID == diag::paren_void_probably_void.ID ||
131+
Info.ID == diag::make_decl_objc.ID ||
132+
Info.ID == diag::optional_req_nonobjc_near_match_add_objc.ID)
131133
return true;
132134

133135
return false;

lib/Migrator/FixitApplyDiagnosticConsumer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ handleDiagnostic(SourceManager &SM, SourceLoc Loc,
5656
ThisBufferID);
5757
auto Length = Fixit.getRange().getByteLength();
5858

59+
if (Fixit.getText().ltrim().rtrim() == "@objc") {
60+
if (AddedObjC.count(Loc.getOpaquePointerValue())) {
61+
return;
62+
} else {
63+
AddedObjC.insert(Loc.getOpaquePointerValue());
64+
}
65+
}
66+
5967
RewriteBuf.ReplaceText(Offset, Length, Fixit.getText());
6068
++NumFixitsApplied;
6169
}

test/Migrator/Inputs/minimal_objc_inference.swift renamed to test/Migrator/Inputs/objc_inference.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,16 @@ func test(object: AnyObject, mine: MyClass) {
2323
_ = #keyPath(MyClass.propertyUsedInKeyPath)
2424
_ = object.usedViaAnyObject?()
2525
}
26+
27+
class SelfReferences : NSObject {
28+
var prop: Int = 2
29+
func foo() {
30+
_ = #selector(self.foo)
31+
_ = #keyPath(prop)
32+
}
33+
34+
func bar() {
35+
_ = #selector(self.foo)
36+
_ = #selector(self.bar)
37+
}
38+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
3+
public class MyClass : NSObject {
4+
@objc public func methodUsedInSelector() {}
5+
@objc public var propertyUsedInKeyPath: Int { return 2 }
6+
@objc dynamic var dynamicVarUsedInSelector: Int { return 2 }
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public func test(object: AnyObject, mine: MyClass) {
2+
_ = #selector(MyClass.methodUsedInSelector)
3+
_ = #selector(getter: MyClass.dynamicVarUsedInSelector)
4+
_ = #keyPath(MyClass.propertyUsedInKeyPath)
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %target-swift-frontend -typecheck -swift-version 3 -enable-swift3-objc-inference %s
3+
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -primary-file %S/Inputs/objc_inference.swift -emit-migrated-file-path %t/complete_objc_inference.swift.result -emit-remap-file-path %t/complete_objc_inference.swift.remap -migrate-keep-objc-visibility -o /dev/null
4+
// RUN: diff -u %S/complete_objc_inference.swift.expected %t/complete_objc_inference.swift.result
5+
// RUN: %target-swift-frontend -typecheck -swift-version 4 -enable-swift3-objc-inference %t/complete_objc_inference.swift.result
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Foundation
2+
3+
class MyClass : NSObject {
4+
@objc var propertyUsedInKeyPath : NSObject? = nil
5+
@objc dynamic var dynamicVarUsedInSelector : Int { return 2 }
6+
@objc func overridden() {}
7+
@objc func usedViaAnyObject() {}
8+
@objc func unused() {}
9+
}
10+
11+
extension MyClass {
12+
@objc func inExtensionAndOverridden() {}
13+
}
14+
15+
class MySubClass : MyClass {
16+
override func overridden() {}
17+
override func inExtensionAndOverridden() {}
18+
}
19+
20+
func test(object: AnyObject, mine: MyClass) {
21+
_ = #selector(MyClass.overridden)
22+
_ = #selector(getter: MyClass.dynamicVarUsedInSelector)
23+
_ = #keyPath(MyClass.propertyUsedInKeyPath)
24+
_ = object.usedViaAnyObject?()
25+
}
26+
27+
class SelfReferences : NSObject {
28+
@objc var prop: Int = 2
29+
@objc func foo() {
30+
_ = #selector(self.foo)
31+
_ = #keyPath(prop)
32+
}
33+
34+
@objc func bar() {
35+
_ = #selector(self.foo)
36+
_ = #selector(self.bar)
37+
}
38+
}
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -primary-file %S/Inputs/minimal_objc_inference.swift -emit-migrated-file-path %t/migrated_minimal_objc_inference.swift -emit-remap-file-path %t/migrated_minimal_objc_inference.swift.remap -o /dev/null
2-
// RUN: %FileCheck %s < %t/migrated_minimal_objc_inference.swift
31
// REQUIRES: objc_interop
4-
5-
// CHECK-NOT: @objc var propertyUsedInKeyPath: NSObject? = nil
6-
// CHECK: @objc dynamic var dynamicVarUsedInSelector : Int { return 2 }
7-
// CHECK-NOT: @objc func overridden() {}
8-
// CHECK-NOT: @objc func usedViaAnyObject() {}
9-
// CHECK-NOT: @objc func inExtensionAndOverridden() {}
10-
// CHECK-NOT: @objc func unused() {}
11-
2+
// RUN: %target-swift-frontend -typecheck -swift-version 3 %s
3+
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -primary-file %S/Inputs/objc_inference.swift -emit-migrated-file-path %t/minimal_objc_inference.swift.result -emit-remap-file-path %t/minimal_objc_inference.swift.remap -o /dev/null
4+
// RUN: diff -u %S/minimal_objc_inference.swift.expected %t/minimal_objc_inference.swift.result
5+
// RUN: %target-swift-frontend -typecheck -swift-version 4 %t/minimal_objc_inference.swift.result
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Foundation
2+
3+
class MyClass : NSObject {
4+
@objc var propertyUsedInKeyPath : NSObject? = nil
5+
@objc dynamic var dynamicVarUsedInSelector : Int { return 2 }
6+
@objc func overridden() {}
7+
@objc func usedViaAnyObject() {}
8+
func unused() {}
9+
}
10+
11+
extension MyClass {
12+
@objc func inExtensionAndOverridden() {}
13+
}
14+
15+
class MySubClass : MyClass {
16+
override func overridden() {}
17+
override func inExtensionAndOverridden() {}
18+
}
19+
20+
func test(object: AnyObject, mine: MyClass) {
21+
_ = #selector(MyClass.overridden)
22+
_ = #selector(getter: MyClass.dynamicVarUsedInSelector)
23+
_ = #keyPath(MyClass.propertyUsedInKeyPath)
24+
_ = object.usedViaAnyObject?()
25+
}
26+
27+
class SelfReferences : NSObject {
28+
@objc var prop: Int = 2
29+
@objc func foo() {
30+
_ = #selector(self.foo)
31+
_ = #keyPath(prop)
32+
}
33+
34+
@objc func bar() {
35+
_ = #selector(self.foo)
36+
_ = #selector(self.bar)
37+
}
38+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %target-swift-frontend -typecheck -swift-version 3 -primary-file %S/Inputs/objc_inference_cross_file_A.swift %S/Inputs/objc_inference_cross_file_B.swift
3+
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -update-code -primary-file %S/Inputs/objc_inference_cross_file_A.swift %S/Inputs/objc_inference_cross_file_B.swift -emit-migrated-file-path %t/objc_inference_cross_file.swift.result -migrate-keep-objc-visibility -o /dev/null
4+
// RUN: diff -u %S/objc_inference_cross_file.swift.expected %t/objc_inference_cross_file.swift.result
5+
// RUN: %target-swift-frontend -typecheck -swift-version 4 -primary-file %t/objc_inference_cross_file.swift.result %S/Inputs/objc_inference_cross_file_B.swift
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
3+
public class MyClass : NSObject {
4+
@objc public func methodUsedInSelector() {}
5+
@objc public var propertyUsedInKeyPath: Int { return 2 }
6+
@objc dynamic var dynamicVarUsedInSelector: Int { return 2 }
7+
}

0 commit comments

Comments
 (0)