diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index 461ee392158..0e2732ab6b2 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -53,6 +53,8 @@ public sealed class CallType(val descriptorKindFilter: D object TYPE : CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)) + object DELEGATE : CallType(DescriptorKindFilter.FUNCTIONS) + object ANNOTATION : CallType(DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude NonAnnotationClassifierExclude) private object NonInfixExclude : DescriptorKindExclude() { @@ -103,6 +105,7 @@ public sealed class CallTypeAndReceiver(CallType.IMPORT_DIRECTIVE, receiver) class PACKAGE_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.PACKAGE_DIRECTIVE, receiver) class TYPE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.TYPE, receiver) + class DELEGATE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.DELEGATE, receiver) class ANNOTATION(receiver: KtExpression?) : CallTypeAndReceiver(CallType.ANNOTATION, receiver) companion object { @@ -193,10 +196,12 @@ public fun CallTypeAndReceiver<*, *>.receiverTypes( } is CallTypeAndReceiver.DEFAULT -> receiverExpression = null + is CallTypeAndReceiver.DOT -> receiverExpression = receiver is CallTypeAndReceiver.SAFE -> receiverExpression = receiver is CallTypeAndReceiver.INFIX -> receiverExpression = receiver is CallTypeAndReceiver.OPERATOR -> receiverExpression = receiver + is CallTypeAndReceiver.DELEGATE -> receiverExpression = receiver is CallTypeAndReceiver.IMPORT_DIRECTIVE, is CallTypeAndReceiver.PACKAGE_DIRECTIVE, diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index bbf301d8b15..f971605f43c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -44,6 +44,7 @@ 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.psi.KtFile import org.jetbrains.kotlin.psi.KtSimpleNameExpression @@ -54,7 +55,7 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression public class KotlinAddImportAction( private val project: Project, private val editor: Editor, - private val element: KtSimpleNameExpression, + private val element: KtExpression, candidates: Collection ) : QuestionAction { @@ -156,9 +157,10 @@ public class KotlinAddImportAction( 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) { - element.mainReference.bindToFqName(descriptor.importableFqName!!, KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING) - } - else { + if (element is KtSimpleNameExpression) { + element.mainReference.bindToFqName(descriptor.importableFqName!!, KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING) + } + } else { ImportInsertHelper.getInstance(project).importDescriptor(file, descriptor) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt index 2a18047a7a2..d1b891d6e09 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt @@ -31,6 +31,8 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory +import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2 +import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.JetBundle import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction import org.jetbrains.kotlin.idea.caches.resolve.analyze @@ -42,16 +44,19 @@ import org.jetbrains.kotlin.idea.core.getResolutionScope import org.jetbrains.kotlin.idea.core.isVisible import org.jetbrains.kotlin.idea.project.ProjectStructureUtil import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.utils.CachedValueProperty import java.util.* /** * Check possibility and perform fix for unresolved references. */ -public abstract class AutoImportFixBase( +abstract class AutoImportFixBase public constructor( expression: KtExpression, val diagnostics: Collection = emptyList()) : KotlinQuickFixAction(expression), HighPriorityAction, HintAction { @@ -189,8 +194,8 @@ public abstract class AutoImportFixBase( } } -public class AutoImportFix(expression: KtSimpleNameExpression, diagnostic: Diagnostic? = null) : AutoImportFixBase(expression, diagnostic) { - override fun getTypeAndReceiver(): CallTypeAndReceiver<*, *> = CallTypeAndReceiver.detect(element as KtSimpleNameExpression) +class AutoImportFix(expression: KtSimpleNameExpression, diagnostic: Diagnostic? = null) : AutoImportFixBase(expression, diagnostic) { + override fun getTypeAndReceiver(): CallTypeAndReceiver<*, *> = CallTypeAndReceiver.detect(element as JetSimpleNameExpression) override fun getImportNames(diagnostics: Collection, element: KtExpression): Collection { element as KtSimpleNameExpression @@ -198,7 +203,14 @@ public class AutoImportFix(expression: KtSimpleNameExpression, diagnostic: Diagn val conventionName = KtPsiUtil.getConventionName(element) if (conventionName != null) { if (element is KtOperationReferenceExpression) { - return listOf(conventionName.asString()) + val elementType = element.firstChild.node.elementType + if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(elementType)) { + val conterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(elementType) + val counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(conterpart) + if (counterpartName != null) { + return listOf(conventionName.asString(), counterpartName.asString()) + } + } } return listOf(conventionName.asString()) @@ -228,4 +240,99 @@ public class AutoImportFix(expression: KtSimpleNameExpression, diagnostic: Diagn private val ERRORS: Collection> by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) } } +} + +class MissingInvokeAutoImportFix(expression: KtExpression, diagnostic: Diagnostic) : AutoImportFixBase(expression, diagnostic) { + override fun getImportNames(diagnostics: Collection, element: KtExpression) = setOf("invoke") + + override fun getTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element as KtExpression) + + override fun getSupportedErrors() = ERRORS + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + val element = diagnostic.psiElement + if (element is KtExpression) { + return MissingInvokeAutoImportFix(element, diagnostic) + } + + return null + } + + private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) } + } +} + +class MissingArrayAccessorAutoImportFix(element: KtArrayAccessExpression, diagnostic: Diagnostic) : AutoImportFixBase(element, diagnostic) { + override fun getImportNames(diagnostics: Collection, element: KtExpression): Set { + val s = if ((element.parent as? KtBinaryExpression)?.operationToken == KtTokens.EQ) "set" else "get" + return setOf(s) + } + + override fun getTypeAndReceiver() = + CallTypeAndReceiver.OPERATOR((element as KtArrayAccessExpression).arrayExpression!!) + + override fun getSupportedErrors() = ERRORS + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + val element = diagnostic.psiElement + if (element is KtArrayAccessExpression && element.arrayExpression != null) { + return MissingArrayAccessorAutoImportFix(element, diagnostic) + } + + return null + } + + private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) } + } +} + +class MissingDelegateAccessorsAutoImportFix(element: KtExpression, diagnostics: Collection) : AutoImportFixBase(element, diagnostics) { + override fun createAction(project: Project, editor: Editor): KotlinAddImportAction { + return KotlinAddImportAction(project, editor, element, suggestions) + } + + override fun getImportNames(diagnostics: Collection, element: KtExpression): Set { + return diagnostics.mapTo(LinkedHashSet()) { if (it.toString().contains("setValue")) "setValue" else "getValue" } + } + + override fun getTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element as KtExpression) + + override fun getSupportedErrors() = ERRORS + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + assert(diagnostic.factory == Errors.DELEGATE_SPECIAL_FUNCTION_MISSING) + return MissingDelegateAccessorsAutoImportFix(diagnostic.psiElement as KtExpression, listOf(diagnostic)) + } + + private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) } + } +} + +class MissingComponentsAutoImportFix(element: KtExpression, diagnostics: Collection) : AutoImportFixBase(element, diagnostics) { + override fun createAction(project: Project, editor: Editor): KotlinAddImportAction { + return KotlinAddImportAction(project, editor, element, suggestions) + } + + override fun getImportNames(diagnostics: Collection, element: KtExpression): List { + return diagnostics.map { + @Suppress("UNCHECKED_CAST") + (it as DiagnosticWithParameters2<*, Name, *>).a.identifier + } + } + + override fun getTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element as KtExpression) + + override fun getSupportedErrors() = ERRORS + + companion object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + assert(diagnostic.factory == Errors.COMPONENT_FUNCTION_MISSING) + return MissingComponentsAutoImportFix(diagnostic.psiElement as KtExpression, listOf(diagnostic)) + } + + private val ERRORS by lazy(LazyThreadSafetyMode.PUBLICATION) { QuickFixes.getInstance().getDiagnostics(this) } + } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 943a3c11aa0..0e04929622b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -131,6 +131,14 @@ public class QuickFixRegistrar : QuickFixContributor { UNRESOLVED_REFERENCE.registerFactory(AutoImportFix) UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(AutoImportFix) + FUNCTION_EXPECTED.registerFactory(MissingInvokeAutoImportFix) + + DELEGATE_SPECIAL_FUNCTION_MISSING.registerFactory(MissingDelegateAccessorsAutoImportFix) + COMPONENT_FUNCTION_MISSING.registerFactory(MissingComponentsAutoImportFix) + + NO_GET_METHOD.registerFactory(MissingArrayAccessorAutoImportFix) + NO_SET_METHOD.registerFactory(MissingArrayAccessorAutoImportFix) + val removeImportFixFactory = RemovePsiElementSimpleFix.createRemoveImportFactory() CONFLICTING_IMPORT.registerFactory(removeImportFixFactory) diff --git a/idea/testData/quickfix/autoImports/delegateExtensionGet.test b/idea/testData/quickfix/autoImports/delegateExtensionGet.test new file mode 100644 index 00000000000..0a54d0a7d01 --- /dev/null +++ b/idea/testData/quickfix/autoImports/delegateExtensionGet.test @@ -0,0 +1,37 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Missing 'getValue(testing.BigTest, kotlin.PropertyMetadata)' method on delegate of type 'some.DelegateImpl' + +package testing + +import some.DelegateImpl + +class BigTest { + val a by DelegateImpl() +} + + + +// FILE: second.kt +package some + +class DelegateImpl { + val value: T = null!! +} + +public fun DelegateImpl.getValue(thisRef: Any?, property: PropertyMetadata): T = value + + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Missing 'getValue(testing.BigTest, kotlin.PropertyMetadata)' method on delegate of type 'some.DelegateImpl' + +package testing + +import some.DelegateImpl +import some.getValue + +class BigTest { + val a by DelegateImpl() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/delegateExtensionSet.test b/idea/testData/quickfix/autoImports/delegateExtensionSet.test new file mode 100644 index 00000000000..d9873fe93c5 --- /dev/null +++ b/idea/testData/quickfix/autoImports/delegateExtensionSet.test @@ -0,0 +1,41 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Missing 'setValue(testing.BigTest, kotlin.PropertyMetadata, kotlin.Int)' method on delegate of type 'some.DelegateImpl' + +package testing + +import some.DelegateImpl +import some.getValue + +class BigTest { + var a by DelegateImpl() +} + + +// FILE: second.kt +package some + +class DelegateImpl { + val value: T = null!! +} + +public fun DelegateImpl.getValue(thisRef: Any?, property: PropertyMetadata): T = value +public fun DelegateImpl.setValue(thisRef: Any, propertyMetadata: PropertyMetadata, t: T) {} + + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Missing 'setValue(testing.BigTest, kotlin.PropertyMetadata, kotlin.Int)' method on delegate of type 'some.DelegateImpl' + +package testing + +import some.DelegateImpl +import some.getValue +import some.setValue + +class BigTest { + var a by DelegateImpl() +} + + diff --git a/idea/testData/quickfix/autoImports/indexCallExtensionGet.test b/idea/testData/quickfix/autoImports/indexCallExtensionGet.test new file mode 100644 index 00000000000..af536ddb4e0 --- /dev/null +++ b/idea/testData/quickfix/autoImports/indexCallExtensionGet.test @@ -0,0 +1,44 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Unresolved reference: foo()["str"] +// ERROR: No get method providing array access + +package testing + +import some.Some + +fun foo(): Some = Some() + +fun testing() { + foo()["str"] +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.get(s: String) {} + + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference: foo()["str"] +// ERROR: No get method providing array access + +package testing + +import some.Some +import some.get + +fun foo(): Some = Some() + +fun testing() { + foo()["str"] +} + + + diff --git a/idea/testData/quickfix/autoImports/indexCallExtensionGetNoOperator.test b/idea/testData/quickfix/autoImports/indexCallExtensionGetNoOperator.test new file mode 100644 index 00000000000..b993bd85307 --- /dev/null +++ b/idea/testData/quickfix/autoImports/indexCallExtensionGetNoOperator.test @@ -0,0 +1,48 @@ +// FILE: first.before.kt +// "Import" "false" +// ERROR: Unresolved reference: foo()["str"] +// ERROR: No get method providing array access +// ACTION: Create extension function 'get' +// ACTION: Create member function 'get' +// ACTION: Replace overloaded operator with function call + + +package testing + +import some.Some + +fun foo(): Some = Some() + +fun testing() { + foo()["str"] +} + + + +// FILE: second.kt +package some + +public class Some + +fun Some.get(s: String) {} + + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference: foo()["str"] +// ERROR: No get method providing array access + +package testing + +import some.Some +import some.get + +fun foo(): Some = Some() + +fun testing() { + foo()["str"] +} + + + diff --git a/idea/testData/quickfix/autoImports/indexCallExtensionSet.test b/idea/testData/quickfix/autoImports/indexCallExtensionSet.test new file mode 100644 index 00000000000..44f7aa3109a --- /dev/null +++ b/idea/testData/quickfix/autoImports/indexCallExtensionSet.test @@ -0,0 +1,40 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Unresolved reference: foo()["other"] +// ERROR: No set method providing array access + +package testing + +import some.Some + +fun foo(): Some = Some() + +fun testing() { + foo()["other"] = 1 +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.set(s: String) {} + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference: foo()["other"] +// ERROR: No set method providing array access + +package testing + +import some.Some +import some.set + +fun foo(): Some = Some() + +fun testing() { + foo()["other"] = 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/indexCallNoImportWhenGetNeededButSetAvailable.test b/idea/testData/quickfix/autoImports/indexCallNoImportWhenGetNeededButSetAvailable.test new file mode 100644 index 00000000000..35a5c5a5e20 --- /dev/null +++ b/idea/testData/quickfix/autoImports/indexCallNoImportWhenGetNeededButSetAvailable.test @@ -0,0 +1,31 @@ +// FILE: first.before.kt +// "Import" "false" +// ERROR: Unresolved reference: foo()["str"] +// ERROR: No set method providing array access +// ACTION: Create extension function 'set' +// ACTION: Create member function 'set' +// ACTION: Replace overloaded operator with function call + + +package testing + +import some.Some + +fun foo(): Some = Some() + +fun testing() { + foo()["str"] = 1 +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.get(s: String) {} + + +// FILE: first.after.kt +// Empty File \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/indexCallNoImportWhenSetNeededButGetAvailable.test b/idea/testData/quickfix/autoImports/indexCallNoImportWhenSetNeededButGetAvailable.test new file mode 100644 index 00000000000..bc84129f304 --- /dev/null +++ b/idea/testData/quickfix/autoImports/indexCallNoImportWhenSetNeededButGetAvailable.test @@ -0,0 +1,31 @@ +// FILE: first.before.kt +// "Import" "false" +// ERROR: Unresolved reference: foo()["str"] +// ERROR: No get method providing array access +// ACTION: Create extension function 'get' +// ACTION: Create member function 'get' +// ACTION: Replace overloaded operator with function call + + +package testing + +import some.Some + +fun foo(): Some = Some() + +fun testing() { + foo()["str"] +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.set(s: String) {} + + +// FILE: first.after.kt +// Empty File \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/invokeExtension.test b/idea/testData/quickfix/autoImports/invokeExtension.test new file mode 100644 index 00000000000..1b1a4efa588 --- /dev/null +++ b/idea/testData/quickfix/autoImports/invokeExtension.test @@ -0,0 +1,41 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Expression 'Some()' of type 'some.Some' cannot be invoked as a function. The function invoke() is not found + +package testing + +import some.Some + +fun testing() { + Some()("str") +} +//----------------------- + + +// FILE: second.kt +// "Import" "true" +// ERROR: Expression 'Some()' of type 'some.Some' cannot be invoked as a function. The function invoke() is not found + +package some + +public class Some + +operator fun Some.invoke(s: String) {} +//----------------------- + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Expression 'Some()' of type 'some.Some' cannot be invoked as a function. The function invoke() is not found + +package testing + +import some.Some +import some.invoke + +fun testing() { + Some()("str") +} +//----------------------- + + diff --git a/idea/testData/quickfix/autoImports/invokeExtensionNoOperator.test b/idea/testData/quickfix/autoImports/invokeExtensionNoOperator.test new file mode 100644 index 00000000000..6dc952e29e4 --- /dev/null +++ b/idea/testData/quickfix/autoImports/invokeExtensionNoOperator.test @@ -0,0 +1,47 @@ +// FILE: first.before.kt +// "Import" "false" +// ERROR: Expression 'Some()' of type 'some.Some' cannot be invoked as a function. The function invoke() is not found +// ACTION: Create extension function 'invoke' +// ACTION: Create member function 'invoke' + + +package testing + +import some.Some + +fun testing() { + Some()("str") +} +//----------------------- + + +// FILE: second.kt +// "Import" "true" +// ERROR: Expression 'Some()' of type 'some.Some' cannot be invoked as a function. The function invoke() is not found + +package some + +public class Some + +fun Some.invoke(s: String) {} +//----------------------- + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Expression 'Some()' of type 'some.Some' cannot be invoked as a function. The function invoke() is not found +// ACTION: Create extension function 'invoke' +// ACTION: Create member function 'invoke' + + +package testing + +import some.Some +import some.invoke + +fun testing() { + Some()("str") +} +//----------------------- + + diff --git a/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent1.test b/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent1.test new file mode 100644 index 00000000000..fb7d5966eea --- /dev/null +++ b/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent1.test @@ -0,0 +1,42 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function + +package testing + +import some.Some +import some.component2 + +fun testing() { + val (a, b) = Some() +} +//----------------------- + + +// FILE: second.kt + +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 + +package testing + +import some.Some +import some.component1 +import some.component2 + +fun testing() { + val (a, b) = Some() +} +//----------------------- + + diff --git a/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent2.test b/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent2.test new file mode 100644 index 00000000000..557ffc3a875 --- /dev/null +++ b/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent2.test @@ -0,0 +1,42 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Multi-declaration initializer of type some.Some must have a 'component2()' function + +package testing + +import some.Some +import some.component1 + +fun testing() { + val (a, b) = Some() +} +//----------------------- + + +// FILE: second.kt + +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 'component2()' function + +package testing + +import some.Some +import some.component1 +import some.component2 + +fun testing() { + val (a, b) = Some() +} +//----------------------- + + diff --git a/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponentNoOperator.test b/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponentNoOperator.test new file mode 100644 index 00000000000..400aaf6ee17 --- /dev/null +++ b/idea/testData/quickfix/autoImports/multiDeclarationExtensionComponentNoOperator.test @@ -0,0 +1,30 @@ +// FILE: first.before.kt +// "Import" "false" +// ERROR: Multi-declaration initializer of type some.Some must have a 'component1()' function +// ACTION: Create extension function 'component1' +// ACTION: Create member function 'component1' + + +package testing + +import some.Some +import some.component2 + +fun testing() { + val (a, b) = Some() +} +//----------------------- + + +// FILE: second.kt +package some + +public class Some + +fun Some.component1() = 1 +operator fun Some.component2() = 3 +//----------------------- + + +// FILE: first.after.kt +// -- Empty file -- \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/operatorAssignPlus.test b/idea/testData/quickfix/autoImports/operatorAssignPlus.test new file mode 100644 index 00000000000..dde65a0dfdc --- /dev/null +++ b/idea/testData/quickfix/autoImports/operatorAssignPlus.test @@ -0,0 +1,39 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
  • public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String defined in kotlin
+ +package testing + +import some.Some + +fun testing() { + var s = Some() + s += 1 +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.plus(i: Int) : Some = this + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
  • public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String defined in kotlin
+ +package testing + +import some.Some +import some.plus + +fun testing() { + var s = Some() + s += 1 +} + + + diff --git a/idea/testData/quickfix/autoImports/operatorAssignPlusAssign.test b/idea/testData/quickfix/autoImports/operatorAssignPlusAssign.test new file mode 100644 index 00000000000..5daeb1d6b9e --- /dev/null +++ b/idea/testData/quickfix/autoImports/operatorAssignPlusAssign.test @@ -0,0 +1,39 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
  • public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String defined in kotlin
+ +package testing + +import some.Some + +fun testing() { + var s = Some() + s += 1 +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.plusAssign(i: Int) {} + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
  • public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String defined in kotlin
+ +package testing + +import some.Some +import some.plusAssign + +fun testing() { + var s = Some() + s += 1 +} + + + diff --git a/idea/testData/quickfix/autoImports/operatorAssignPlusTwoVariantsDifferentPackages.test b/idea/testData/quickfix/autoImports/operatorAssignPlusTwoVariantsDifferentPackages.test new file mode 100644 index 00000000000..7cb39042416 --- /dev/null +++ b/idea/testData/quickfix/autoImports/operatorAssignPlusTwoVariantsDifferentPackages.test @@ -0,0 +1,47 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
  • public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String defined in kotlin
+ +package testing + +import some.Some + +fun testing() { + var s = Some() + s += 1 +} + + + +// FILE: second.kt +package some + +public class Some + +operator fun Some.plusAssign(i: Int) {} + +// FILE: second.kt +// Lexicography is before "some" +package aaa + +import some.Some + +operator fun Some.plus(i: Int) : Some = this + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
  • public operator fun kotlin.String?.plus(other: kotlin.Any?): kotlin.String defined in kotlin
+ +package testing + +import some.Some +import some.plusAssign + +fun testing() { + var s = Some() + s += 1 +} + + + diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index dc36c88dc1a..d713e81a8db 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -83,6 +83,18 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } + @TestMetadata("delegateExtensionGet.test") + public void testDelegateExtensionGet() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/delegateExtensionGet.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("delegateExtensionSet.test") + public void testDelegateExtensionSet() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/delegateExtensionSet.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("divOperator.before.Main.kt") public void testDivOperator() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/divOperator.before.Main.kt"); @@ -143,6 +155,36 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } + @TestMetadata("indexCallExtensionGet.test") + public void testIndexCallExtensionGet() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/indexCallExtensionGet.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("indexCallExtensionGetNoOperator.test") + public void testIndexCallExtensionGetNoOperator() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/indexCallExtensionGetNoOperator.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("indexCallExtensionSet.test") + public void testIndexCallExtensionSet() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/indexCallExtensionSet.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("indexCallNoImportWhenGetNeededButSetAvailable.test") + public void testIndexCallNoImportWhenGetNeededButSetAvailable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/indexCallNoImportWhenGetNeededButSetAvailable.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("indexCallNoImportWhenSetNeededButGetAvailable.test") + public void testIndexCallNoImportWhenSetNeededButGetAvailable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/indexCallNoImportWhenSetNeededButGetAvailable.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("infixCall.before.Main.kt") public void testInfixCall() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/infixCall.before.Main.kt"); @@ -155,12 +197,42 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } + @TestMetadata("invokeExtension.test") + public void testInvokeExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/invokeExtension.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("invokeExtensionNoOperator.test") + public void testInvokeExtensionNoOperator() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/invokeExtensionNoOperator.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("minusOperator.before.Main.kt") public void testMinusOperator() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/minusOperator.before.Main.kt"); doTestWithExtraFile(fileName); } + @TestMetadata("multiDeclarationExtensionComponent1.test") + public void testMultiDeclarationExtensionComponent1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent1.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("multiDeclarationExtensionComponent2.test") + public void testMultiDeclarationExtensionComponent2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionComponent2.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("multiDeclarationExtensionComponentNoOperator.test") + public void testMultiDeclarationExtensionComponentNoOperator() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/multiDeclarationExtensionComponentNoOperator.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("nestedClass.before.Main.kt") public void testNestedClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/nestedClass.before.Main.kt"); @@ -239,6 +311,24 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } + @TestMetadata("operatorAssignPlus.test") + public void testOperatorAssignPlus() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/operatorAssignPlus.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("operatorAssignPlusAssign.test") + public void testOperatorAssignPlusAssign() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/operatorAssignPlusAssign.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("operatorAssignPlusTwoVariantsDifferentPackages.test") + public void testOperatorAssignPlusTwoVariantsDifferentPackages() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/operatorAssignPlusTwoVariantsDifferentPackages.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("packageClass.before.Main.kt") public void testPackageClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/packageClass.before.Main.kt");