Files
swift-mirror/test/SourceKit/CodeExpand/code-expand.swift
Alex Hoppen 865e80f9c4 [CodeComplete] Default parameter names of completed closure to internal names
If have a function that takes a trailing closure as follows
```
func sort(callback: (_ left: Int, _ right: Int) -> Bool) {}
```
completing a call to `sort` and expanding the trailing closure results in
```
sort { <#Int#>, <#Int#> in
  <#code#>
}
```

We should be doing a better job here and defaulting the trailing closure's to the internal names specified in the function signature. I.e. the final result should be
```
sort { left, right in
  <#code#>
}
```

This commit does exactly that.

Firstly, it keeps track of the closure's internal names (as specified in the declaration of `sort`) in the closure's type through a new `InternalLabel` property in `AnyFunctionType::Param`. Once the type containing the parameter gets canonicalized, the internal label is dropped.

Secondly, it adds a new option to `ASTPrinter` to always try and print parameter labels. With this option set to true, it will always print external paramter labels and, if they are present, print the internal parameter label as `_ <internalLabel>`.

Finally, we can use this new printing mode to print the trailing closure’s type as
```
<#T##callback: (Int, Int) -> Bool##(_ left: Int, _ right: Int) -> Bool#>
```

This is already correctly expanded by code-expand to the desired result. I also added a test case for that behaviour.
2021-04-01 19:14:19 +02:00

251 lines
6.3 KiB
Swift

