Use Intrinsics.checkNotNullParameter to throw NPE in parameter null checks
Similarly to previous commits, this method was unused, so we're changing its semantics in API version >= 1.4. #KT-22275 In Progress
This commit is contained in:
@@ -954,7 +954,7 @@ public class AsmUtil {
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
if (receiverParameter != null) {
|
||||
String name = getNameForReceiverParameter(descriptor, state.getBindingContext(), state.getLanguageVersionSettings());
|
||||
genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, name, descriptor);
|
||||
genParamAssertion(v, state, frameMap, receiverParameter, name, descriptor);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -963,17 +963,17 @@ public class AsmUtil {
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
if (receiverParameter != null) {
|
||||
String name = getNameForReceiverParameter(descriptor, state.getBindingContext(), state.getLanguageVersionSettings());
|
||||
genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, name, descriptor);
|
||||
genParamAssertion(v, state, frameMap, receiverParameter, name, descriptor);
|
||||
}
|
||||
|
||||
for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
|
||||
genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString(), descriptor);
|
||||
genParamAssertion(v, state, frameMap, parameter, parameter.getName().asString(), descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
private static void genParamAssertion(
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@NotNull GenerationState state,
|
||||
@NotNull FrameMap frameMap,
|
||||
@NotNull ParameterDescriptor parameter,
|
||||
@NotNull String name,
|
||||
@@ -982,7 +982,7 @@ public class AsmUtil {
|
||||
KotlinType type = parameter.getType();
|
||||
if (isNullableType(type) || InlineClassesUtilsKt.isNullableUnderlyingType(type)) return;
|
||||
|
||||
Type asmType = typeMapper.mapType(type);
|
||||
Type asmType = state.getTypeMapper().mapType(type);
|
||||
if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
|
||||
StackValue value;
|
||||
if (JvmCodegenUtil.isDeclarationOfBigArityFunctionInvoke(containingDeclaration) ||
|
||||
@@ -998,9 +998,10 @@ public class AsmUtil {
|
||||
}
|
||||
value.put(asmType, v);
|
||||
v.visitLdcInsn(name);
|
||||
v.invokestatic(
|
||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V", false
|
||||
);
|
||||
String methodName = state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_4) >= 0
|
||||
? "checkNotNullParameter"
|
||||
: "checkParameterIsNotNull";
|
||||
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -433,7 +433,7 @@ internal fun AbstractInsnNode.isCheckNotNull() =
|
||||
internal fun AbstractInsnNode.isCheckParameterIsNotNull() =
|
||||
isInsn<MethodInsnNode>(Opcodes.INVOKESTATIC) {
|
||||
owner == IntrinsicMethods.INTRINSICS_CLASS_NAME &&
|
||||
name == "checkParameterIsNotNull" &&
|
||||
(name == "checkParameterIsNotNull" || name == "checkNotNullParameter") &&
|
||||
desc == "(Ljava/lang/Object;Ljava/lang/String;)V"
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -207,7 +207,10 @@ class ExpressionCodegen(
|
||||
if (!param.type.unboxInlineClass().isNullable() && !isPrimitive(asmType)) {
|
||||
mv.load(findLocalIndex(param.symbol), asmType)
|
||||
mv.aconst(param.name.asString())
|
||||
mv.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V", false)
|
||||
val methodName =
|
||||
if (state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) "checkNotNullParameter"
|
||||
else "checkParameterIsNotNull"
|
||||
mv.invokestatic("kotlin/jvm/internal/Intrinsics", methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -48,8 +48,8 @@ class A : MutableMap<Any, Any> {
|
||||
}
|
||||
|
||||
override fun getOrDefault(key: Any, defaultValue: Any): Any {
|
||||
// this condition can not be true because of checkParameterIsNotNull checks in the begin of every method, but it's left here
|
||||
// to emphasize that we expect these parameters are not null
|
||||
// this condition can not be true because of checkParameterIsNotNull/checkNotNullParameter checks in the begin of every method,
|
||||
// but it's left here to emphasize that we expect these parameters are not null
|
||||
if (key == null || defaultValue == null) {
|
||||
throw IllegalArgumentException("fail")
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// !API_VERSION: LATEST
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: A.java
|
||||
|
||||
public class A {
|
||||
public static void test() {
|
||||
new B().foo(null);
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
class B {
|
||||
fun foo(s: String) {}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
try {
|
||||
A.test()
|
||||
return "Fail: NPE should have been thrown"
|
||||
} catch (e: Throwable) {
|
||||
if (e::class != NullPointerException::class) return "Fail: exception class should be NPE: ${e::class}"
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// !API_VERSION: LATEST
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
public inline fun <R> doRun(block: () -> R): R {
|
||||
return block()
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
return doRun { "OK" }
|
||||
}
|
||||
Vendored
+2
-1
@@ -13,4 +13,5 @@ fun AsNonNullReference.nonNullReferenceExtension(b1: AsNonNullReference) {} // 2
|
||||
fun asNullablePrimitive(c: AsNonNullPrimitive?) {}
|
||||
fun asNullableReference(c: AsNonNullReference?) {}
|
||||
|
||||
// 8 checkParameterIsNotNull
|
||||
// 8 checkParameterIsNotNull
|
||||
// 0 checkNotNullParameter
|
||||
|
||||
+2
-1
@@ -5,4 +5,5 @@ inline class AsAny(val a: Any?)
|
||||
fun asNotNullAny(a: AsAny) {}
|
||||
fun AsAny.asNotNullAnyExtension(b: AsAny): AsAny = this
|
||||
|
||||
// 0 checkParameterIsNotNull
|
||||
// 0 checkParameterIsNotNull
|
||||
// 0 checkNotNullParameter
|
||||
|
||||
@@ -32,12 +32,16 @@ class TestAccessor {
|
||||
|
||||
// @TestMethod.class:
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
|
||||
// @TestMethodOverloads.class:
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
|
||||
// @TestProperty.class:
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
|
||||
// @TestAccessor.class:
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
// 0 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter \(Ljava/lang/Object;Ljava/lang/String;\)V
|
||||
|
||||
@@ -13,3 +13,4 @@ fun bar(a: ArrayList<String>) {
|
||||
// 1 checkExpressionValueIsNotNull
|
||||
// 0 checkNotNullExpressionValue
|
||||
// 1 checkParameterIsNotNull
|
||||
// 0 checkNotNullParameter
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
fun <T : Any> foo(t: T) = t
|
||||
|
||||
// 1 checkParameterIsNotNull
|
||||
// 0 checkNotNullParameter
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// !API_VERSION: LATEST
|
||||
|
||||
fun <T : Any> foo(t: T) = t
|
||||
|
||||
// 0 checkParameterIsNotNull
|
||||
// 1 checkNotNullParameter
|
||||
+1
@@ -37,3 +37,4 @@ internal fun bar(a: A<String, Int>, b: B<String>, c: C) {
|
||||
// 3 checkExpressionValueIsNotNull
|
||||
// 0 checkNotNullExpressionValue
|
||||
// 3 checkParameterIsNotNull
|
||||
// 0 checkNotNullParameter
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// !API_VERSION: LATEST
|
||||
|
||||
fun test(s: String) = s?.length
|
||||
|
||||
// 0 IFNULL
|
||||
// 0 IFNONNULL
|
||||
// 0 intValue
|
||||
// 0 valueOf
|
||||
+5
@@ -16429,6 +16429,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("parameterNullCheckThrowsNpe_1_4.kt")
|
||||
public void testParameterNullCheckThrowsNpe_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsNpe_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveCheckWithSideEffect.kt")
|
||||
public void testPrimitiveCheckWithSideEffect() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
|
||||
|
||||
+18
@@ -2473,6 +2473,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/nullChecks")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NullChecks extends AbstractBlackBoxInlineCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNullChecks() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nullChecks"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("parameterNullCheck_1_4.kt")
|
||||
public void testParameterNullCheck_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/nullChecks/parameterNullCheck_1_4.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/optimizations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -3163,6 +3163,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/assertionForNotNullTypeParam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("assertionForNotNullTypeParam_1_4.kt")
|
||||
public void testAssertionForNotNullTypeParam_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/assertionForNotNullTypeParam_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("doNotGenerateParamAssertions.kt")
|
||||
public void testDoNotGenerateParamAssertions() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/doNotGenerateParamAssertions.kt");
|
||||
@@ -3296,6 +3301,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("redundantSafeCall_1_4.kt")
|
||||
public void testRedundantSafeCall_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("reifiedIs.kt")
|
||||
public void testReifiedIs() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/reifiedIs.kt");
|
||||
|
||||
Generated
+18
@@ -2473,6 +2473,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/nullChecks")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NullChecks extends AbstractCompileKotlinAgainstInlineKotlinTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNullChecks() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nullChecks"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("parameterNullCheck_1_4.kt")
|
||||
public void testParameterNullCheck_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/nullChecks/parameterNullCheck_1_4.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/optimizations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+5
@@ -16429,6 +16429,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("parameterNullCheckThrowsNpe_1_4.kt")
|
||||
public void testParameterNullCheckThrowsNpe_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsNpe_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveCheckWithSideEffect.kt")
|
||||
public void testPrimitiveCheckWithSideEffect() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
|
||||
|
||||
+5
@@ -15314,6 +15314,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("parameterNullCheckThrowsNpe_1_4.kt")
|
||||
public void testParameterNullCheckThrowsNpe_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsNpe_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveCheckWithSideEffect.kt")
|
||||
public void testPrimitiveCheckWithSideEffect() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
|
||||
|
||||
+18
@@ -2473,6 +2473,24 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/nullChecks")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NullChecks extends AbstractIrBlackBoxInlineCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNullChecks() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nullChecks"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("parameterNullCheck_1_4.kt")
|
||||
public void testParameterNullCheck_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/nullChecks/parameterNullCheck_1_4.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/optimizations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+10
@@ -3133,6 +3133,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/assertionForNotNullTypeParam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("assertionForNotNullTypeParam_1_4.kt")
|
||||
public void testAssertionForNotNullTypeParam_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/assertionForNotNullTypeParam_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("doNotGenerateParamAssertions.kt")
|
||||
public void testDoNotGenerateParamAssertions() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/doNotGenerateParamAssertions.kt");
|
||||
@@ -3266,6 +3271,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("redundantSafeCall_1_4.kt")
|
||||
public void testRedundantSafeCall_1_4() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall_1_4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("reifiedIs.kt")
|
||||
public void testReifiedIs() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/reifiedIs.kt");
|
||||
|
||||
@@ -126,9 +126,9 @@ public class Intrinsics {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkNotNullParameter(Object value, String message) {
|
||||
public static void checkNotNullParameter(Object value, String paramName) {
|
||||
if (value == null) {
|
||||
throw sanitizeStackTrace(new IllegalArgumentException(message));
|
||||
throw sanitizeStackTrace(new NullPointerException(paramName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user