diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 6ba01356aea..93fdebaa290 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -625,7 +625,7 @@ public interface Errors { DiagnosticFactory1 MISSING_RECEIVER = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION = DiagnosticFactory0.create(WARNING); + DiagnosticFactory1 ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION = DiagnosticFactory1.create(WARNING); DiagnosticFactory0 ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION = DiagnosticFactory0.create(WARNING); // Call resolution diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 41c8bf29b30..3b82f8970ca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -760,7 +760,7 @@ public class DefaultErrorMessages { MAP.put(NO_VALUE_FOR_PARAMETER, "No value passed for parameter ''{0}''", NAME); MAP.put(MISSING_RECEIVER, "A receiver of type {0} is required", RENDER_TYPE); MAP.put(NO_RECEIVER_ALLOWED, "No receiver can be passed to this function or property"); - MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION, "Assigning single elements to varargs in named form is deprecated"); + MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION, "Assigning single elements to varargs in named form is deprecated", TO_STRING); MAP.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION, "Assigning single elements to varargs in named form is deprecated"); MAP.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt index 285a6e79526..5c71ff19f1f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssigningNamedArgumentToVarargChecker.kt @@ -53,7 +53,7 @@ class AssigningNamedArgumentToVarargChecker : CallChecker { checkAssignmentOfSingleElementInAnnotation(argument, argumentExpression, context) } else { - checkAssignmentOfSingleElementInFunction(argument, argumentExpression, context) + checkAssignmentOfSingleElementInFunction(argument, argumentExpression, context, parameterDescriptor) } } @@ -75,10 +75,11 @@ class AssigningNamedArgumentToVarargChecker : CallChecker { private fun checkAssignmentOfSingleElementInFunction( argument: ValueArgument, argumentExpression: KtExpression, - context: ResolutionContext<*> + context: ResolutionContext<*>, + parameterDescriptor: ValueParameterDescriptor ) { if (!argument.hasSpread()) { - context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.on(argumentExpression)) + context.trace.report(Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.on(argumentExpression, parameterDescriptor.type)) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 3bf32a3ba8b..9a939866246 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -518,5 +518,6 @@ class QuickFixRegistrar : QuickFixContributor { ANNOTATION_USED_AS_ANNOTATION_ARGUMENT.registerFactory(RemoveAtFromAnnotationArgument) ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION.registerFactory(ReplaceWithArrayCallInAnnotationFix) + ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.registerFactory(SurroundWithArrayOfWithSpreadOperatorInFunctionFix) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithArrayOfWithSpreadOperatorInFunctionFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithArrayOfWithSpreadOperatorInFunctionFix.kt new file mode 100644 index 00000000000..5ab4096d6b0 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithArrayOfWithSpreadOperatorInFunctionFix.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.resolve.CollectionLiteralResolver.Companion.ARRAY_OF_FUNCTION +import org.jetbrains.kotlin.resolve.CollectionLiteralResolver.Companion.PRIMITIVE_TYPE_TO_ARRAY + +class SurroundWithArrayOfWithSpreadOperatorInFunctionFix( + val wrapper: Name, + argument: KtExpression +) : KotlinQuickFixAction(argument) { + override fun getText() = "Surround with *$wrapper(...)" + + override fun getFamilyName() = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val argument = element?.getParentOfType(false) ?: return + val argumentName = argument.getArgumentName()?.asName ?: return + val argumentExpression = argument.getArgumentExpression() ?: return + + val factory = KtPsiFactory(argumentExpression) + + val surroundedWithArrayOf = factory.createExpressionByPattern("$wrapper($0)", argumentExpression) + val newArgument = factory.createArgument(surroundedWithArrayOf, argumentName, isSpread = true) + + argument.replace(newArgument) + } + + companion object : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + val actualDiagnostic = Errors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.cast(diagnostic) + val parameterType = actualDiagnostic.a + + val wrapper = PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayElementType(parameterType)] ?: ARRAY_OF_FUNCTION + return SurroundWithArrayOfWithSpreadOperatorInFunctionFix(wrapper, actualDiagnostic.psiElement) + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt new file mode 100644 index 00000000000..002a7e9c10f --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt @@ -0,0 +1,8 @@ +// "Surround with *arrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +fun anyFoo(vararg a: Any) {} + +fun test() { + anyFoo(a = intArrayOf(1)) +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt.after b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt.after new file mode 100644 index 00000000000..1742d81541d --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt.after @@ -0,0 +1,8 @@ +// "Surround with *arrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +fun anyFoo(vararg a: Any) {} + +fun test() { + anyFoo(a = *arrayOf(intArrayOf(1))) +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt new file mode 100644 index 00000000000..fd41853c89e --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt @@ -0,0 +1,8 @@ +// "Surround with *intArrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +fun foo(vararg s: Int) {} + +fun test() { + foo(s = 1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt.after b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt.after new file mode 100644 index 00000000000..e1baabbdd86 --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt.after @@ -0,0 +1,8 @@ +// "Surround with *intArrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +fun foo(vararg s: Int) {} + +fun test() { + foo(s = *intArrayOf(1)) +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt new file mode 100644 index 00000000000..566dcba3857 --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt @@ -0,0 +1,8 @@ +// "Surround with *arrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +fun foo(vararg s: String) {} + +fun test() { + foo(s = "value") +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt.after b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt.after new file mode 100644 index 00000000000..a6f4e7c2e10 --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt.after @@ -0,0 +1,8 @@ +// "Surround with *arrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +fun foo(vararg s: String) {} + +fun test() { + foo(s = *arrayOf("value")) +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt new file mode 100644 index 00000000000..a48ebe7f75c --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt @@ -0,0 +1,8 @@ +// "Surround with *arrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +class Foo(vararg val p: T) + +fun test() { + Foo(p = 123) +} \ No newline at end of file diff --git a/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt.after b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt.after new file mode 100644 index 00000000000..d0dbf24d87f --- /dev/null +++ b/idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt.after @@ -0,0 +1,8 @@ +// "Surround with *arrayOf(...)" "true" +// LANGUAGE_VERSION: 1.2 + +class Foo(vararg val p: T) + +fun test() { + Foo(p = *arrayOf(123)) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 7215eb40544..5c0631ba9f7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -10428,6 +10428,39 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SurroundWithArrayOfForNamedArgumentsToVarargs extends AbstractQuickFixTest { + public void testAllFilesPresentInSurroundWithArrayOfForNamedArgumentsToVarargs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("replaceForVarargOfAny.kt") + public void testReplaceForVarargOfAny() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceForVarargOfAny.kt"); + doTest(fileName); + } + + @TestMetadata("replaceToArrayOfPrimitiveTypes.kt") + public void testReplaceToArrayOfPrimitiveTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/replaceToArrayOfPrimitiveTypes.kt"); + doTest(fileName); + } + + @TestMetadata("simpleNamedArgumentToVararg.kt") + public void testSimpleNamedArgumentToVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/simpleNamedArgumentToVararg.kt"); + doTest(fileName); + } + + @TestMetadata("surroundWithSpreadForConstructorCall.kt") + public void testSurroundWithSpreadForConstructorCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/surroundWithArrayOfForNamedArgumentsToVarargs/surroundWithSpreadForConstructorCall.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/surroundWithNullCheck") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)