From 69704c017f0e395628fbd1494fd6a59d90fcb6f5 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 15 Jun 2016 17:55:13 +0300 Subject: [PATCH] Create from Usage: Suggest "Create function/secondary constructor" quick fix on argument type mismatch #KT-11864 Fixed (cherry picked from commit 1912783) --- ChangeLog.md | 1 + .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 ++ .../CreateCallableFromCallActionFactory.kt | 9 +++++---- .../createFunction/call/argumentTypeMismatch.kt | 6 ++++++ .../call/argumentTypeMismatch.kt.after | 10 ++++++++++ .../argumentTypeMismatch.kt | 7 +++++++ .../argumentTypeMismatch.kt.after | 9 +++++++++ ...xclToRemoveNullabilityDisabledWhenItCannotHelp.kt | 1 + .../letClassImplementGenericInterfaceTwice.kt | 1 + .../letClassImplementGenericStarInterface.kt | 1 + .../letClassImplementIndirectlyInheritedInterface.kt | 1 + .../typeMismatch/letStringImplementInterface.kt | 1 + .../kotlin/idea/quickfix/QuickFixTestGenerated.java | 12 ++++++++++++ 13 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt create mode 100644 idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt.after diff --git a/ChangeLog.md b/ChangeLog.md index 5d3ba62de43..321a68cbd21 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -153,6 +153,7 @@ - [`KT-11768`](https://youtrack.jetbrains.com/issue/KT-11768) "Introduce local variable" intention - [`KT-11806`](https://youtrack.jetbrains.com/issue/KT-11806) Quick-fix to increase visibility for invisible member - [`KT-11807`](https://youtrack.jetbrains.com/issue/KT-11807) Use function body template when generating overriding functions with default body +- [`KT-11864`](https://youtrack.jetbrains.com/issue/KT-11864) Suggest "Create function/secondary constructor" quick fix on argument type mismatch - [`KT-11876`](https://youtrack.jetbrains.com/issue/KT-11876) Quickfix for "Extension function type is not allowed as supertype" error - [`KT-11920`](https://youtrack.jetbrains.com/issue/KT-11920) "Increase visibility" and "Decrease visibility" quickfixes for exposed visibility errors - [`KT-12089`](https://youtrack.jetbrains.com/issue/KT-12089) Quickfix "Make primary constructor parameter a property" diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 882e53816e6..6051e7ee931 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -284,6 +284,8 @@ class QuickFixRegistrar : QuickFixContributor { TOO_MANY_ARGUMENTS.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES) EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES) NONE_APPLICABLE.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES) + TYPE_MISMATCH.registerFactory(CreateCallableFromCallActionFactory.Function) + TYPE_MISMATCH.registerFactory(CreateCallableFromCallActionFactory.Constructor) NO_VALUE_FOR_PARAMETER.registerFactory(CreateConstructorFromDelegationCallActionFactory) TOO_MANY_ARGUMENTS.registerFactory(CreateConstructorFromDelegationCallActionFactory) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt index b670457ec7a..2b024fadbb3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt @@ -31,10 +31,7 @@ import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS -import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType -import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch -import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis +import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets import org.jetbrains.kotlin.resolve.calls.callUtil.getCall @@ -74,6 +71,10 @@ sealed class CreateCallableFromCallActionFactory( Errors.TOO_MANY_ARGUMENTS, Errors.NONE_APPLICABLE -> diagElement.getNonStrictParentOfType() + Errors.TYPE_MISMATCH -> diagElement + .getParentOfTypeAndBranch { getArgumentExpression() } + ?.getStrictParentOfType() + else -> throw AssertionError("Unexpected diagnostic: ${diagnostic.factory}") } as? KtExpression } diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt new file mode 100644 index 00000000000..fe873a72743 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt @@ -0,0 +1,6 @@ +// "Create function 'foo'" "true" +fun foo(n: Int) {} + +fun test() { + foo("abc") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt.after new file mode 100644 index 00000000000..395a40ff192 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt.after @@ -0,0 +1,10 @@ +// "Create function 'foo'" "true" +fun foo(n: Int) {} + +fun test() { + foo("abc") +} + +fun foo(n: String) { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. +} diff --git a/idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt b/idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt new file mode 100644 index 00000000000..f2c88815fd0 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt @@ -0,0 +1,7 @@ +// "Create secondary constructor" "true" +// ERROR: None of the following functions can be called with the arguments supplied:
public constructor Foo(n: Int) defined in Foo
public constructor Foo(n: String) defined in Foo +class Foo(val n: Int) + +fun test() { + val foo = Foo("abc") +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt.after b/idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt.after new file mode 100644 index 00000000000..b3bd9a06113 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt.after @@ -0,0 +1,9 @@ +// "Create secondary constructor" "true" +// ERROR: None of the following functions can be called with the arguments supplied:
public constructor Foo(n: Int) defined in Foo
public constructor Foo(n: String) defined in Foo +class Foo(val n: Int) { + constructor(n: String) : this() +} + +fun test() { + val foo = Foo("abc") +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/addExclExclToRemoveNullabilityDisabledWhenItCannotHelp.kt b/idea/testData/quickfix/typeMismatch/addExclExclToRemoveNullabilityDisabledWhenItCannotHelp.kt index c01e915b3ff..4799c240ecb 100644 --- a/idea/testData/quickfix/typeMismatch/addExclExclToRemoveNullabilityDisabledWhenItCannotHelp.kt +++ b/idea/testData/quickfix/typeMismatch/addExclExclToRemoveNullabilityDisabledWhenItCannotHelp.kt @@ -1,5 +1,6 @@ // "Add non-null asserted (!!) call" "false" // ACTION: Change parameter 's' type of function 'other' to 'String?' +// ACTION: Create function 'other' // ERROR: Type mismatch: inferred type is String? but Int was expected fun test() { val s: String? = "" diff --git a/idea/testData/quickfix/typeMismatch/letClassImplementGenericInterfaceTwice.kt b/idea/testData/quickfix/typeMismatch/letClassImplementGenericInterfaceTwice.kt index 4fd2d7510ae..23567b18681 100644 --- a/idea/testData/quickfix/typeMismatch/letClassImplementGenericInterfaceTwice.kt +++ b/idea/testData/quickfix/typeMismatch/letClassImplementGenericInterfaceTwice.kt @@ -1,6 +1,7 @@ // "Let 'B' implement interface 'A'" "false" // ACTION: Change parameter 'a' type of function 'let.implement.foo' to 'B' // ACTION: Convert to expression body +// ACTION: Create function 'foo' // ERROR: Type mismatch: inferred type is B but A was expected package let.implement diff --git a/idea/testData/quickfix/typeMismatch/letClassImplementGenericStarInterface.kt b/idea/testData/quickfix/typeMismatch/letClassImplementGenericStarInterface.kt index df1dcd0300f..1a9777d8bf0 100644 --- a/idea/testData/quickfix/typeMismatch/letClassImplementGenericStarInterface.kt +++ b/idea/testData/quickfix/typeMismatch/letClassImplementGenericStarInterface.kt @@ -1,6 +1,7 @@ // "Let 'B' implement interface 'A<*>'" "false" // ACTION: Change parameter 'a' type of function 'let.implement.foo' to 'B' // ACTION: Convert to expression body +// ACTION: Create function 'foo' // ERROR: Type mismatch: inferred type is B but A<*> was expected package let.implement diff --git a/idea/testData/quickfix/typeMismatch/letClassImplementIndirectlyInheritedInterface.kt b/idea/testData/quickfix/typeMismatch/letClassImplementIndirectlyInheritedInterface.kt index dc7bd0316cd..b32d422dd96 100644 --- a/idea/testData/quickfix/typeMismatch/letClassImplementIndirectlyInheritedInterface.kt +++ b/idea/testData/quickfix/typeMismatch/letClassImplementIndirectlyInheritedInterface.kt @@ -1,6 +1,7 @@ // "Let 'B' implement interface 'A'" "false" // ACTION: Change parameter 'a' type of function 'let.implement.foo' to 'B' // ACTION: Convert to expression body +// ACTION: Create function 'foo' // ERROR: Type mismatch: inferred type is B but A was expected package let.implement diff --git a/idea/testData/quickfix/typeMismatch/letStringImplementInterface.kt b/idea/testData/quickfix/typeMismatch/letStringImplementInterface.kt index 5fa0d8beb54..04dd8d6bb0f 100644 --- a/idea/testData/quickfix/typeMismatch/letStringImplementInterface.kt +++ b/idea/testData/quickfix/typeMismatch/letStringImplementInterface.kt @@ -2,6 +2,7 @@ // ACTION: Change parameter 'a' type of function 'let.implement.foo' to 'String' // ACTION: Convert to expression body // ACTION: To raw string literal +// ACTION: Create function 'foo' // ERROR: Type mismatch: inferred type is String but A was expected package let.implement diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 0f497a20a49..c35d6efc07e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1929,6 +1929,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createFunction/call"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); } + @TestMetadata("argumentTypeMismatch.kt") + public void testArgumentTypeMismatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/argumentTypeMismatch.kt"); + doTest(fileName); + } + @TestMetadata("callInAnnotationEntry.kt") public void testCallInAnnotationEntry() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/callInAnnotationEntry.kt"); @@ -2680,6 +2686,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createSecondaryConstructor"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); } + @TestMetadata("argumentTypeMismatch.kt") + public void testArgumentTypeMismatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createSecondaryConstructor/argumentTypeMismatch.kt"); + doTest(fileName); + } + @TestMetadata("callWithExpectedType.kt") public void testCallWithExpectedType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createSecondaryConstructor/callWithExpectedType.kt");