Fix for KT-4250: IllegalAccessError when using protected java member from lambda function

#KT-4250 Fixed
This commit is contained in:
Michael Bogdanov
2015-10-27 10:33:28 +03:00
parent 0a70c80af3
commit f3e6fab68e
10 changed files with 149 additions and 10 deletions
@@ -373,7 +373,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return labelTarget;
}
assert descriptor instanceof ClassDescriptor : "Don't know how to generate super-call to not a class";
return getParentContextSubclassOf((ClassDescriptor) descriptor, context).getThisDescriptor();
CodegenContext result = getParentContextSubclassOf((ClassDescriptor) descriptor, context);
assert result != null : "Can't find parent context for " + descriptor;
return result.getThisDescriptor();
}
@NotNull
@@ -2397,17 +2399,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
}
@Nullable
// Find the first parent of the current context which corresponds to a subclass of a given class
@NotNull
private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
CodegenContext c = context;
while (true) {
while (c != null) {
if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
return c;
}
c = c.getParentContext();
assert c != null;
}
return null;
}
@NotNull
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
import org.jetbrains.kotlin.fileClasses.FileClasses;
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
import org.jetbrains.kotlin.load.java.JavaVisibilities;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
@@ -65,7 +66,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isStaticDeclaration;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic;
@@ -637,7 +638,9 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
boolean syntheticBackingField = accessor instanceof AccessorForPropertyBackingFieldFromLocal;
boolean forceField = (AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
!isCompanionObject(accessor.getContainingDeclaration())) || syntheticBackingField;
!isCompanionObject(accessor.getContainingDeclaration())) ||
syntheticBackingField ||
original.getVisibility() == JavaVisibilities.PROTECTED_STATIC_VISIBILITY;
StackValue property = codegen.intermediateValueForProperty(
original, forceField, syntheticBackingField, accessor.getSuperCallTarget(), true, StackValue.none()
);
@@ -696,15 +699,15 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallTarget() != null
);
boolean isTopLevelDeclaration = isTopLevelDeclaration(functionDescriptor);
int reg = isTopLevelDeclaration ? 0 : 1;
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor);
int reg = hasDispatchReceiver ? 1 : 0;
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {
iv.anew(callableMethod.getOwner());
iv.dup();
reg = 0;
}
else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor) && !isTopLevelDeclaration)) {
else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor) && hasDispatchReceiver)) {
if (!AnnotationUtilKt.isPlatformStaticInObjectOrClass(functionDescriptor)) {
iv.load(0, OBJECT_TYPE);
}
@@ -24,12 +24,15 @@ import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.java.JavaVisibilities;
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.storage.NullableLazyValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.*;
@@ -544,6 +547,14 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
}
if (descriptorContext == null &&
JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
!(descriptor instanceof SamConstructorDescriptor)) {
//seems we need static receiver in resolved call
descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
superCallTarget = (ClassDescriptor) enclosed;
}
if (descriptorContext == null) {
return descriptor;
}
@@ -0,0 +1,10 @@
public class JavaClass {
public String runZ(Z z) {
return z.run("O", "K");
}
protected interface Z {
String run(String s1, String s2);
}
}
@@ -0,0 +1,12 @@
package zzz
import JavaClass
import JavaClass.Z
class A : JavaClass() {
fun test() = runZ(JavaClass.Z {a, b -> a + b})
}
fun box(): String {
return A().test()
}
@@ -0,0 +1,7 @@
public abstract class First {
protected static String TEST = "OK";
protected static String test() {
return TEST;
}
}
@@ -0,0 +1,23 @@
package anotherPackage
import First
class Second : First() {
val some = { First.TEST }
fun foo() = { First.test() }
val some2 = { TEST }
fun foo2() = { test() }
}
fun box(): String {
if (Second().some.invoke() != "OK") return "fail 1"
if (Second().foo().invoke() != "OK") return "fail 2"
if (Second().some2.invoke() != "OK") return "fail 3"
if (Second().foo2().invoke() != "OK") return "fail 4"
return "OK"
}
@@ -0,0 +1,22 @@
public class Base {
protected static String BASE_ONLY = "BASE";
protected static String baseOnly() {
return BASE_ONLY;
}
protected static String TEST = "BASE";
protected static String test() {
return TEST;
}
public static class Derived extends Base {
protected static String TEST = "DERIVED";
protected static String test() {
return TEST;
}
}
}
@@ -0,0 +1,31 @@
package anotherPackage
import Base.Derived
import Base
class Kotlin : Base.Derived() {
fun doTest(): String {
if ({ TEST }() != "DERIVED") return "fail 1"
if ({ test() }() != "DERIVED") return "fail 2"
if ({ Derived.TEST }() != "DERIVED") return "fail 3"
if ({ Derived.test() }() != "DERIVED") return "fail 4"
if ({ Base.TEST }() != "BASE") return "fail 5"
if ({ Base.test() }() != "BASE") return "fail 6"
if ({ Base.BASE_ONLY }() != "BASE") return "fail 7"
if ({ Base.baseOnly() }() != "BASE") return "fail 8"
if ({ BASE_ONLY }() != "BASE") return "fail 9"
if ({ baseOnly() }() != "BASE") return "fail 10"
return "OK"
}
}
fun box(): String {
return Kotlin().doTest()
}
@@ -627,5 +627,23 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("protectedSamConstructor")
public void testProtectedSamConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/");
doTestWithJava(fileName);
}
@TestMetadata("protectedStatic")
public void testProtectedStatic() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/statics/protectedStatic/");
doTestWithJava(fileName);
}
@TestMetadata("protectedStatic2")
public void testProtectedStatic2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/statics/protectedStatic2/");
doTestWithJava(fileName);
}
}
}