mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[CodeCompletion] Improve completion for Swift keypath expression
* Handle completion in 'parseExprKeyPath()' instead of 'parseExprPostfixSuffix()'. * Fix a crash for implicit type keypath. e.g. '\.path.<complete>'. (SR-8042). * Use 'completeExprKeyPath()' callback. * Implement completion without '.'. e.g. '\Ty.path<complete>' * Improved handling for 'subscript' in completion. * Improved handling for optional unwrapping in completion. https://bugs.swift.org/browse/SR-8042 rdar://problem/41262612
This commit is contained in:
@@ -1,19 +1,33 @@
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_1 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_2 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_3 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_NODOT | %FileCheck %s -check-prefix=PERSONTYPE-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE_DOT | %FileCheck %s -check-prefix=PERSONTYPE-DOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARRAY_NODOT | %FileCheck %s -check-prefix=ARRAY-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARRAY_DOT | %FileCheck %s -check-prefix=ARRAY-DOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OBJ_NODOT | %FileCheck %s -check-prefix=OBJ-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OBJ_DOT | %FileCheck %s -check-prefix=OBJ-DOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OPTIONAL_NODOT | %FileCheck %s -check-prefix=OPTIONAL-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OPTIONAL_DOT | %FileCheck %s -check-prefix=OPTIONAL-DOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNWRAPPED_NODOT | %FileCheck %s -check-prefix=OBJ-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNWRAPPED_DOT | %FileCheck %s -check-prefix=OBJ-DOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CHAIN_NODOT | %FileCheck %s -check-prefix=OBJ-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CHAIN_DOT | %FileCheck %s -check-prefix=OBJ-DOT
|
||||
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_5 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_6 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_7 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_8 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_9 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_10 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PART_11 | %FileCheck %s -check-prefix=PERSON-MEMBER
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARRAYTYPE_NODOT | %FileCheck %s -check-prefix=ARRAYTYPE-NODOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ARRAYTYPE_DOT | %FileCheck %s -check-prefix=ARRAYTYPE-DOT
|
||||
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=APPLY_TYPE_DOT | %FileCheck %s -check-prefix=PERSONTYPE-DOT
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=APPLY_OBJ_DOT | %FileCheck %s -check-prefix=OBJ-DOT
|
||||
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EMPTY_1 | %FileCheck %s -check-prefix=INVALID
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EMPTY_2 | %FileCheck %s -check-prefix=INVALID
|
||||
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_BASEONLY | %FileCheck %s -check-prefix=PERSONTYPE-DOT
|
||||
// FIXME: RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_EXPLICIT | %FileCheck %s -check-prefix=INVALID
|
||||
|
||||
class Person {
|
||||
var name: String
|
||||
var friends: [Person] = []
|
||||
var bestFriend: Person? = nil
|
||||
var itself: Person { return self }
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
@@ -21,25 +35,105 @@ class Person {
|
||||
subscript(_ index: Int) -> Int { get { return 1} }
|
||||
}
|
||||
|
||||
let keyPath1 = \Person.#^PART_1^#
|
||||
let keyPath2 = \Person.friends[0].#^PART_2^#
|
||||
let keyPath3 = \Person.friends[0].friends[0].friends[0].#^PART_3^#
|
||||
let _ = \Person#^TYPE_NODOT^#
|
||||
// PERSONTYPE-NODOT: Begin completions, 5 items
|
||||
// PERSONTYPE-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .name[#String#]; name=name
|
||||
// PERSONTYPE-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .friends[#[Person]#]; name=friends
|
||||
// PERSONTYPE-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .bestFriend[#Person?#]; name=bestFriend
|
||||
// PERSONTYPE-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .itself[#Person#]; name=itself
|
||||
// PERSONTYPE-NODOT-NEXT: Decl[Subscript]/CurrNominal: .[{#Int#}][#Int#]; name=[Int]
|
||||
|
||||
// FIXME: the optionality keypath should work after our compiler is ready.
|
||||
let keyPath4 = \Person.bestFriend?.#^PART_4^#
|
||||
let keyPath5 = \Person.friends.[0].friends[0].friends[0].#^PART_5^#
|
||||
let keyPath6 = \[Person].[0].#^PART_6^#
|
||||
let keyPath7 = \[Person].[0].friends[0].#^PART_7^#
|
||||
let _ = \Person.#^TYPE_DOT^#
|
||||
// PERSONTYPE-DOT: Begin completions, 5 items
|
||||
// PERSONTYPE-DOT-NEXT: Decl[InstanceVar]/CurrNominal: name[#String#]; name=name
|
||||
// PERSONTYPE-DOT-NEXT: Decl[InstanceVar]/CurrNominal: friends[#[Person]#]; name=friends
|
||||
// PERSONTYPE-DOT-NEXT: Decl[InstanceVar]/CurrNominal: bestFriend[#Person?#]; name=bestFriend
|
||||
// PERSONTYPE-DOT-NEXT: Decl[InstanceVar]/CurrNominal: itself[#Person#]; name=itself
|
||||
// PERSONTYPE-DOT-NEXT: Decl[Subscript]/CurrNominal: [{#Int#}][#Int#]; name=[Int]
|
||||
|
||||
func foo1(_ p : Person) {
|
||||
_ = p[keyPath:\Person.#^PART_8^#]
|
||||
_ = p[keyPath:\Person.friends[0].#^PART_9^#]
|
||||
_ = p[keyPath:\[Person].[0].#^PART_10^#]
|
||||
_ = p[keyPath:\Person.friends.[0].friends[0].friends[0].#^PART_11^#]
|
||||
let _ = \Person.friends#^ARRAY_NODOT^#
|
||||
// ARRAY-NODOT: Begin completions
|
||||
// ARRAY-NODOT-DAG: Decl[Subscript]/CurrNominal: [{#Int#}][#Element#]; name=[Int]
|
||||
// ARRAY-NODOT-DAG: Decl[InstanceVar]/CurrNominal: .count[#Int#]; name=count
|
||||
// ARRAY-NODOT-DAG: Decl[InstanceVar]/Super: .first[#Person?#]; name=first
|
||||
|
||||
let _ = \Person.friends.#^ARRAY_DOT^#
|
||||
// ARRAY-DOT: Begin completions
|
||||
// ARRAY-DOT-NOT: Decl[Subscript]/CurrNominal: [{#Int#}][#Element#]; name=[Int]
|
||||
// ARRAY-DOT-DAG: Decl[InstanceVar]/CurrNominal: count[#Int#]; name=count
|
||||
// ARRAY-DOT-DAG: Decl[InstanceVar]/Super: first[#Person?#]; name=first
|
||||
// ARRAY-DOT-NOT: Decl[Subscript]/CurrNominal: [{#Int#}][#Element#]; name=[Int]
|
||||
|
||||
let _ = \Person.friends[0]#^OBJ_NODOT^#
|
||||
// OBJ-NODOT: Begin completions, 5 items
|
||||
// OBJ-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .name[#String#]; name=name
|
||||
// OBJ-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .friends[#[Person]#]; name=friends
|
||||
// OBJ-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .bestFriend[#Person?#]; name=bestFriend
|
||||
// OBJ-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: .itself[#Person#]; name=itself
|
||||
// OBJ-NODOT-NEXT: Decl[Subscript]/CurrNominal: [{#Int#}][#Int#]; name=[Int]
|
||||
|
||||
let _ = \Person.friends[0].#^OBJ_DOT^#
|
||||
// OBJ-DOT: Begin completions, 4 items
|
||||
// OBJ-DOT-NEXT: Decl[InstanceVar]/CurrNominal: name[#String#]; name=name
|
||||
// OBJ-DOT-NEXT: Decl[InstanceVar]/CurrNominal: friends[#[Person]#]; name=friends
|
||||
// OBJ-DOT-NEXT: Decl[InstanceVar]/CurrNominal: bestFriend[#Person?#]; name=bestFriend
|
||||
// OBJ-DOT-NEXT: Decl[InstanceVar]/CurrNominal: itself[#Person#]; name=itself
|
||||
|
||||
let _ = \Person.bestFriend#^OPTIONAL_NODOT^#
|
||||
// OPTIONAL-NODOT: Begin completions
|
||||
// OPTIONAL-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: ?.name[#String#]; name=name
|
||||
// OPTIONAL-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: ?.friends[#[Person]#]; name=friends
|
||||
// OPTIONAL-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: ?.bestFriend[#Person?#]; name=bestFriend
|
||||
// OPTIONAL-NODOT-NEXT: Decl[InstanceVar]/CurrNominal: ?.itself[#Person#]; name=itself
|
||||
// OPTIONAL-NODOT-NEXT: Decl[Subscript]/CurrNominal: ?[{#Int#}][#Int#]; name=[Int]
|
||||
// OPTIONAL-NODOT: Decl[InstanceVar]/CurrNominal: .unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped
|
||||
|
||||
let _ = \Person.bestFriend.#^OPTIONAL_DOT^#
|
||||
// OPTIONAL-DOT: Begin completions
|
||||
// OPTIONAL-DOT-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.name[#String#]; name=name
|
||||
// OPTIONAL-DOT-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.friends[#[Person]#]; name=friends
|
||||
// OPTIONAL-DOT-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.bestFriend[#Person?#]; name=bestFriend
|
||||
// OPTIONAL-DOT-NEXT: Decl[InstanceVar]/CurrNominal/Erase[1]: ?.itself[#Person#]; name=itself
|
||||
// OPTIONAL-DOT: Decl[InstanceVar]/CurrNominal: unsafelyUnwrapped[#Person#]; name=unsafelyUnwrapped
|
||||
|
||||
let _ = \Person.bestFriend?#^UNWRAPPED_NODOT^#
|
||||
// Same as OBJ_NODOT.
|
||||
|
||||
let _ = \Person.bestFriend?.#^UNWRAPPED_DOT^#
|
||||
// Same as OBJ_DOT.
|
||||
|
||||
let _ = \Person.bestFriend?.itself#^CHAIN_NODOT^#
|
||||
// Same as OBJ_NODOT.
|
||||
|
||||
let _ = \Person.bestFriend?.itself.#^CHAIN_DOT^#
|
||||
// Same as OBJ_DOT.
|
||||
|
||||
let _ = \[Person]#^ARRAYTYPE_NODOT^#
|
||||
// ARRAYTYPE-NODOT: Begin completions
|
||||
// ARRAYTYPE-NODOT-DAG: Decl[Subscript]/CurrNominal: .[{#Int#}][#Element#]; name=[Int]
|
||||
// ARRAYTYPE-NODOT-DAG: Decl[InstanceVar]/CurrNominal: .count[#Int#]; name=count
|
||||
// ARRAYTYPE-NODOT-DAG: Decl[InstanceVar]/Super: .first[#Person?#]; name=first
|
||||
|
||||
let _ = \[Person].#^ARRAYTYPE_DOT^#
|
||||
// ARRAYTYPE-DOT: Begin completions
|
||||
// ARRAYTYPE-DOT-DAG: Decl[Subscript]/CurrNominal: [{#Int#}][#Element#]; name=[Int]
|
||||
// ARRAYTYPE-DOT-DAG: Decl[InstanceVar]/CurrNominal: count[#Int#]; name=count
|
||||
// ARRAYTYPE-DOT-DAG: Decl[InstanceVar]/Super: first[#Person?#]; name=first
|
||||
|
||||
func test(_ p: Person) {
|
||||
let _ = p[keyPath: \Person.#^APPLY_TYPE_DOT^#]
|
||||
// Same as TYPE_DOT.
|
||||
let _ = p[keyPath: \Person.friends[0].#^APPLY_OBJ_DOT^#]
|
||||
// Same as OBJ_DOT.
|
||||
}
|
||||
|
||||
// PERSON-MEMBER: Begin completions, 4 items
|
||||
// PERSON-MEMBER-NEXT: Decl[InstanceVar]/CurrNominal: name[#String#]; name=name
|
||||
// PERSON-MEMBER-NEXT: Decl[InstanceVar]/CurrNominal: friends[#[Person]#]; name=friends
|
||||
// PERSON-MEMBER-NEXT: Decl[InstanceVar]/CurrNominal: bestFriend[#Person?#]; name=bestFriend
|
||||
// PERSON-MEMBER-NEXT: Decl[Subscript]/CurrNominal: [{#Int#}][#Int#]; name=[Int]
|
||||
let _ = \.#^EMPTY_1^#
|
||||
let _ = \.friends.#^EMPTY_2^#
|
||||
// INVALID-NOT: Begin completions
|
||||
|
||||
let _: PartialKeyPath<Person> = \.#^CONTEXT_BASEONLY^#
|
||||
// Same as TYPE_DOT.
|
||||
|
||||
let _: KeyPath<Person, String> = \.#^CONTEXT_EXPLICIT^#
|
||||
// FIXME: Currently, it's suggest nothing. Since we know the base type is
|
||||
// 'Person', we should suggest at least '.name'.
|
||||
|
||||
Reference in New Issue
Block a user