Import all components and delegates accessors if possible
This commit is contained in:
@@ -47,6 +47,8 @@ public fun FqName.tail(prefix: FqName): FqName {
|
||||
}
|
||||
}
|
||||
|
||||
public fun FqName.parentOrNull(): FqName? = if (this.isRoot) null else parent()
|
||||
|
||||
private enum class State {
|
||||
BEGINNING,
|
||||
MIDDLE,
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.jetbrains.kotlin.idea.actions
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||
import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass
|
||||
import com.intellij.codeInsight.daemon.impl.actions.AddImportAction
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.codeInsight.hint.QuestionAction
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
@@ -27,6 +29,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.ui.popup.PopupStep
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.statistics.StatisticsManager
|
||||
import com.intellij.psi.util.ProximityLocation
|
||||
import com.intellij.psi.util.proximity.PsiProximityComparator
|
||||
@@ -44,70 +47,94 @@ import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.name.parentOrNull
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
fun createSingleImportAction(project: Project,
|
||||
editor: Editor,
|
||||
element: KtElement,
|
||||
descriptors: Collection<DeclarationDescriptor>): KotlinAddImportAction {
|
||||
val prioritizer = Prioritizer(element.getContainingJetFile())
|
||||
val variants = descriptors
|
||||
.groupBy { it.importableFqName!! }
|
||||
.map {
|
||||
val (fqName, sameFqNameDescriptors) = it
|
||||
val priority = sameFqNameDescriptors.map { prioritizer.priority(it) }.min()!!
|
||||
Prioritizer.VariantWithPriority(SingleImportVariant(fqName, sameFqNameDescriptors), priority)
|
||||
}
|
||||
.sortedBy { it.priority }
|
||||
.map { it.variant }
|
||||
|
||||
return KotlinAddImportAction(project, editor, element, variants)
|
||||
}
|
||||
|
||||
fun createGroupedImportsAction(project: Project,
|
||||
editor: Editor,
|
||||
element: KtElement,
|
||||
autoImportDescription: String,
|
||||
descriptors: Collection<DeclarationDescriptor>): KotlinAddImportAction {
|
||||
val prioritizer = DescriptorGroupPrioritizer(element.getContainingJetFile())
|
||||
|
||||
val variants = descriptors
|
||||
.groupBy { it.importableFqName!!.parentOrNull() ?: FqName.ROOT }
|
||||
.map {
|
||||
val samePackageDescriptors = it.value
|
||||
val variant = if (samePackageDescriptors.size > 1) {
|
||||
GroupedImportVariant(autoImportDescription, samePackageDescriptors)
|
||||
}
|
||||
else {
|
||||
SingleImportVariant(samePackageDescriptors.first().importableFqName!!, samePackageDescriptors)
|
||||
}
|
||||
|
||||
val priority = prioritizer.priority(samePackageDescriptors)
|
||||
DescriptorGroupPrioritizer.VariantWithPriority(variant, priority)
|
||||
}
|
||||
.sortedBy {
|
||||
it.priority
|
||||
}
|
||||
.map { it.variant }
|
||||
|
||||
return KotlinAddImportAction(project, editor, element, variants)
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically adds import directive to the file for resolving reference.
|
||||
* Based on {@link AddImportAction}
|
||||
*/
|
||||
public class KotlinAddImportAction(
|
||||
internal class KotlinAddImportAction(
|
||||
private val project: Project,
|
||||
private val editor: Editor,
|
||||
private val element: KtExpression,
|
||||
candidates: Collection<DeclarationDescriptor>
|
||||
) : QuestionAction {
|
||||
private val element: KtElement,
|
||||
private val variants: List<AutoImportVariant>) : QuestionAction {
|
||||
fun showHint(): Boolean {
|
||||
if (variants.isEmpty()) return false
|
||||
|
||||
private val file = element.getContainingJetFile()
|
||||
private val prioritizer = Prioritizer(file)
|
||||
|
||||
private inner class Variant(
|
||||
val fqName: FqName,
|
||||
val descriptors: Collection<DeclarationDescriptor>
|
||||
) {
|
||||
val priority = descriptors
|
||||
.map { prioritizer.priority(fqName, it) }
|
||||
.min()!!
|
||||
|
||||
val descriptorToImport: DeclarationDescriptor
|
||||
get() {
|
||||
return descriptors.singleOrNull()
|
||||
?: descriptors.sortedBy { if (it is ClassDescriptor) 0 else 1 }.first()
|
||||
}
|
||||
|
||||
val declarationToImport = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptorToImport)
|
||||
}
|
||||
|
||||
private val variants = candidates
|
||||
.groupBy { it.importableFqName!! }
|
||||
.map { Variant(it.key, it.value) }
|
||||
.sortedBy { it.priority }
|
||||
|
||||
public val highestPriorityFqName: FqName
|
||||
get() = variants.first().fqName
|
||||
|
||||
override fun execute(): Boolean {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
if (!element.isValid()) return false
|
||||
|
||||
// TODO: Validate resolution variants. See AddImportAction.execute()
|
||||
|
||||
if (variants.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
addImport(variants.first())
|
||||
}
|
||||
else {
|
||||
chooseCandidateAndImport()
|
||||
}
|
||||
val hintText = ShowAutoImportPass.getMessage(variants.size > 1, variants.first().hint)
|
||||
HintManager.getInstance().showQuestionHint(editor, hintText, element.getTextOffset(), element.getTextRange()!!.getEndOffset(), this)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getImportSelectionPopup(): BaseListPopupStep<Variant> {
|
||||
return object : BaseListPopupStep<Variant>(JetBundle.message("imports.chooser.title"), variants) {
|
||||
override fun execute(): Boolean {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
if (!element.isValid) return false
|
||||
|
||||
if (variants.size == 1 || ApplicationManager.getApplication().isUnitTestMode) {
|
||||
addImport(variants.first())
|
||||
return true
|
||||
}
|
||||
|
||||
JBPopupFactory.getInstance().createListPopup(getVariantSelectionPopup()).showInBestPositionFor(editor)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getVariantSelectionPopup(): BaseListPopupStep<AutoImportVariant> {
|
||||
return object : BaseListPopupStep<AutoImportVariant>(JetBundle.message("imports.chooser.title"), variants) {
|
||||
override fun isAutoSelectionEnabled() = false
|
||||
|
||||
override fun onChosen(selectedValue: Variant?, finalChoice: Boolean): PopupStep<String>? {
|
||||
override fun onChosen(selectedValue: AutoImportVariant?, finalChoice: Boolean): PopupStep<String>? {
|
||||
if (selectedValue == null || project.isDisposed) return null
|
||||
|
||||
if (finalChoice) {
|
||||
@@ -115,7 +142,7 @@ public class KotlinAddImportAction(
|
||||
return null
|
||||
}
|
||||
|
||||
val toExclude = AddImportAction.getAllExcludableStrings(selectedValue.fqName.asString())
|
||||
val toExclude = AddImportAction.getAllExcludableStrings(selectedValue.excludeFqNameCheck.asString())
|
||||
|
||||
return object : BaseListPopupStep<String>(null, toExclude) {
|
||||
override fun getTextFor(value: String): String {
|
||||
@@ -131,65 +158,116 @@ public class KotlinAddImportAction(
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasSubstep(selectedValue: Variant?) = true
|
||||
|
||||
override fun getTextFor(value: Variant) = value.fqName.asString()
|
||||
|
||||
override fun getIconFor(value: Variant) = JetDescriptorIconProvider.getIcon(value.descriptorToImport, value.declarationToImport, 0)
|
||||
override fun hasSubstep(selectedValue: AutoImportVariant?) = true
|
||||
override fun getTextFor(value: AutoImportVariant) = value.hint
|
||||
override fun getIconFor(value: AutoImportVariant) = value.icon(project)
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseCandidateAndImport() {
|
||||
JBPopupFactory.getInstance().createListPopup(getImportSelectionPopup()).showInBestPositionFor(editor)
|
||||
}
|
||||
|
||||
private fun addImport(selectedVariant: Variant) {
|
||||
private fun addImport(variant: AutoImportVariant) {
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
|
||||
project.executeWriteCommand(QuickFixBundle.message("add.import")) {
|
||||
if (!element.isValid()) return@executeWriteCommand
|
||||
if (!element.isValid) return@executeWriteCommand
|
||||
|
||||
selectedVariant.declarationToImport?.let {
|
||||
val location = ProximityLocation(file, ModuleUtilCore.findModuleForPsiElement(file))
|
||||
val file = element.getContainingJetFile()
|
||||
|
||||
variant.declarationToImport(project)?.let {
|
||||
val location = ProximityLocation(element, ModuleUtilCore.findModuleForPsiElement(element))
|
||||
StatisticsManager.getInstance().incUseCount(PsiProximityComparator.STATISTICS_KEY, it, location)
|
||||
}
|
||||
|
||||
val descriptor = selectedVariant.descriptorToImport
|
||||
// for class or package we use ShortenReferences because we not necessary insert an import but may want to insert partly qualified name
|
||||
if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) {
|
||||
if (element is KtSimpleNameExpression) {
|
||||
element.mainReference.bindToFqName(descriptor.importableFqName!!, KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING)
|
||||
for (descriptor in variant.descriptorsToImport) {
|
||||
// for class or package we use ShortenReferences because we not necessary insert an import but may want to
|
||||
// insert partly qualified name
|
||||
if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) {
|
||||
if (element is KtSimpleNameExpression) {
|
||||
element.mainReference.bindToFqName(descriptor.importableFqName!!, KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING)
|
||||
}
|
||||
} else {
|
||||
ImportInsertHelper.getInstance(project).importDescriptor(file, descriptor)
|
||||
}
|
||||
} else {
|
||||
ImportInsertHelper.getInstance(project).importDescriptor(file, descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Prioritizer(private val file: KtFile) {
|
||||
private val classifier = ImportableFqNameClassifier(file)
|
||||
private val proximityComparator = PsiProximityComparator(file)
|
||||
|
||||
private inner class Priority(private val fqName: FqName, private val descriptor: DeclarationDescriptor) : Comparable<Priority> {
|
||||
private val isDeprecated = KotlinBuiltIns.isDeprecated(descriptor)
|
||||
private val classification = classifier.classify(fqName, false)
|
||||
private val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor)
|
||||
|
||||
override fun compareTo(other: Priority): Int {
|
||||
if (isDeprecated != other.isDeprecated) {
|
||||
return if (isDeprecated) +1 else -1
|
||||
}
|
||||
|
||||
val c1 = classification.compareTo(other.classification)
|
||||
if (c1 != 0) return c1
|
||||
|
||||
val c2 = proximityComparator.compare(declaration, other.declaration)
|
||||
if (c2 != 0) return c2
|
||||
|
||||
return fqName.asString().compareTo(other.fqName.asString())
|
||||
}
|
||||
}
|
||||
|
||||
fun priority(fqName: FqName, descriptor: DeclarationDescriptor) = Priority(fqName, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private class Prioritizer(private val file: KtFile, private val compareNames: Boolean = true) {
|
||||
private val classifier = ImportableFqNameClassifier(file)
|
||||
private val proximityComparator = PsiProximityComparator(file)
|
||||
|
||||
inner class Priority(private val descriptor: DeclarationDescriptor) : Comparable<Priority> {
|
||||
private val isDeprecated = KotlinBuiltIns.isDeprecated(descriptor)
|
||||
private val fqName = descriptor.importableFqName!!
|
||||
private val classification = classifier.classify(fqName, false)
|
||||
private val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor)
|
||||
|
||||
override fun compareTo(other: Priority): Int {
|
||||
if (isDeprecated != other.isDeprecated) {
|
||||
return if (isDeprecated) +1 else -1
|
||||
}
|
||||
|
||||
val c1 = classification.compareTo(other.classification)
|
||||
if (c1 != 0) return c1
|
||||
|
||||
val c2 = proximityComparator.compare(declaration, other.declaration)
|
||||
if (c2 != 0) return c2
|
||||
|
||||
if (compareNames) {
|
||||
return fqName.asString().compareTo(other.fqName.asString())
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
fun priority(descriptor: DeclarationDescriptor) = Priority(descriptor)
|
||||
|
||||
data class VariantWithPriority(val variant: AutoImportVariant, val priority: Priority)
|
||||
}
|
||||
|
||||
private class DescriptorGroupPrioritizer(private val file: KtFile) {
|
||||
private val prioritizer = Prioritizer(file, false)
|
||||
|
||||
inner class Priority(val descriptors: List<DeclarationDescriptor>) : Comparable<Priority> {
|
||||
val ownDescriptorsPriority = descriptors.map { prioritizer.priority(it) }.max()!!
|
||||
|
||||
override fun compareTo(other: Priority): Int {
|
||||
val c1 = ownDescriptorsPriority.compareTo(other.ownDescriptorsPriority)
|
||||
if (c1 != 0) return c1
|
||||
|
||||
return other.descriptors.size - descriptors.size
|
||||
}
|
||||
}
|
||||
|
||||
fun priority(descriptors: List<DeclarationDescriptor>) = Priority(descriptors)
|
||||
|
||||
data class VariantWithPriority(val variant: AutoImportVariant, val priority: Priority)
|
||||
}
|
||||
|
||||
internal interface AutoImportVariant {
|
||||
val descriptorsToImport: Collection<DeclarationDescriptor>
|
||||
val hint: String
|
||||
val excludeFqNameCheck: FqName
|
||||
|
||||
fun icon(project: Project) = JetDescriptorIconProvider.getIcon(descriptorsToImport.first(), declarationToImport(project), 0)
|
||||
|
||||
fun declarationToImport(project: Project): PsiElement? =
|
||||
DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptorsToImport.first())
|
||||
}
|
||||
|
||||
private class GroupedImportVariant(val autoImportDescription: String, val descriptors: Collection<DeclarationDescriptor>) : AutoImportVariant {
|
||||
override val excludeFqNameCheck: FqName = descriptors.first().importableFqName!!.parent()
|
||||
override val descriptorsToImport: Collection<DeclarationDescriptor> get() = descriptors
|
||||
override val hint: String get() = "$autoImportDescription from $excludeFqNameCheck"
|
||||
}
|
||||
|
||||
private class SingleImportVariant(
|
||||
override val excludeFqNameCheck: FqName,
|
||||
val descriptors: Collection<DeclarationDescriptor>
|
||||
) : AutoImportVariant {
|
||||
override val descriptorsToImport: Collection<DeclarationDescriptor> get() =
|
||||
listOf(descriptors.singleOrNull() ?: descriptors.sortedBy { if (it is ClassDescriptor) 0 else 1 }.first())
|
||||
|
||||
override val hint: String get() = excludeFqNameCheck.asString()
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInspection.HintAction
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
|
||||
import org.jetbrains.kotlin.idea.actions.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
|
||||
@@ -80,12 +80,7 @@ abstract class AutoImportFixBase<T: KtExpression>(expression: T, val diagnostics
|
||||
|
||||
if (suggestionCount == 0) return false
|
||||
|
||||
val suggestions = computeSuggestions()
|
||||
val action = KotlinAddImportAction(element.project, editor, element, suggestions)
|
||||
val hintText = ShowAutoImportPass.getMessage(suggestions.size > 1, action.highestPriorityFqName.asString())
|
||||
HintManager.getInstance().showQuestionHint(editor, hintText, element.textOffset, element.textRange.endOffset, action)
|
||||
|
||||
return true
|
||||
return createAction(element.project, editor).showHint()
|
||||
}
|
||||
|
||||
override fun getText() = JetBundle.message("import.fix")
|
||||
@@ -97,8 +92,7 @@ abstract class AutoImportFixBase<T: KtExpression>(expression: T, val diagnostics
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction {
|
||||
val suggestions = computeSuggestions()
|
||||
KotlinAddImportAction(project, editor!!, element, suggestions).execute()
|
||||
createAction(project, editor!!).execute()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +100,10 @@ abstract class AutoImportFixBase<T: KtExpression>(expression: T, val diagnostics
|
||||
|
||||
private fun isOutdated() = modificationCountOnCreate != PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount()
|
||||
|
||||
protected open fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||
return createSingleImportAction(project, editor, element, computeSuggestions())
|
||||
}
|
||||
|
||||
fun computeSuggestions(): Collection<DeclarationDescriptor> {
|
||||
if (!element.isValid()) return listOf()
|
||||
if (element.getContainingFile() !is KtFile) return emptyList()
|
||||
@@ -291,12 +289,25 @@ class MissingDelegateAccessorsAutoImportFix(element: KtExpression, diagnostics:
|
||||
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
||||
|
||||
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||
if (diagnostics.size > 1) {
|
||||
return createGroupedImportsAction(project, editor, element, "Delegate accessors", computeSuggestions())
|
||||
}
|
||||
|
||||
return super.createAction(project, editor)
|
||||
}
|
||||
|
||||
override fun getSupportedErrors() = ERRORS
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtExpression>? {
|
||||
assert(diagnostic.factory == Errors.DELEGATE_SPECIAL_FUNCTION_MISSING)
|
||||
return MissingDelegateAccessorsAutoImportFix(diagnostic.psiElement as KtExpression, listOf(diagnostic))
|
||||
return (diagnostic.psiElement as? KtExpression)?.let { MissingDelegateAccessorsAutoImportFix(it, listOf(diagnostic)) }
|
||||
}
|
||||
|
||||
override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
||||
val element = sameTypeDiagnostics.first().psiElement
|
||||
return (element as? KtExpression)?.let { MissingDelegateAccessorsAutoImportFix(it, sameTypeDiagnostics) }.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) }
|
||||
@@ -309,12 +320,25 @@ class MissingComponentsAutoImportFix(element: KtExpression, diagnostics: Collect
|
||||
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element)
|
||||
|
||||
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||
if (diagnostics.size > 1) {
|
||||
return createGroupedImportsAction(project, editor, element, "Component functions", computeSuggestions())
|
||||
}
|
||||
|
||||
return super.createAction(project, editor)
|
||||
}
|
||||
|
||||
override fun getSupportedErrors() = ERRORS
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtExpression>? {
|
||||
assert(diagnostic.factory == Errors.COMPONENT_FUNCTION_MISSING)
|
||||
return MissingComponentsAutoImportFix(diagnostic.psiElement as KtExpression, listOf(diagnostic))
|
||||
return (diagnostic.psiElement as? KtExpression)?.let { MissingComponentsAutoImportFix(it, listOf(diagnostic)) }
|
||||
}
|
||||
|
||||
override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
||||
val element = sameTypeDiagnostics.first().psiElement
|
||||
return (element as? KtExpression)?.let { MissingComponentsAutoImportFix(it, sameTypeDiagnostics) }.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) }
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
|
||||
import org.jetbrains.kotlin.idea.actions.createSingleImportAction
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.targetDescriptors
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
@@ -96,7 +96,7 @@ public class KotlinReferenceImporter : ReferenceImporter {
|
||||
|
||||
var result = false
|
||||
CommandProcessor.getInstance().runUndoTransparentAction {
|
||||
result = KotlinAddImportAction(project, editor, this, suggestions).execute()
|
||||
result = createSingleImportAction(project, editor, this, suggestions).execute()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Missing 'getValue(testing.BigTest, kotlin.reflect.KProperty<*>)' method on delegate of type 'some.DelegateImpl<kotlin.Int>'
|
||||
// ERROR: Missing 'setValue(testing.BigTest, kotlin.reflect.KProperty<*>, [ERROR : Type from delegate])' method on delegate of type 'some.DelegateImpl<kotlin.Int>'
|
||||
|
||||
package testing
|
||||
|
||||
import some.DelegateImpl
|
||||
|
||||
class BigTest {
|
||||
var a by <caret>DelegateImpl<Int>()
|
||||
}
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
package some
|
||||
|
||||
class DelegateImpl<T> {
|
||||
val value: T = null!!
|
||||
}
|
||||
|
||||
public fun <T> DelegateImpl<T>.getValue(thisRef: Any?, property: PropertyMetadata): T = value
|
||||
public fun <T> DelegateImpl<T>.setValue(thisRef: Any, propertyMetadata: PropertyMetadata, t: T) {}
|
||||
|
||||
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Missing 'getValue(testing.BigTest, kotlin.reflect.KProperty<*>)' method on delegate of type 'some.DelegateImpl<kotlin.Int>'
|
||||
// ERROR: Missing 'setValue(testing.BigTest, kotlin.reflect.KProperty<*>, [ERROR : Type from delegate])' method on delegate of type 'some.DelegateImpl<kotlin.Int>'
|
||||
|
||||
package testing
|
||||
|
||||
import some.DelegateImpl
|
||||
import some.getValue
|
||||
import some.setValue
|
||||
|
||||
class BigTest {
|
||||
var a by <caret>DelegateImpl<Int>()
|
||||
}
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import some.Some
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
// "Import" "true"
|
||||
|
||||
package some
|
||||
|
||||
public class Some
|
||||
|
||||
operator fun Some.component1() = 1
|
||||
operator fun Some.component2() = 3
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import some.Some
|
||||
import some.component1
|
||||
import some.component2
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import some.Some
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
package some
|
||||
|
||||
public class Some
|
||||
|
||||
operator fun Some.component1() = 1
|
||||
operator fun Some.component2() = 3
|
||||
//-----------------------
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
package other
|
||||
|
||||
import some.Some
|
||||
|
||||
operator fun Some.component1() = 1
|
||||
operator fun Some.component2() = 3
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import some.Some
|
||||
import some.component1
|
||||
import some.component2
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import some.Some
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
package some
|
||||
|
||||
public class Some
|
||||
|
||||
operator fun Some.component1() = 1
|
||||
operator fun Some.component2() = 3
|
||||
//-----------------------
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
package other
|
||||
|
||||
import some.Some
|
||||
|
||||
operator fun Some.component1() = 1
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import some.Some
|
||||
import some.component1
|
||||
import some.component2
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type aaa.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type aaa.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import aaa.Some
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
package aaa
|
||||
|
||||
public class Some
|
||||
|
||||
@Deprecated("Use componenents from other")
|
||||
operator fun Some.component1() = 1
|
||||
operator fun Some.component2() = 3
|
||||
//-----------------------
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
package other
|
||||
|
||||
import aaa.Some
|
||||
|
||||
operator fun Some.component1() = 1
|
||||
operator fun Some.component2() = 3
|
||||
//-----------------------
|
||||
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Multi-declaration initializer of type aaa.Some must have a 'component1()' function
|
||||
// ERROR: Multi-declaration initializer of type aaa.Some must have a 'component2()' function
|
||||
|
||||
package testing
|
||||
|
||||
import aaa.Some
|
||||
import other.component1
|
||||
import other.component2
|
||||
|
||||
fun testing() {
|
||||
val (a, b) = <caret>Some()
|
||||
}
|
||||
//-----------------------
|
||||
|
||||
|
||||
@@ -83,6 +83,12 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("delegateExtensionBoth.test")
|
||||
public void testDelegateExtensionBoth() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/delegateExtensionBoth.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("delegateExtensionGet.test")
|
||||
public void testDelegateExtensionGet() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/delegateExtensionGet.test");
|
||||
@@ -215,6 +221,30 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclarationExtensionAllComponents.test")
|
||||
public void testMultiDeclarationExtensionAllComponents() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionAllComponents.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclarationExtensionAllComponentsMany.test")
|
||||
public void testMultiDeclarationExtensionAllComponentsMany() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionAllComponentsMany.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclarationExtensionAllComponentsPrefereFull.test")
|
||||
public void testMultiDeclarationExtensionAllComponentsPrefereFull() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionAllComponentsPrefereFull.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclarationExtensionAllComponentsPrefereNotDeprecated.test")
|
||||
public void testMultiDeclarationExtensionAllComponentsPrefereNotDeprecated() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionAllComponentsPrefereNotDeprecated.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclarationExtensionComponent1.test")
|
||||
public void testMultiDeclarationExtensionComponent1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent1.test");
|
||||
|
||||
Reference in New Issue
Block a user