如何覆盖 Kotlin 生成的不必要的空检查?
How to cover unnecessary null check generated by Kotlin?
考虑以下最小的 Kotlin 示例:
fun <U> someWrapper(supplier: () -> U): () -> (U) {
return { supplier() }
}
fun foo(taskExecutor: TaskExecutor): Int {
val future = CompletableFuture.supplyAsync(someWrapper {
42
}, taskExecutor::execute)
return future.join()
}
@Test
public void shouldFoo() {
assertThat(foo(), is(42));
}
我在 Jacoco 中有分支覆盖规则,上面的代码失败了,说 2 个分支中的 1 个没有在 someWrapper
调用的行中覆盖。不幸的是,我无法排除调用 someWrapper
的所有 classes。
查看反编译后的Java代码:
public final int foo(TaskExecutor taskExecutor) {
Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
if (var10000 != null) {
Object var2 = var10000;
var10000 = new Foo$sam$java_util_function_Supplier[=11=]((Function0)var2);
}
Supplier var3 = (Supplier)var10000;
Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
this.invoke((Runnable)var1);
return Unit.INSTANCE;
}
public final void invoke(Runnable p1) {
((TaskExecutor)this.receiver).execute(p1);
}
public final KDeclarationContainer getOwner() {
return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
}
public final String getName() {
return "execute";
}
public final String getSignature() {
return "execute(Ljava/lang/Runnable;)V";
}
});
CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor[=11=](var4)));
var10000 = future.join();
Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
return ((Number)var10000).intValue();
}
我认为,问题出在 if (var10000 != null)
分支,它甚至被 IDE 标记为不必要(总是如此)。
是否可以通过某种方式调整代码以覆盖所有分支,例如。通过确保编译器不生成额外的空检查?只要我能够提供修饰的 lambda,我就可以更改 foo(..)
和 someWrapper(..)
的代码。
我使用 Kotlin 1.3.50 和 Jacoco 0.8.4。
编辑。
一个明显的解决方法是将 supplyAsync(someWrapper { ... })
提取到某些实用程序 class 并仅排除 class,即:
fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}
这对我来说已经足够好了,尽管我仍然很好奇为什么分支是由 Kotlin 添加的,而无需分支。
如果 someWrapper
的 return 值仅用作 Supplier
的实例,则可以通过显式使用 [=12= 删除不必要的空检查] 作为 return 类型。
fun <U> someWrapper(supplier: () -> U): Supplier<U> {
return Supplier { supplier() }
}
考虑以下最小的 Kotlin 示例:
fun <U> someWrapper(supplier: () -> U): () -> (U) {
return { supplier() }
}
fun foo(taskExecutor: TaskExecutor): Int {
val future = CompletableFuture.supplyAsync(someWrapper {
42
}, taskExecutor::execute)
return future.join()
}
@Test
public void shouldFoo() {
assertThat(foo(), is(42));
}
我在 Jacoco 中有分支覆盖规则,上面的代码失败了,说 2 个分支中的 1 个没有在 someWrapper
调用的行中覆盖。不幸的是,我无法排除调用 someWrapper
的所有 classes。
查看反编译后的Java代码:
public final int foo(TaskExecutor taskExecutor) {
Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
if (var10000 != null) {
Object var2 = var10000;
var10000 = new Foo$sam$java_util_function_Supplier[=11=]((Function0)var2);
}
Supplier var3 = (Supplier)var10000;
Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
this.invoke((Runnable)var1);
return Unit.INSTANCE;
}
public final void invoke(Runnable p1) {
((TaskExecutor)this.receiver).execute(p1);
}
public final KDeclarationContainer getOwner() {
return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
}
public final String getName() {
return "execute";
}
public final String getSignature() {
return "execute(Ljava/lang/Runnable;)V";
}
});
CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor[=11=](var4)));
var10000 = future.join();
Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
return ((Number)var10000).intValue();
}
我认为,问题出在 if (var10000 != null)
分支,它甚至被 IDE 标记为不必要(总是如此)。
是否可以通过某种方式调整代码以覆盖所有分支,例如。通过确保编译器不生成额外的空检查?只要我能够提供修饰的 lambda,我就可以更改 foo(..)
和 someWrapper(..)
的代码。
我使用 Kotlin 1.3.50 和 Jacoco 0.8.4。
编辑。
一个明显的解决方法是将 supplyAsync(someWrapper { ... })
提取到某些实用程序 class 并仅排除 class,即:
fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}
这对我来说已经足够好了,尽管我仍然很好奇为什么分支是由 Kotlin 添加的,而无需分支。
如果 someWrapper
的 return 值仅用作 Supplier
的实例,则可以通过显式使用 [=12= 删除不必要的空检查] 作为 return 类型。
fun <U> someWrapper(supplier: () -> U): Supplier<U> {
return Supplier { supplier() }
}