mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-14 00:21:27 +00:00
KT-14815 alt + enter -> "import" over a constructor reference is not working
#KT-14815 fixed
This commit is contained in:
committed by
Simon Ogorodnik
parent
f9b2929bca
commit
db8edb01c3
@@ -59,8 +59,8 @@ internal fun createSingleImportAction(
|
||||
element: KtElement,
|
||||
fqNames: Collection<FqName>
|
||||
): KotlinAddImportAction {
|
||||
val file = element.getContainingKtFile()
|
||||
val prioritizer = Prioritizer(element.getContainingKtFile())
|
||||
val file = element.containingKtFile
|
||||
val prioritizer = Prioritizer(element.containingKtFile)
|
||||
val variants = fqNames
|
||||
.map { fqName ->
|
||||
val sameFqNameDescriptors = file.resolveImportReference(fqName)
|
||||
@@ -73,6 +73,29 @@ internal fun createSingleImportAction(
|
||||
return KotlinAddImportAction(project, editor, element, variants)
|
||||
}
|
||||
|
||||
internal fun createSingleImportActionForConstructor(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
element: KtElement,
|
||||
fqNames: Collection<FqName>
|
||||
): KotlinAddImportAction {
|
||||
val file = element.containingKtFile
|
||||
val prioritizer = Prioritizer(element.containingKtFile)
|
||||
val variants = fqNames
|
||||
.map { fqName ->
|
||||
val sameFqNameDescriptors = file.resolveImportReference(fqName.parent())
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.flatMap { it.constructors }
|
||||
|
||||
val priority = sameFqNameDescriptors.map { prioritizer.priority(it) }.min() ?: return@map null
|
||||
Prioritizer.VariantWithPriority(SingleImportVariant(fqName, sameFqNameDescriptors), priority)
|
||||
}
|
||||
.filterNotNull()
|
||||
.sortedBy { it.priority }
|
||||
.map { it.variant }
|
||||
return KotlinAddImportAction(project, editor, element, variants)
|
||||
}
|
||||
|
||||
internal fun createGroupedImportsAction(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
|
||||
import org.jetbrains.kotlin.idea.actions.createGroupedImportsAction
|
||||
import org.jetbrains.kotlin.idea.actions.createSingleImportAction
|
||||
import org.jetbrains.kotlin.idea.actions.createSingleImportActionForConstructor
|
||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
@@ -238,17 +239,9 @@ internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T, f
|
||||
|
||||
if (expression is KtSimpleNameExpression) {
|
||||
if (!expression.isImportDirectiveExpression() && !isSelectorInQualified(expression)) {
|
||||
val filterByCallType = { descriptor: DeclarationDescriptor -> callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor) }
|
||||
val filterByCallType = callTypeAndReceiver.toFilter()
|
||||
|
||||
when (TargetPlatformDetector.getPlatform(expression.getContainingKtFile())) {
|
||||
JsPlatform -> indicesHelper
|
||||
// Enum entries should be contributes with members import fix
|
||||
.getKotlinClasses({ it == name },
|
||||
psiFilter = { ktDeclaration -> ktDeclaration !is KtEnumEntry },
|
||||
kindFilter = { kind -> kind != ClassKind.ENUM_ENTRY })
|
||||
.filterTo(result, filterByCallType)
|
||||
JvmPlatform -> indicesHelper.getJvmClassesByName(name).filterTo(result, filterByCallType)
|
||||
}
|
||||
indicesHelper.getClassesByName(expression, name).filterTo(result, filterByCallType)
|
||||
|
||||
indicesHelper.getTopLevelTypeAliases { it == name }.filterTo(result, filterByCallType)
|
||||
|
||||
@@ -272,6 +265,31 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix
|
||||
}
|
||||
}
|
||||
|
||||
internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression) : ImportFixBase<KtSimpleNameExpression>(expression, MyFactory) {
|
||||
override fun getCallTypeAndReceiver() = element?.let {
|
||||
CallTypeAndReceiver.detect(it) as? CallTypeAndReceiver.CALLABLE_REFERENCE
|
||||
}
|
||||
|
||||
override fun fillCandidates(name: String, callTypeAndReceiver: CallTypeAndReceiver<*, *>, bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper): List<DeclarationDescriptor> {
|
||||
val expression = element ?: return emptyList()
|
||||
|
||||
val filterByCallType = callTypeAndReceiver.toFilter()
|
||||
// TODO Type-aliases
|
||||
return indicesHelper.getClassesByName(expression, name).asSequence().map { it.constructors }.flatten().filter(filterByCallType).toList()
|
||||
}
|
||||
|
||||
override fun createAction(project: Project, editor: Editor, element: KtExpression): KotlinAddImportAction {
|
||||
return createSingleImportActionForConstructor(project, editor, element, suggestions)
|
||||
}
|
||||
|
||||
override val importNames = element?.mainReference?.resolvesByNames ?: emptyList()
|
||||
|
||||
companion object MyFactory : Factory() {
|
||||
override fun createAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportConstructorReferenceFix)
|
||||
}
|
||||
}
|
||||
|
||||
internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase<KtExpression>(expression, MyFactory) {
|
||||
override val importNames = OperatorNameConventions.INVOKE.singletonList()
|
||||
|
||||
@@ -279,7 +297,7 @@ internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase
|
||||
|
||||
companion object MyFactory : Factory() {
|
||||
override fun createAction(diagnostic: Diagnostic) =
|
||||
(diagnostic.psiElement as? KtExpression)?.let { InvokeImportFix(it) }
|
||||
(diagnostic.psiElement as? KtExpression)?.let(::InvokeImportFix)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +424,7 @@ internal class ImportMemberFix(expression: KtSimpleNameExpression) : ImportFixBa
|
||||
|
||||
val result = ArrayList<DeclarationDescriptor>()
|
||||
|
||||
val filterByCallType = { descriptor: DeclarationDescriptor -> callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor) }
|
||||
val filterByCallType = callTypeAndReceiver.toFilter()
|
||||
|
||||
indicesHelper.getKotlinEnumsByName(name).filterTo(result, filterByCallType)
|
||||
|
||||
@@ -552,4 +570,17 @@ object ImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory() {
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun KotlinIndicesHelper.getClassesByName(expressionForPlatform: KtExpression, name: String) =
|
||||
when (TargetPlatformDetector.getPlatform(expressionForPlatform.containingKtFile)) {
|
||||
JsPlatform -> getKotlinClasses({ it == name },
|
||||
// Enum entries should be contributes with members import fix
|
||||
psiFilter = { ktDeclaration -> ktDeclaration !is KtEnumEntry },
|
||||
kindFilter = { kind -> kind != ClassKind.ENUM_ENTRY })
|
||||
JvmPlatform -> getJvmClassesByName(name)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
private fun CallTypeAndReceiver<*, *>.toFilter() = { descriptor: DeclarationDescriptor -> this.callType.descriptorKindFilter.accepts(descriptor) }
|
||||
@@ -140,6 +140,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
|
||||
UNRESOLVED_REFERENCE.registerFactory(ImportMemberFix)
|
||||
UNRESOLVED_REFERENCE.registerFactory(ImportFix)
|
||||
UNRESOLVED_REFERENCE.registerFactory(ImportConstructorReferenceFix)
|
||||
|
||||
TOO_MANY_ARGUMENTS.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
|
||||
10
idea/testData/quickfix/autoImports/constructorReference.after.kt
vendored
Normal file
10
idea/testData/quickfix/autoImports/constructorReference.after.kt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// "Import" "true"
|
||||
// ERROR: Unresolved reference: Some
|
||||
package p1
|
||||
|
||||
import p2.Some
|
||||
import p2.receiveSomeCtor
|
||||
|
||||
fun a() {
|
||||
receiveSomeCtor(::Some<caret>)
|
||||
}
|
||||
10
idea/testData/quickfix/autoImports/constructorReference.before.Dependency.kt
vendored
Normal file
10
idea/testData/quickfix/autoImports/constructorReference.before.Dependency.kt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package p2
|
||||
|
||||
class Some {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun receiveSomeCtor(ctor: () -> Some) {
|
||||
|
||||
}
|
||||
9
idea/testData/quickfix/autoImports/constructorReference.before.Main.kt
vendored
Normal file
9
idea/testData/quickfix/autoImports/constructorReference.before.Main.kt
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// "Import" "true"
|
||||
// ERROR: Unresolved reference: Some
|
||||
package p1
|
||||
|
||||
import p2.receiveSomeCtor
|
||||
|
||||
fun a() {
|
||||
receiveSomeCtor(::Some<caret>)
|
||||
}
|
||||
14
idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.after.kt
vendored
Normal file
14
idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.after.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// "Import" "false"
|
||||
// ERROR: Unresolved reference: Some
|
||||
// ACTION: Convert reference to lambda
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Create function 'Some'
|
||||
// ACTION: Rename reference
|
||||
|
||||
package p1
|
||||
|
||||
import p2.receiveSomeCtor
|
||||
|
||||
fun some() {
|
||||
receiveSomeCtor(::Some<caret>)
|
||||
}
|
||||
7
idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Dependency.kt
vendored
Normal file
7
idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Dependency.kt
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package p2
|
||||
|
||||
interface Some
|
||||
|
||||
fun receiveSomeCtor(ctor: () -> Some) {
|
||||
|
||||
}
|
||||
14
idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt
vendored
Normal file
14
idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// "Import" "false"
|
||||
// ERROR: Unresolved reference: Some
|
||||
// ACTION: Convert reference to lambda
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Create function 'Some'
|
||||
// ACTION: Rename reference
|
||||
|
||||
package p1
|
||||
|
||||
import p2.receiveSomeCtor
|
||||
|
||||
fun some() {
|
||||
receiveSomeCtor(::Some<caret>)
|
||||
}
|
||||
@@ -96,6 +96,12 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("constructorReference.before.Main.kt")
|
||||
public void testConstructorReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/constructorReference.before.Main.kt");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("delegateExtensionBoth.test")
|
||||
public void testDelegateExtensionBoth() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/delegateExtensionBoth.test");
|
||||
@@ -474,6 +480,12 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noImportInterfaceRefAsConstructor.before.Main.kt")
|
||||
public void testNoImportInterfaceRefAsConstructor() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noImportInterfaceRefAsConstructor.before.Main.kt");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noImportsForClassInExcludedPackage.before.Main.kt")
|
||||
public void testNoImportsForClassInExcludedPackage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noImportsForClassInExcludedPackage.before.Main.kt");
|
||||
|
||||
Reference in New Issue
Block a user