From cca64b8fabad869032a461752c2693cb00f22bb9 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Mon, 27 Jul 2020 13:03:45 +0300 Subject: [PATCH] NI: use the inferred type to check of nullable array for vararg ^KT-40555 Fixed --- ...FirOldFrontendDiagnosticsTestGenerated.java | 5 +++++ .../NullableVarargArgumentCallChecker.kt | 18 +++++++++++++----- .../inferredNullableArrayAsVararg.fir.kt | 15 +++++++++++++++ .../varargs/inferredNullableArrayAsVararg.kt | 15 +++++++++++++++ .../varargs/inferredNullableArrayAsVararg.txt | 14 ++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 5 +++++ .../DiagnosticsUsingJavacTestGenerated.java | 5 +++++ 7 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.fir.kt create mode 100644 compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt create mode 100644 compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.txt diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 282b4bbbb43..d35a5912ee8 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -24847,6 +24847,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/varargs/assigningSingleElementsInNamedFormFunDeprecation_before.kt"); } + @TestMetadata("inferredNullableArrayAsVararg.kt") + public void testInferredNullableArrayAsVararg() throws Exception { + runTest("compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt"); + } + @TestMetadata("kt1781.kt") public void testKt1781() throws Exception { runTest("compiler/testData/diagnostics/tests/varargs/kt1781.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/NullableVarargArgumentCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/NullableVarargArgumentCallChecker.kt index 39bb1cbc6e2..7f9e29b9895 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/NullableVarargArgumentCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/NullableVarargArgumentCallChecker.kt @@ -8,12 +8,13 @@ package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE_INFO import org.jetbrains.kotlin.resolve.calls.components.stableType +import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall -import org.jetbrains.kotlin.resolve.calls.tower.ExpressionKotlinCallArgumentImpl import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl -import org.jetbrains.kotlin.resolve.calls.tower.NewVariableAsFunctionResolvedCallImpl +import org.jetbrains.kotlin.resolve.calls.tower.SimplePSIKotlinCallArgument import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.types.FlexibleType import org.jetbrains.kotlin.types.TypeUtils @@ -29,11 +30,18 @@ object NullableVarargArgumentCallChecker : CallChecker { if (resolvedCall !is NewResolvedCallImpl<*>) return for (argument in resolvedCall.argumentMappingByOriginal.values) { for (arg in argument.arguments) { - if (!arg.isSpread || arg !is ExpressionKotlinCallArgumentImpl) continue - val spreadElement = arg.valueArgument.getSpreadElement() ?: continue + if (!arg.isSpread || arg !is SimplePSIKotlinCallArgument) continue + val spreadElement = arg.valueArgument.getSpreadElement() ?: continue val receiver = arg.receiver.safeAs() ?: continue - val type = receiver.stableType + + val type = if (receiver.stableType.constructor is TypeVariableTypeConstructor) { + context.trace.bindingContext[EXPRESSION_TYPE_INFO, arg.valueArgument.getArgumentExpression()]?.type + ?: receiver.stableType + } else { + receiver.stableType + } + if (type !is FlexibleType && TypeUtils.isNullableType(type)) { context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement)) } diff --git a/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.fir.kt b/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.fir.kt new file mode 100644 index 00000000000..52a587bd6c1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.fir.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +// FILE: Test.java +public class Test { + static public void foo(String ... x) { + + } +} + +// FILE: test.kt +fun select(vararg x: T) = x[1] + +fun main(x: Array?) { + Test.foo(*(select(arrayOf(""), null))) // no compilation errors before the fix, NPE +} diff --git a/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt b/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt new file mode 100644 index 00000000000..7bdcd493823 --- /dev/null +++ b/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +// FILE: Test.java +public class Test { + static public void foo(String ... x) { + + } +} + +// FILE: test.kt +fun select(vararg x: T) = x[1] + +fun main(x: Array?) { + Test.foo(*(select(arrayOf(""), null))) // no compilation errors before the fix, NPE +} diff --git a/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.txt b/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.txt new file mode 100644 index 00000000000..19c48ba9dda --- /dev/null +++ b/compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.txt @@ -0,0 +1,14 @@ +package + +public fun main(/*0*/ x: kotlin.Array?): kotlin.Unit +public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T + +public open class Test { + public constructor Test() + 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 + + // Static members + public open fun foo(/*0*/ vararg x: kotlin.String! /*kotlin.Array<(out) kotlin.String!>!*/): kotlin.Unit +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 42230663e72..f6a8c14e4aa 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -24929,6 +24929,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/varargs/assigningSingleElementsInNamedFormFunDeprecation_before.kt"); } + @TestMetadata("inferredNullableArrayAsVararg.kt") + public void testInferredNullableArrayAsVararg() throws Exception { + runTest("compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt"); + } + @TestMetadata("kt1781.kt") public void testKt1781() throws Exception { runTest("compiler/testData/diagnostics/tests/varargs/kt1781.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 103599c6329..b950896e5cf 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -24849,6 +24849,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/varargs/assigningSingleElementsInNamedFormFunDeprecation_before.kt"); } + @TestMetadata("inferredNullableArrayAsVararg.kt") + public void testInferredNullableArrayAsVararg() throws Exception { + runTest("compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt"); + } + @TestMetadata("kt1781.kt") public void testKt1781() throws Exception { runTest("compiler/testData/diagnostics/tests/varargs/kt1781.kt");