KT-34000: Allow autoimport to suggest fixes in qualified expressions

- it is required to be able to autoimport extensions from objects,
not only from the top level
- use `substituteExtensionIfCallable` to handle generics for extension methods
- move finding expression receivers to the separate method, add `Receivers` value class to hold found receivers
- change `CallableDescriptor.isValidByReceiversFor` to return false
if explicit receiver is not required for the descriptor
- ^KT-34000 Fixed
This commit is contained in:
Roman Golyshev
2019-09-26 17:51:11 +03:00
committed by Roman Golyshev
parent b2d2165342
commit c463fad3b7
14 changed files with 294 additions and 27 deletions
@@ -0,0 +1,12 @@
// "Import" "true"
package p
class T {
companion object {
fun T.foobar() {}
}
}
fun usage(t: T) {
t.<caret>foobar()
}
@@ -0,0 +1,14 @@
// "Import" "true"
package p
import p.T.Companion.foobar
class T {
companion object {
fun T.foobar() {}
}
}
fun usage(t: T) {
t.<caret>foobar()
}
@@ -0,0 +1,12 @@
// "Import" "true"
package p
class T {
companion object {
val T.foobar get = 10
}
}
fun usage(t: T) {
t.<caret>foobar
}
@@ -0,0 +1,14 @@
// "Import" "true"
package p
import p.T.Companion.foobar
class T {
companion object {
val T.foobar get = 10
}
}
fun usage(t: T) {
t.<caret>foobar
}
@@ -0,0 +1,26 @@
// "Import" "true"
package p
class T
class NotT
class NotTT
object TopLevelObject1 {
fun T.foobar() {}
}
object TopLevelObject2 {
fun NotT.foobar() {} // other type, should not be imported
}
object TopLevelObject3 {
fun foobar() {} // not an extension, should not be imported
}
object TopLevelObject4 {
fun NotTT.foobar() {} // NotTT present as receiver, but explicit receiver shuts him down
}
fun NotTT.usage(t: T) {
t.<caret>foobar()
}
@@ -0,0 +1,28 @@
// "Import" "true"
package p
import p.TopLevelObject1.foobar
class T
class NotT
class NotTT
object TopLevelObject1 {
fun T.foobar() {}
}
object TopLevelObject2 {
fun NotT.foobar() {} // other type, should not be imported
}
object TopLevelObject3 {
fun foobar() {} // not an extension, should not be imported
}
object TopLevelObject4 {
fun NotTT.foobar() {} // NotTT present as receiver, but explicit receiver shuts him down
}
fun NotTT.usage(t: T) {
t.foobar()
}
@@ -0,0 +1,12 @@
// "Import" "true"
package p
class T
object TopLevelObject1 {
fun <A> A.foobar() {}
}
fun usage(t: T) {
t.<caret>foobar()
}
@@ -0,0 +1,14 @@
// "Import" "true"
package p
import p.TopLevelObject1.foobar
class T
object TopLevelObject1 {
fun <A> A.foobar() {}
}
fun usage(t: T) {
t.foobar()
}
@@ -0,0 +1,26 @@
// "Import" "true"
package p
class T
class NotT
class NotTT
object TopLevelObject1 {
val T.foobar get() = 10
}
object TopLevelObject2 {
val NotT.foobar get() = 10 // other type, should not be imported
}
object TopLevelObject3 {
val foobar get() = 10 // not an extension, should not be imported
}
object TopLevelObject4 {
val NotTT.foobar get() = 10 // NotTT present as receiver, but explicit receiver shuts him down
}
fun NotTT.usage(t: T) {
t.foobar<caret>
}
@@ -0,0 +1,28 @@
// "Import" "true"
package p
import p.TopLevelObject1.foobar
class T
class NotT
class NotTT
object TopLevelObject1 {
val T.foobar get() = 10
}
object TopLevelObject2 {
val NotT.foobar get() = 10 // other type, should not be imported
}
object TopLevelObject3 {
val foobar get() = 10 // not an extension, should not be imported
}
object TopLevelObject4 {
val NotTT.foobar get() = 10 // NotTT present as receiver, but explicit receiver shuts him down
}
fun NotTT.usage(t: T) {
t.foobar
}
@@ -0,0 +1,12 @@
// "Import" "true"
package p
class T
object TopLevelObject1 {
val <A> A.foobar get() = 10
}
fun usage(t: T) {
t.<caret>foobar
}
@@ -0,0 +1,14 @@
// "Import" "true"
package p
import p.TopLevelObject1.foobar
class T
object TopLevelObject1 {
val <A> A.foobar get() = 10
}
fun usage(t: T) {
t.<caret>foobar
}