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:
Alexander Udalov
2019-08-06 10:56:44 +02:00
parent 480313210a
commit 2baddb029c
23 changed files with 173 additions and 16 deletions
@@ -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);
}
}
@@ -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"
}
@@ -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)
}
}
@@ -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")
}
@@ -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" }
}
@@ -13,4 +13,5 @@ fun AsNonNullReference.nonNullReferenceExtension(b1: AsNonNullReference) {} // 2
fun asNullablePrimitive(c: AsNonNullPrimitive?) {}
fun asNullableReference(c: AsNonNullReference?) {}
// 8 checkParameterIsNotNull
// 8 checkParameterIsNotNull
// 0 checkNotNullParameter
@@ -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
+4
View File
@@ -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,3 +1,4 @@
fun <T : Any> foo(t: T) = t
// 1 checkParameterIsNotNull
// 0 checkNotNullParameter
@@ -0,0 +1,6 @@
// !API_VERSION: LATEST
fun <T : Any> foo(t: T) = t
// 0 checkParameterIsNotNull
// 1 checkNotNullParameter
@@ -37,3 +37,4 @@ internal fun bar(a: A<String, Int>, b: B<String>, c: C) {
// 3 checkExpressionValueIsNotNull
// 0 checkNotNullExpressionValue
// 3 checkParameterIsNotNull
// 0 checkNotNullParameter
@@ -0,0 +1,8 @@
// !API_VERSION: LATEST
fun test(s: String) = s?.length
// 0 IFNULL
// 0 IFNONNULL
// 0 intValue
// 0 valueOf
@@ -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");
@@ -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");
@@ -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)
@@ -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");
@@ -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");
@@ -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)
@@ -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));
}
}