Fix add import quick fix for delegated property and missing extension
^KT-39199 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
f453649d0b
commit
943f03e55f
+3
-1
@@ -183,7 +183,9 @@ class ReferenceVariantsCollector(
|
|||||||
val extensions = if (runtimeReceiver != null)
|
val extensions = if (runtimeReceiver != null)
|
||||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter)
|
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, listOf(runtimeReceiver.type), nameFilter)
|
||||||
else
|
else
|
||||||
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, nameExpression, bindingContext, nameFilter)
|
indicesHelper.getCallableTopLevelExtensions(
|
||||||
|
callTypeAndReceiver, nameExpression, bindingContext, receiverTypeFromDiagnostic = null, nameFilter
|
||||||
|
)
|
||||||
|
|
||||||
val (extensionsVariants, notImportedExtensions) = extensions.partition {
|
val (extensionsVariants, notImportedExtensions) = extensions.partition {
|
||||||
importableFqNameClassifier.isImportableDescriptorImported(
|
importableFqNameClassifier.isImportableDescriptorImported(
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||||
import org.jetbrains.kotlin.resolve.scopes.collectSyntheticStaticFunctions
|
import org.jetbrains.kotlin.resolve.scopes.collectSyntheticStaticFunctions
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.isError
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -139,12 +140,21 @@ class KotlinIndicesHelper(
|
|||||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||||
position: KtExpression,
|
position: KtExpression,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
|
receiverTypeFromDiagnostic: KotlinType?,
|
||||||
nameFilter: (String) -> Boolean
|
nameFilter: (String) -> Boolean
|
||||||
): Collection<CallableDescriptor> {
|
): Collection<CallableDescriptor> {
|
||||||
val receiverTypes =
|
val receiverTypes = callTypeAndReceiver.receiverTypes(
|
||||||
callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)
|
bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false
|
||||||
?: return emptyList()
|
)
|
||||||
return getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter)
|
|
||||||
|
return if (receiverTypes == null || receiverTypes.all { it.isError }) {
|
||||||
|
if (receiverTypeFromDiagnostic != null)
|
||||||
|
getCallableTopLevelExtensions(callTypeAndReceiver, listOf(receiverTypeFromDiagnostic), nameFilter)
|
||||||
|
else
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCallableTopLevelExtensions(
|
fun getCallableTopLevelExtensions(
|
||||||
|
|||||||
@@ -259,7 +259,16 @@ internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T, f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, expression, bindingContext) { it == name })
|
val receiverFromDiagnostic = if (callTypeAndReceiver.callType == CallType.DELEGATE) getReceiverTypeFromDiagnostic() else null
|
||||||
|
result.addAll(
|
||||||
|
indicesHelper.getCallableTopLevelExtensions(
|
||||||
|
callTypeAndReceiver,
|
||||||
|
expression,
|
||||||
|
bindingContext,
|
||||||
|
receiverFromDiagnostic
|
||||||
|
) { it == name }
|
||||||
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,7 +503,8 @@ internal open class ArrayAccessorImportFix(
|
|||||||
internal class DelegateAccessorsImportFix(
|
internal class DelegateAccessorsImportFix(
|
||||||
element: KtExpression,
|
element: KtExpression,
|
||||||
override val importNames: Collection<Name>,
|
override val importNames: Collection<Name>,
|
||||||
private val solveSeveralProblems: Boolean
|
private val solveSeveralProblems: Boolean,
|
||||||
|
private val diagnostic: Diagnostic,
|
||||||
) : OrdinaryImportFixBase<KtExpression>(element, MyFactory) {
|
) : OrdinaryImportFixBase<KtExpression>(element, MyFactory) {
|
||||||
|
|
||||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
||||||
@@ -511,6 +521,9 @@ internal class DelegateAccessorsImportFix(
|
|||||||
return super.createAction(project, editor, element)
|
return super.createAction(project, editor, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getReceiverTypeFromDiagnostic(): KotlinType? =
|
||||||
|
if (diagnostic.factory === Errors.DELEGATE_SPECIAL_FUNCTION_MISSING) Errors.DELEGATE_SPECIAL_FUNCTION_MISSING.cast(diagnostic).b else null
|
||||||
|
|
||||||
companion object MyFactory : Factory() {
|
companion object MyFactory : Factory() {
|
||||||
private fun importNames(diagnostics: Collection<Diagnostic>): Collection<Name> {
|
private fun importNames(diagnostics: Collection<Diagnostic>): Collection<Name> {
|
||||||
return diagnostics.map {
|
return diagnostics.map {
|
||||||
@@ -524,14 +537,15 @@ internal class DelegateAccessorsImportFix(
|
|||||||
|
|
||||||
override fun createImportAction(diagnostic: Diagnostic) =
|
override fun createImportAction(diagnostic: Diagnostic) =
|
||||||
(diagnostic.psiElement as? KtExpression)?.let {
|
(diagnostic.psiElement as? KtExpression)?.let {
|
||||||
DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false)
|
DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false, diagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<DelegateAccessorsImportFix> {
|
override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<DelegateAccessorsImportFix> {
|
||||||
val element = sameTypeDiagnostics.first().psiElement
|
val diagnostic = sameTypeDiagnostics.first()
|
||||||
|
val element = diagnostic.psiElement
|
||||||
val names = importNames(sameTypeDiagnostics)
|
val names = importNames(sameTypeDiagnostics)
|
||||||
return listOfNotNull((element as? KtExpression)?.let { DelegateAccessorsImportFix(it, names, true) })
|
return listOfNotNull((element as? KtExpression)?.let { DelegateAccessorsImportFix(it, names, true, diagnostic) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -641,7 +655,7 @@ internal class ImportForMismatchingArgumentsFix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
indicesHelper
|
indicesHelper
|
||||||
.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext) { it == name }
|
.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext, receiverTypeFromDiagnostic = null) { it == name }
|
||||||
.forEach(::processDescriptor)
|
.forEach(::processDescriptor)
|
||||||
|
|
||||||
if (!isSelectorInQualified(element)) {
|
if (!isSelectorInQualified(element)) {
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// "Import" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// ERROR: Type 'MyDelegate<TypeVariable(T)>' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate
|
||||||
|
|
||||||
|
package import
|
||||||
|
|
||||||
|
import base.MyDelegate
|
||||||
|
import base.getValue
|
||||||
|
|
||||||
|
val myVal by MyDelegate { false }
|
||||||
idea/testData/quickfix/autoImports/importGetValueExtensionForDelegateWithLambda.before.Dependency.kt
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
class MyDelegate<T>(init: () -> T) {
|
||||||
|
var value: T = init()
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun <T> MyDelegate<T>.getValue(thisObj: Any?, property: kotlin.reflect.KProperty<*>): T = value
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Import" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// ERROR: Type 'MyDelegate<TypeVariable(T)>' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate
|
||||||
|
|
||||||
|
package import
|
||||||
|
|
||||||
|
import base.MyDelegate
|
||||||
|
|
||||||
|
val myVal by <caret>MyDelegate { false }
|
||||||
+5
@@ -686,6 +686,11 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
|||||||
runTest("idea/testData/quickfix/autoImports/importFromRoot.before.Main.kt");
|
runTest("idea/testData/quickfix/autoImports/importFromRoot.before.Main.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("importGetValueExtensionForDelegateWithLambda.before.Main.kt")
|
||||||
|
public void testImportGetValueExtensionForDelegateWithLambda() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/autoImports/importGetValueExtensionForDelegateWithLambda.before.Main.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("importInFirstPartInQualifiedExpression.before.Main.kt")
|
@TestMetadata("importInFirstPartInQualifiedExpression.before.Main.kt")
|
||||||
public void testImportInFirstPartInQualifiedExpression() throws Exception {
|
public void testImportInFirstPartInQualifiedExpression() throws Exception {
|
||||||
runTest("idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt");
|
runTest("idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user