KT-19011: Fix import optimizing when extension functional type is used
It should check is extension functional type imported from companion is actually called on companion instance #KT-19011 fixed
This commit is contained in:
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
|||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
|
||||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||||
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
||||||
import org.jetbrains.kotlin.idea.kdoc.KDocReference
|
import org.jetbrains.kotlin.idea.kdoc.KDocReference
|
||||||
@@ -34,7 +33,9 @@ import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
|||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
@@ -254,7 +255,7 @@ fun KtExpression.readWriteAccess(useResolveForReadWrite: Boolean): ReferenceAcce
|
|||||||
ReferenceAccess.READ
|
ReferenceAccess.READ
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor): Boolean {
|
fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor, bindingContext: BindingContext): Boolean {
|
||||||
if (!target.canBeReferencedViaImport()) return false
|
if (!target.canBeReferencedViaImport()) return false
|
||||||
|
|
||||||
if (this is KDocReference) return element.getQualifiedName().size == 1
|
if (this is KDocReference) return element.getQualifiedName().size == 1
|
||||||
@@ -267,6 +268,10 @@ fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor): Boolean {
|
|||||||
if (callTypeAndReceiver.receiver != null) {
|
if (callTypeAndReceiver.receiver != null) {
|
||||||
if (target !is PropertyDescriptor || !target.type.isExtensionFunctionType) return false
|
if (target !is PropertyDescriptor || !target.type.isExtensionFunctionType) return false
|
||||||
if (callTypeAndReceiver !is CallTypeAndReceiver.DOT && callTypeAndReceiver !is CallTypeAndReceiver.SAFE) return false
|
if (callTypeAndReceiver !is CallTypeAndReceiver.DOT && callTypeAndReceiver !is CallTypeAndReceiver.SAFE) return false
|
||||||
|
|
||||||
|
val resolvedCall = bindingContext[BindingContext.CALL, referenceExpression].getResolvedCall(bindingContext)
|
||||||
|
as? VariableAsFunctionResolvedCall ?: return false
|
||||||
|
if (resolvedCall.variableCall.explicitReceiverKind.isDispatchReceiver) return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.parent is KtThisExpression || element.parent is KtSuperExpression) return false // TODO: it's a bad design of PSI tree, we should change it
|
if (element.parent is KtThisExpression || element.parent is KtSuperExpression) return false // TODO: it's a bad design of PSI tree, we should change it
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class CodeToInlineBuilder(
|
|||||||
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType
|
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType
|
||||||
|
|
||||||
//TODO: other types of references ('[]' etc)
|
//TODO: other types of references ('[]' etc)
|
||||||
if (expression.mainReference.canBeResolvedViaImport(target)) {
|
if (expression.mainReference.canBeResolvedViaImport(target, bindingContext)) {
|
||||||
codeToInline.fqNamesToImport.add(target.importableFqName!!)
|
codeToInline.fqNamesToImport.add(target.importableFqName!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
if (declaration != null && declaration.isInCopiedArea(file, startOffsets, endOffsets)) continue
|
if (declaration != null && declaration.isInCopiedArea(file, startOffsets, endOffsets)) continue
|
||||||
|
|
||||||
if (!reference.canBeResolvedViaImport(descriptor)) continue
|
if (!reference.canBeResolvedViaImport(descriptor, bindingContext)) continue
|
||||||
|
|
||||||
val fqName = descriptor.importableFqName!!
|
val fqName = descriptor.importableFqName!!
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class KotlinImportOptimizer : ImportOptimizer {
|
|||||||
if (target is PackageViewDescriptor && parentFqName == FqName.ROOT) continue // no need to import top-level packages
|
if (target is PackageViewDescriptor && parentFqName == FqName.ROOT) continue // no need to import top-level packages
|
||||||
if (target !is PackageViewDescriptor && parentFqName == currentPackageName) continue
|
if (target !is PackageViewDescriptor && parentFqName == currentPackageName) continue
|
||||||
|
|
||||||
if (!reference.canBeResolvedViaImport(target)) continue
|
if (!reference.canBeResolvedViaImport(target, bindingContext)) continue
|
||||||
|
|
||||||
if (isAccessibleAsMember(importableDescriptor, element, bindingContext)) continue
|
if (isAccessibleAsMember(importableDescriptor, element, bindingContext)) continue
|
||||||
|
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p1
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
companion object {
|
||||||
|
val COMPANION_VAL: Any.() -> Unit = TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p2
|
||||||
|
|
||||||
|
import p1.Foo
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo.COMPANION_VAL
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p2
|
||||||
|
|
||||||
|
import p1.Foo
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo.COMPANION_VAL
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p1
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
companion object {
|
||||||
|
val COMPANION_VAL: Any.() -> Unit = TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package p2
|
||||||
|
|
||||||
|
import p1.Foo
|
||||||
|
import p1.Foo.Companion.COMPANION_VAL
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo.COMPANION_VAL()
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package p2
|
||||||
|
|
||||||
|
import p1.Foo
|
||||||
|
import p1.Foo.Companion.COMPANION_VAL
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo.COMPANION_VAL()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p1
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
companion object {
|
||||||
|
val COMPANION_VAL: Any.() -> Unit = TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p2
|
||||||
|
|
||||||
|
import p1.Foo
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo.COMPANION_VAL("")
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package p2
|
||||||
|
|
||||||
|
import p1.Foo
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
Foo.COMPANION_VAL("")
|
||||||
|
}
|
||||||
@@ -89,6 +89,24 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExtensionFunctionalTypeValFromCompanionObject.kt")
|
||||||
|
public void testExtensionFunctionalTypeValFromCompanionObject() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt")
|
||||||
|
public void testExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt")
|
||||||
|
public void testExtensionFunctionalTypeValFromCompanionObjectNonExtCall() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InvokeFunction.kt")
|
@TestMetadata("InvokeFunction.kt")
|
||||||
public void testInvokeFunction() throws Exception {
|
public void testInvokeFunction() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/InvokeFunction.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/InvokeFunction.kt");
|
||||||
|
|||||||
@@ -290,6 +290,24 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExtensionFunctionalTypeValFromCompanionObject.kt")
|
||||||
|
public void testExtensionFunctionalTypeValFromCompanionObject() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt")
|
||||||
|
public void testExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt")
|
||||||
|
public void testExtensionFunctionalTypeValFromCompanionObjectNonExtCall() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InvokeFunction.kt")
|
@TestMetadata("InvokeFunction.kt")
|
||||||
public void testInvokeFunction() throws Exception {
|
public void testInvokeFunction() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/InvokeFunction.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/InvokeFunction.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user