Fix for KT-11969: ProGuard issue with private interface methods

#KT-11969 Fixed
This commit is contained in:
Mikhael Bogdanov
2016-12-22 14:50:52 +01:00
parent 6444ccc962
commit f1c1fcf0fc
14 changed files with 226 additions and 9 deletions
@@ -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"
}
+54
View File
@@ -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
}
@@ -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");
@@ -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");
@@ -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");