From a33877a9b9784402d5a6f8eedbbf63d8adf9ae38 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Thu, 21 Jan 2021 16:24:26 +0300 Subject: [PATCH] Fix add import quick fix for unresolved conventional invoke operator After adding extension invoke on DeepRecursiveFunction in 1.4, the compiler start reporting another error and now it doesn't write info about callable descriptor. Therefore it's needed to use another source of info for expression type ^KT-40926 Fixed --- .../kotlin/idea/quickfix/AbstractImportFix.kt | 11 ++++++++--- .../ImportOperatorInvokeWithConvention.after.kt | 12 ++++++++++++ ...OperatorInvokeWithConvention.before.Dependency.kt | 6 ++++++ ...ImportOperatorInvokeWithConvention.before.Main.kt | 11 +++++++++++ .../quickfix/QuickFixMultiFileTestGenerated.java | 5 +++++ 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.after.kt create mode 100644 idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Dependency.kt create mode 100644 idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Main.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt index bbad816414e..7d5ccb1c24e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AbstractImportFix.kt @@ -85,6 +85,7 @@ internal abstract class ImportFixBase protected constructor( protected abstract val importNames: Collection protected abstract fun getCallTypeAndReceiver(): CallTypeAndReceiver<*, *>? + protected open fun getReceiverTypeFromDiagnostic(): KotlinType? = null override fun showHint(editor: Editor): Boolean { val element = element ?: return false @@ -251,7 +252,7 @@ internal abstract class OrdinaryImportFixBase(expression: T, f indicesHelper.getTopLevelCallablesByName(name).filterTo(result, filterByCallType) } if (callTypeAndReceiver.callType == CallType.OPERATOR) { - val type = expression.getCallableDescriptor()?.returnType + val type = expression.getCallableDescriptor()?.returnType ?: getReceiverTypeFromDiagnostic() if (type != null) { result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(type), { it == name })) } @@ -432,14 +433,18 @@ internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression) } } -internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase(expression, MyFactory) { +internal class InvokeImportFix( + expression: KtExpression, val diagnostic: Diagnostic +) : OrdinaryImportFixBase(expression, MyFactory) { override val importNames = listOf(OperatorNameConventions.INVOKE) override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.OPERATOR(it) } + override fun getReceiverTypeFromDiagnostic(): KotlinType = Errors.FUNCTION_EXPECTED.cast(diagnostic).b + companion object MyFactory : Factory() { override fun createImportAction(diagnostic: Diagnostic) = - (diagnostic.psiElement as? KtExpression)?.let(::InvokeImportFix) + (diagnostic.psiElement as? KtExpression)?.let { InvokeImportFix(it, diagnostic) } } } diff --git a/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.after.kt b/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.after.kt new file mode 100644 index 00000000000..4bfe41ecb25 --- /dev/null +++ b/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.after.kt @@ -0,0 +1,12 @@ +// "Import" "true" +// WITH_RUNTIME +// ERROR: Expression 'topVal' of type 'SomeType' cannot be invoked as a function. The function 'invoke()' is not found + +package mig + +import another.invoke +import another.topVal + +fun use() { + topVal() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Dependency.kt b/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Dependency.kt new file mode 100644 index 00000000000..cf68d759222 --- /dev/null +++ b/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Dependency.kt @@ -0,0 +1,6 @@ +package another + +interface SomeType + +operator fun SomeType.invoke() {} +val topVal = object : SomeType {} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Main.kt b/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Main.kt new file mode 100644 index 00000000000..0bf6613e0ff --- /dev/null +++ b/idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Main.kt @@ -0,0 +1,11 @@ +// "Import" "true" +// WITH_RUNTIME +// ERROR: Expression 'topVal' of type 'SomeType' cannot be invoked as a function. The function 'invoke()' is not found + +package mig + +import another.topVal + +fun use() { + topVal() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index f4ec48d922e..a4d1154e619 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -795,6 +795,11 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes runTest("idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedSetterFromJava.test"); } + @TestMetadata("ImportOperatorInvokeWithConvention.before.Main.kt") + public void testImportOperatorInvokeWithConvention() throws Exception { + runTest("idea/testData/quickfix/autoImports/ImportOperatorInvokeWithConvention.before.Main.kt"); + } + @TestMetadata("importTrait.before.Main.kt") public void testImportTrait() throws Exception { runTest("idea/testData/quickfix/autoImports/importTrait.before.Main.kt");