From 142e85be04387240868d88dd3aa59f98bc765dc6 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 18 Dec 2015 19:50:21 +0300 Subject: [PATCH] Prohibit functions (and constructors) with multiple vararg parameters. --- .../jetbrains/kotlin/diagnostics/Errors.java | 2 ++ .../diagnostics/PositioningStrategies.kt | 7 +++++ .../rendering/DefaultErrorMessages.java | 1 + .../kotlin/resolve/DeclarationsChecker.kt | 18 ++++++++++++ .../expressions/FunctionsTypingVisitor.kt | 1 + .../invalidTypesInAnnotationConstructor.kt | 10 +++---- .../invalidTypesInAnnotationConstructor.txt | 24 +++++++-------- .../mulitpleVarargParameters.kt | 27 +++++++++++++++++ .../mulitpleVarargParameters.txt | 29 +++++++++++++++++++ .../valVarFunctionParameter.kt | 6 ++-- .../checkers/DiagnosticsTestGenerated.java | 6 ++++ 11 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index e7444a8e9df..6c337a08f10 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -420,6 +420,8 @@ public interface Errors { DiagnosticFactory0 USELESS_VARARG_ON_PARAMETER = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 MULTIPLE_VARARG_PARAMETERS = DiagnosticFactory0.create(ERROR, PARAMETER_VARARG_MODIFIER); + // Named parameters DiagnosticFactory0 DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = DiagnosticFactory0.create(ERROR, PARAMETER_DEFAULT_VALUE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 17b00a88b12..bbb22d7fcf8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -285,6 +285,13 @@ public object PositioningStrategies { } } + @JvmField public val PARAMETER_VARARG_MODIFIER: PositioningStrategy = object : PositioningStrategy() { + override fun mark(element: KtParameter): List { + val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!! + return markNode(varargModifier.node) + } + } + @JvmField public val CALL_ELEMENT: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: PsiElement): List { return markElement((element as? KtCallElement)?.getCalleeExpression() ?: element) 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 4b1e626faae..90416a00dcc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -234,6 +234,7 @@ public class DefaultErrorMessages { MAP.put(ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE, "An anonymous function is not allowed to specify default values for its parameters"); MAP.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless"); + MAP.put(MULTIPLE_VARARG_PARAMETERS, "Multiple vararg-parameters are prohibited"); MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties"); MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 1207a51a4a7..46bee23420c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -130,6 +130,7 @@ class DeclarationsChecker( declaration.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor) identifierChecker.checkDeclaration(declaration, trace) + checkVarargParameters(trace, constructorDescriptor) } private fun checkModifiersAndAnnotationsInPackageDirective(file: KtFile) { @@ -323,11 +324,13 @@ class DeclarationsChecker( else if (aClass is KtEnumEntry) { checkEnumEntry(aClass, classDescriptor) } + for (memberDescriptor in classDescriptor.declaredCallableMembers) { if (memberDescriptor.kind != CallableMemberDescriptor.Kind.DECLARATION) continue val member = DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor) as? KtFunction if (member != null && memberDescriptor is FunctionDescriptor) { checkFunctionExposedType(member, memberDescriptor) + checkVarargParameters(trace, memberDescriptor) } } } @@ -650,7 +653,9 @@ class DeclarationsChecker( trace.report(IMPLICIT_NOTHING_RETURN_TYPE.on(nameIdentifier ?: function)) } } + checkFunctionExposedType(function, functionDescriptor) + checkVarargParameters(trace, functionDescriptor) } private fun checkFunctionExposedType(function: KtFunction, functionDescriptor: FunctionDescriptor) { @@ -740,6 +745,19 @@ class DeclarationsChecker( } companion object { + internal fun checkVarargParameters(trace: BindingTrace, callableDescriptor: CallableDescriptor) { + val numberOfVarargParameters = callableDescriptor.valueParameters.count { it.varargElementType != null } + if (numberOfVarargParameters > 1) { + for (parameter in callableDescriptor.valueParameters) { + if (parameter.varargElementType != null) { + val parameterDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(parameter) + if (parameterDeclaration is KtParameter) { + trace.report(MULTIPLE_VARARG_PARAMETERS.on(parameterDeclaration)) + } + } + } + } + } private fun removeDuplicateTypes(conflictingTypes: MutableSet) { val iterator = conflictingTypes.iterator() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index 8a97920a74b..aa721238f8b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -109,6 +109,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre if (!function.hasBody() && !function.hasModifier(KtTokens.EXTERNAL_KEYWORD)) { context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)) } + DeclarationsChecker.checkVarargParameters(context.trace, functionDescriptor) if (isStatement) { return createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context) diff --git a/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.kt b/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.kt index d6a0f4c5b10..10e4fd9b28e 100644 --- a/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.kt +++ b/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.kt @@ -33,11 +33,6 @@ annotation class Ann8(val p1: Array, val p3: Array, val p4: Array) -annotation class Ann9(vararg val p1: String, - vararg val p2: Class<*>, - vararg val p3: MyEnum, - vararg val p4: Ann1, - vararg val p5: Int) // INCORRECT annotation class InAnn1(val p1: Int?, @@ -64,6 +59,11 @@ annotation class InAnn10(val p1: String?Ann1?) annotation class InAnn12(val p1: MyEnum?) +annotation class InAnn13(vararg val p1: String, + vararg val p2: Class<*>, + vararg val p3: MyEnum, + vararg val p4: Ann1, + vararg val p5: Int) enum class MyEnum { A diff --git a/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.txt b/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.txt index 6442b55d272..bd4201c3432 100644 --- a/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.txt +++ b/compiler/testData/diagnostics/tests/annotations/invalidTypesInAnnotationConstructor.txt @@ -83,18 +83,6 @@ package test { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } - public final annotation class Ann9 : kotlin.Annotation { - public constructor Ann9(/*0*/ vararg p1: kotlin.String /*kotlin.Array*/, /*1*/ vararg p2: java.lang.Class<*> /*kotlin.Array>*/, /*2*/ vararg p3: test.MyEnum /*kotlin.Array*/, /*3*/ vararg p4: test.Ann1 /*kotlin.Array*/, /*4*/ vararg p5: kotlin.Int /*kotlin.IntArray*/) - public final val p1: kotlin.Array - public final val p2: kotlin.Array> - public final val p3: kotlin.Array - public final val p4: kotlin.Array - public final val p5: kotlin.IntArray - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - } - public final annotation class InAnn1 : kotlin.Annotation { public constructor InAnn1(/*0*/ p1: kotlin.Int?, /*1*/ p3: kotlin.Short?, /*2*/ p4: kotlin.Long?, /*3*/ p5: kotlin.Double?, /*4*/ p6: kotlin.Float?, /*5*/ p7: kotlin.Char?, /*6*/ p8: kotlin.Boolean?) public final val p1: kotlin.Int? @@ -133,6 +121,18 @@ package test { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + public final annotation class InAnn13 : kotlin.Annotation { + public constructor InAnn13(/*0*/ vararg p1: kotlin.String /*kotlin.Array*/, /*1*/ vararg p2: java.lang.Class<*> /*kotlin.Array>*/, /*2*/ vararg p3: test.MyEnum /*kotlin.Array*/, /*3*/ vararg p4: test.Ann1 /*kotlin.Array*/, /*4*/ vararg p5: kotlin.Int /*kotlin.IntArray*/) + public final val p1: kotlin.Array + public final val p2: kotlin.Array> + public final val p3: kotlin.Array + public final val p4: kotlin.Array + public final val p5: kotlin.IntArray + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + public final annotation class InAnn4 : kotlin.Annotation { public constructor InAnn4(/*0*/ p1: kotlin.Array, /*1*/ p2: kotlin.Array?) public final val p1: kotlin.Array diff --git a/compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt b/compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt new file mode 100644 index 00000000000..f2ca787a5f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt @@ -0,0 +1,27 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED +fun test(vararg x1: Int, vararg x2: Int) { + fun test2(vararg x1: Int, vararg x2: Int) { + class LocalClass(vararg x1: Int, vararg x2: Int) { + constructor(vararg x1: Int, vararg x2: Int, xx: Int) {} + } + fun test3(vararg x1: Int, vararg x2: Int) {} + } +} + +fun Any.test(vararg x1: Int, vararg x2: Int, vararg x3: Int) {} + +interface I { + fun test(vararg x1: Int, vararg x2: Int) +} + +abstract class C(vararg x1: Int, vararg x2: Int, b: Boolean) { + fun test(vararg x1: Int, vararg x2: Int) {} + + abstract fun test2(vararg x1: Int, vararg x2: Int) + + class CC(vararg x1: Int, vararg x2: Int, b: Boolean) { + constructor(vararg x1: Int, vararg x2: Int) {} + fun test(vararg x1: Int, vararg x2: Int) {} + } +} + diff --git a/compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.txt b/compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.txt new file mode 100644 index 00000000000..ff7fc3f08d8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.txt @@ -0,0 +1,29 @@ +package + +public fun test(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit +public fun kotlin.Any.test(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/, /*2*/ vararg x3: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit + +public abstract class C { + public constructor C(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/, /*2*/ b: kotlin.Boolean) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun test(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit + public abstract fun test2(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class CC { + public constructor CC(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/) + public constructor CC(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/, /*2*/ b: kotlin.Boolean) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun test(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public interface I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun test(/*0*/ vararg x1: kotlin.Int /*kotlin.IntArray*/, /*1*/ vararg x2: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt b/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt index 70cd086ce73..acf95d9adb4 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt @@ -2,9 +2,9 @@ fun f( val a: Int, var b: Int, c: Int, - vararg var d: Int, - vararg val e: Int, - vararg f: Int + vararg var d: Int, + vararg val e: Int, + vararg f: Int ) { diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 596dbb81de0..3e6e225e8d2 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4224,6 +4224,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("mulitpleVarargParameters.kt") + public void testMulitpleVarargParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt"); + doTest(fileName); + } + @TestMetadata("MultiDeclarationErrors.kt") public void testMultiDeclarationErrors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/MultiDeclarationErrors.kt");