Fix for KT-11969: ProGuard issue with private interface methods
#KT-11969 Fixed
This commit is contained in:
@@ -133,7 +133,7 @@ public class FunctionCodegen {
|
||||
new FunctionGenerationStrategy.FunctionDefault(state, function));
|
||||
}
|
||||
|
||||
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(),
|
||||
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor, true), functionDescriptor, owner.getContextKind(),
|
||||
DefaultParameterValueLoader.DEFAULT, function);
|
||||
|
||||
generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor);
|
||||
|
||||
@@ -66,6 +66,8 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8Interface;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceMember;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS;
|
||||
@@ -375,7 +377,14 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
private Type computeOuterClass(@NotNull CodegenContext<?> context) {
|
||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> outermost = context.getClassOrPackageParentContext();
|
||||
if (outermost instanceof ClassContext) {
|
||||
return typeMapper.mapType(((ClassContext) outermost).getContextDescriptor());
|
||||
ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor();
|
||||
if (context instanceof MethodContext) {
|
||||
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
||||
if (isInterface(functionDescriptor.getContainingDeclaration()) && !isJvm8InterfaceMember(functionDescriptor, state)) {
|
||||
return typeMapper.mapDefaultImpls(classDescriptor);
|
||||
}
|
||||
}
|
||||
return typeMapper.mapType(classDescriptor);
|
||||
}
|
||||
else if (outermost instanceof MultifileClassFacadeContext || outermost instanceof DelegatingToPartContext) {
|
||||
Type implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(outermost);
|
||||
@@ -393,10 +402,17 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
@Nullable
|
||||
private Method computeEnclosingMethod(@NotNull CodegenContext context) {
|
||||
if (context instanceof MethodContext) {
|
||||
Method method = typeMapper.mapAsmMethod(((MethodContext) context).getFunctionDescriptor());
|
||||
if (!method.getName().equals("<clinit>")) {
|
||||
return method;
|
||||
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
||||
if ("<clinit>".equals(functionDescriptor.getName().asString())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (((MethodContext) context).isDefaultFunctionContext()) {
|
||||
return typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind());
|
||||
}
|
||||
|
||||
return typeMapper.mapAsmMethod(functionDescriptor, context.getContextKind());
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -299,9 +299,14 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodContext intoFunction(FunctionDescriptor descriptor, boolean isDefaultFunctionContext) {
|
||||
return new MethodContext(descriptor, getContextKind(), this, null, isDefaultFunctionContext);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodContext intoFunction(FunctionDescriptor descriptor) {
|
||||
return new MethodContext(descriptor, getContextKind(), this, null);
|
||||
return intoFunction(descriptor, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -34,7 +34,7 @@ public class ConstructorContext extends MethodContext {
|
||||
@NotNull CodegenContext parent,
|
||||
@Nullable MutableClosure closure
|
||||
) {
|
||||
super(contextDescriptor, kind, parent, closure);
|
||||
super(contextDescriptor, kind, parent, closure, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,7 @@ class InlineLambdaContext(
|
||||
closure: MutableClosure?,
|
||||
val isCrossInline: Boolean,
|
||||
val isPropertyReference: Boolean
|
||||
) : MethodContext(functionDescriptor, contextKind, parentContext, closure) {
|
||||
) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) {
|
||||
|
||||
override fun getFirstCrossInlineOrNonInlineContext(): CodegenContext<*> {
|
||||
if (isCrossInline) return this
|
||||
|
||||
@@ -39,16 +39,19 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
||||
// Note: in case of code inside property accessors, functionDescriptor will be that accessor,
|
||||
// but CodegenContext#contextDescriptor will be the corresponding property
|
||||
private final FunctionDescriptor functionDescriptor;
|
||||
private final boolean isDefaultFunctionContext;
|
||||
|
||||
protected MethodContext(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull OwnerKind contextKind,
|
||||
@NotNull CodegenContext parentContext,
|
||||
@Nullable MutableClosure closure
|
||||
@Nullable MutableClosure closure,
|
||||
boolean isDefaultFunctionContext
|
||||
) {
|
||||
super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure,
|
||||
parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
|
||||
this.functionDescriptor = functionDescriptor;
|
||||
this.isDefaultFunctionContext = isDefaultFunctionContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -126,4 +129,8 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
||||
public FunctionDescriptor getFunctionDescriptor() {
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
public boolean isDefaultFunctionContext() {
|
||||
return isDefaultFunctionContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
interface Z {
|
||||
private fun privateFun() = { "OK" }
|
||||
|
||||
fun callPrivateFun() = privateFun()
|
||||
|
||||
fun publicFun() = { "OK" }
|
||||
|
||||
fun funWithDefaultArgs(s: () -> Unit = {}): () -> Unit
|
||||
|
||||
val property: () -> Unit
|
||||
get() = {}
|
||||
|
||||
class Nested
|
||||
}
|
||||
|
||||
class Test : Z {
|
||||
override fun funWithDefaultArgs(s: () -> Unit): () -> Unit {
|
||||
return s
|
||||
}
|
||||
|
||||
fun funWithDefaultArgsInClass(s: () -> Unit = {}): () -> Unit {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
|
||||
val privateFun = Test().callPrivateFun()
|
||||
var enclosing = privateFun.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "privateFun") return "fail 1: ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 2: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val publicFun = Test().publicFun()
|
||||
enclosing = publicFun.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "publicFun") return "fail 3: ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 4: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val property = Test().property
|
||||
enclosing = property.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "getProperty") return "fail 4: ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 5: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val defaultArgs = Test().funWithDefaultArgs()
|
||||
enclosing = defaultArgs.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "funWithDefaultArgs\$default") return "fail 6: ${enclosing.name}"
|
||||
if (enclosing.parameterTypes.size != 4) return "fail 7: not default method ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "DefaultImpls") return "fail 8: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val defaultArgsInClass = Test().funWithDefaultArgsInClass()
|
||||
enclosing = defaultArgsInClass.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "funWithDefaultArgsInClass\$default") return "fail 6: ${enclosing.name}"
|
||||
if (enclosing.parameterTypes.size != 4) return "fail 7: not default method ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "Test") return "fail 8: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val nested = Z.Nested::class.java
|
||||
val enclosingClass = nested.enclosingClass!!
|
||||
if (enclosingClass.name != "Z") return "fail 9: ${enclosingClass.name}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
interface Z {
|
||||
private fun privateFun() = { "OK" }
|
||||
|
||||
fun callPrivateFun() = privateFun()
|
||||
|
||||
fun publicFun() = { "OK" }
|
||||
|
||||
fun funWithDefaultArgs(s: () -> Unit = {}): () -> Unit
|
||||
|
||||
val property: () -> Unit
|
||||
get() = {}
|
||||
|
||||
class Nested
|
||||
}
|
||||
|
||||
class Test : Z {
|
||||
override fun funWithDefaultArgs(s: () -> Unit): () -> Unit {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
|
||||
val privateFun = Test().callPrivateFun()
|
||||
var enclosing = privateFun.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "privateFun") return "fail 1: ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 2: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val publicFun = Test().publicFun()
|
||||
enclosing = publicFun.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "publicFun") return "fail 3: ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 4: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val property = Test().property
|
||||
enclosing = property.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "getProperty") return "fail 4: ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 5: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val defaultArgs = Test().funWithDefaultArgs()
|
||||
enclosing = defaultArgs.javaClass.enclosingMethod!!
|
||||
if (enclosing.name != "funWithDefaultArgs\$default") return "fail 6: ${enclosing.name}"
|
||||
if (enclosing.parameterTypes.size != 4) return "fail 7: not default method ${enclosing.name}"
|
||||
if (enclosing.getDeclaringClass().simpleName != "Z") return "fail 8: ${enclosing.getDeclaringClass().simpleName}"
|
||||
|
||||
val nested = Z.Nested::class.java
|
||||
val enclosingClass = nested.enclosingClass!!
|
||||
if (enclosingClass.name != "Z") return "fail 9: ${enclosingClass.name}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
public final class Kt11969Kt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
}
|
||||
|
||||
public final class Test {
|
||||
public method <init>(): void
|
||||
public @org.jetbrains.annotations.NotNull method callPrivateFun(): kotlin.jvm.functions.Function0
|
||||
public @org.jetbrains.annotations.NotNull method funWithDefaultArgs(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): kotlin.jvm.functions.Function0
|
||||
public synthetic static method funWithDefaultArgsInClass$default(p0: Test, p1: kotlin.jvm.functions.Function0, p2: int, p3: java.lang.Object): kotlin.jvm.functions.Function0
|
||||
public final @org.jetbrains.annotations.NotNull method funWithDefaultArgsInClass(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): kotlin.jvm.functions.Function0
|
||||
public @org.jetbrains.annotations.NotNull method getProperty(): kotlin.jvm.functions.Function0
|
||||
public @org.jetbrains.annotations.NotNull method publicFun(): kotlin.jvm.functions.Function0
|
||||
}
|
||||
|
||||
public interface Z {
|
||||
inner class Z/DefaultImpls
|
||||
inner class Z/Nested
|
||||
public abstract @org.jetbrains.annotations.NotNull method callPrivateFun(): kotlin.jvm.functions.Function0
|
||||
public abstract @org.jetbrains.annotations.NotNull method funWithDefaultArgs(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): kotlin.jvm.functions.Function0
|
||||
public abstract @org.jetbrains.annotations.NotNull method getProperty(): kotlin.jvm.functions.Function0
|
||||
public abstract @org.jetbrains.annotations.NotNull method publicFun(): kotlin.jvm.functions.Function0
|
||||
}
|
||||
|
||||
public final class Z/DefaultImpls {
|
||||
inner class Z/DefaultImpls
|
||||
public static @org.jetbrains.annotations.NotNull method callPrivateFun(p0: Z): kotlin.jvm.functions.Function0
|
||||
public synthetic static method funWithDefaultArgs$default(p0: Z, p1: kotlin.jvm.functions.Function0, p2: int, p3: java.lang.Object): kotlin.jvm.functions.Function0
|
||||
public static @org.jetbrains.annotations.NotNull method getProperty(p0: Z): kotlin.jvm.functions.Function0
|
||||
private static method privateFun(p0: Z): kotlin.jvm.functions.Function0
|
||||
public static @org.jetbrains.annotations.NotNull method publicFun(p0: Z): kotlin.jvm.functions.Function0
|
||||
}
|
||||
|
||||
public final static class Z/Nested {
|
||||
inner class Z/Nested
|
||||
public method <init>(): void
|
||||
}
|
||||
+6
@@ -13234,6 +13234,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt11969.kt")
|
||||
public void testKt11969() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt6368.kt")
|
||||
public void testKt6368() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt");
|
||||
|
||||
+6
@@ -203,6 +203,12 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt11969.kt")
|
||||
public void testKt11969() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/kt11969.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt14243.kt")
|
||||
public void testKt14243() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/kt14243.kt");
|
||||
|
||||
@@ -13234,6 +13234,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt11969.kt")
|
||||
public void testKt11969() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt6368.kt")
|
||||
public void testKt6368() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt");
|
||||
|
||||
@@ -13234,6 +13234,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt11969.kt")
|
||||
public void testKt11969() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt6368.kt")
|
||||
public void testKt6368() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt");
|
||||
|
||||
+12
@@ -16139,6 +16139,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("kt11969.kt")
|
||||
public void testKt11969() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt11969.kt");
|
||||
try {
|
||||
doTest(fileName);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("kt6368.kt")
|
||||
public void testKt6368() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/enclosing/kt6368.kt");
|
||||
|
||||
Reference in New Issue
Block a user