// RUN: %sourcekitd-test -req=expand-placeholder %s | %FileCheck %s
foo(x: <#T##() -> Void#>)
// CHECK: foo {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
foo(x: <#T##() -> Void#>, y: <#T##Int#>)
// CHECK: foo(x: {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }, y: Int)
anArr.indexOfObjectPassingTest(<#T##predicate: ((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?##((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?#>)
// CHECK: anArr.indexOfObjectPassingTest { <#AnyObject!#>, <#Int#>, <#UnsafePointer<ObjCBool>#> in
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
anArr.indexOfObjectPassingTest(<#T##predicate: ((_ obj: AnyObject!, _ idx: Int, _ stop: UnsafePointer<ObjCBool>) -> Bool)?##((_ obj: AnyObject!, _ idx: Int, _ stop: UnsafePointer<ObjCBool>) -> Bool)?#>)
// CHECK: anArr.indexOfObjectPassingTest { obj, idx, stop in
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
anArr.indexOfObjectAtIndexes(<#T##s: NSIndexSet?##NSIndexSet?#>, options: <#T##NSEnumerationOptions#>, passingTest: <#T##((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?#>)
// CHECK: anArr.indexOfObjectAtIndexes(NSIndexSet?, options: NSEnumerationOptions) { <#AnyObject!#>, <#Int#>, <#UnsafePointer<ObjCBool>#> in
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
if anArr.indexOfObjectPassingTest(<#T##predicate: ((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?##((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?#>) {
}
// CHECK: if anArr.indexOfObjectPassingTest({ <#AnyObject!#>, <#Int#>, <#UnsafePointer<ObjCBool>#> in
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }) {
// CHECK-NEXT: }
dispatch_after(<#T##when: dispatch_time_t##dispatch_time_t#>, <#T##queue: dispatch_queue_t?##dispatch_queue_t?#>, <#T##block: dispatch_block_t?##dispatch_block_t?##() -> Void#>)
// CHECK: dispatch_after(dispatch_time_t, dispatch_queue_t?) {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
@resultBuilder
struct MyBuilder {}
func acceptBuilder<Result>(@MyBuilder body: () -> Result) {}
do {
acceptBuilder(body: <#T##() -> Result#>)
// CHECK: acceptBuilder {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
}
foo(x: <#T##Self.SegueIdentifier -> Void#>)
// CHECK: foo { <#Self.SegueIdentifier#> in
store.requestAccessToEntityType(<#T##entityType: EKEntityType##EKEntityType#>, completion: <#T##EKEventStoreRequestAccessCompletionHandler##EKEventStoreRequestAccessCompletionHandler##(Bool, NSError?) -> Void#>)
// CHECK: store.requestAccessToEntityType(EKEntityType) { <#Bool#>, <#NSError?#> in
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
func f() {
store.requestAccessToEntityType(<#T##entityType: EKEntityType##EKEntityType#>, completion: nil)
}
// CHECK: store.requestAccessToEntityType(EKEntityType, completion: nil)
func f1() {
bar(<#T##d: () -> ()##() -> ()#>)
}
// CHECK: bar {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
func f1() {
bar(<#T##__skip__: () -> ()##() -> ()#>, <#T##d: () -> ()##() -> ()#>)
}
// CHECK: bar {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: } _: {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
func f1() {
bar(<#T##d: () -> ()##() -> ()#>, <#T##d: () -> ()##() -> ()#>)
}
// CHECK: bar {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: } _: {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
func f1() {
bar(a : <#T##__skip__: () -> ()##() -> ()#>, b : <#T##d: () -> ()##() -> ()#>)
}
// CHECK: bar {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: } b: {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
func f1() {
bar(a : <#T##d: () -> ()##() -> ()#>, b : <#T##d: () -> ()##() -> ()#>)
}
// CHECK: bar {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: } b: {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
func f1() {
bar(a : {}}, <#T##d: () -> ()##() -> ()#>)
}
// CHECK: bar(a : {}}, <#T##d: () -> ()##() -> ()#>)
foo(withDuration: 1, animations: <#T##() -> Void#>)
if true {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
}
foo(.foo(<#T##block: () -> Void##() -> Void#>))
// CHECK: foo(.foo({
braced1(x: {<#T##() -> Void#>})
// CHECK: braced1 {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }
braced2(x: {<#T##() -> Void#>}, y: Int)
// CHECK: braced2(x: {
// CHECK-NEXT: <#code#>
// CHECK-NEXT: }, y: Int)
func returnTrailing() -> Int {
return withtrail(<#T##() -> ()#>)
// CHECK: return withtrail {
// CHECK-NEXT: <#code#>
}
var yieldTrailing: Int {
_read {
yield withtrail(<#T##() -> ()#>)
// CHECK: yield withtrail {
// CHECK-NEXT: <#code#>
}
}
func caseTrailing() -> Int {
switch true {
case true: withtrail(<#T##() -> ()#>)
// CHECK: case true: withtrail {
// CHECK-NEXT: <#code#>
default: withtrail(<#T##() -> ()#>)
// CHECK: default: withtrail {
// CHECK-NEXT: <#code#>
}
}
func throwTrailing() -> Int {
throw withtrail(<#T##() -> ()#>)
// CHECK: throw withtrail {
// CHECK-NEXT: <#code#>
}
func singleExprTrailing1() -> Int {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
var singleExprTrailing2: Int {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
var singleExprTrailing3: Int {
get {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
}
closureTrailingMulti {
bah()
withtrail(<#T##() -> ()#>)
// CHECK: bah()
// CHECK-NEXT: withtrail {
// CHECK-NEXT: <#code#>
}
closureIf {
if withtrail(<#T##() -> ()#>) {}
// CHECK: if withtrail({
// CHECK-NEXT: <#code#>
}
closureNonTrail {
nonTrail(<#T##() -> ()#>, 1)
// CHECK: nonTrail({
// CHECK-NEXT: <#code#>
}
singleExprClosureTrailing {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
singleExprClosureTrailingParens({
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
})
singleExprClosureMultiArg(1) {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
singleExprClosureMultiArg(1) {
withtrail(<#T##() -> ()#>)
// CHECK: withtrail {
// CHECK-NEXT: <#code#>
}
func active() {
foo(<#T##value: Foo##Foo#>)
// CHECK: foo(Foo)
}
func activeWithTrailing() {
forEach(<#T##() -> ()#>)
// CHECK: forEach {
// CHECK-NEXT: <#code#>
}
#if false
func inactive() {
foo(<#T##value: Foo##Foo#>)
// CHECK: foo(Foo)
}
func inactiveWithTrailing() {
forEach(<#T##() -> ()#>)
// CHECK: forEach {
// CHECK-NEXT: <#code#>
}
#endif
expandClosureWithInternalParameterNames {
withtrail(<#T##callback: (Int, Int) -> Bool##(_ a: Int, _ b: Int) -> Bool#>)
// CHECK: withtrail { a, b in
// CHECK-NEXT: <#code#>
}