Fix synthetic accessor generation for properties

Generate synthetic accessors for property accessors only if the
corresponding methods are accessible in the current context.

 #KT-19306 Fixed Target versions 1.1.5
This commit is contained in:
Dmitry Petrov
2017-08-01 09:02:33 +03:00
parent dde0efd8ab
commit 2427b2cc6c
3 changed files with 55 additions and 6 deletions
@@ -580,7 +580,8 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
superCallTarget = (ClassDescriptor) enclosed; superCallTarget = (ClassDescriptor) enclosed;
} }
if (descriptorContext == null && withinInliningContext && superCallTarget != null) { boolean isSuperCallTarget = superCallTarget != null;
if (descriptorContext == null && withinInliningContext && isSuperCallTarget) {
//generate super calls within inline function through synthetic accessors //generate super calls within inline function through synthetic accessors
descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this); descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
} }
@@ -606,8 +607,9 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
int getterAccessFlag = getter == null ? propertyAccessFlag int getterAccessFlag = getter == null ? propertyAccessFlag
: propertyAccessFlag | getVisibilityAccessFlag(getter); : propertyAccessFlag | getVisibilityAccessFlag(getter);
boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext, boolean getterAccessorRequired =
withinInliningContext, superCallTarget != null); canGenerateAccessorInContext(getter == null ? propertyDescriptor : getter, descriptorContext) &&
isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext, withinInliningContext, isSuperCallTarget);
PropertySetterDescriptor setter = propertyDescriptor.getSetter(); PropertySetterDescriptor setter = propertyDescriptor.getSetter();
@@ -615,8 +617,9 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
if (setter != null && setter.getVisibility().normalize() != Visibilities.INVISIBLE_FAKE) { if (setter != null && setter.getVisibility().normalize() != Visibilities.INVISIBLE_FAKE) {
setterAccessFlag = propertyAccessFlag | getVisibilityAccessFlag(setter); setterAccessFlag = propertyAccessFlag | getVisibilityAccessFlag(setter);
} }
boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext, boolean setterAccessorRequired =
withinInliningContext, superCallTarget != null); canGenerateAccessorInContext(setter == null ? propertyDescriptor : setter, descriptorContext) &&
isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext, withinInliningContext, isSuperCallTarget);
if (!getterAccessorRequired && !setterAccessorRequired) { if (!getterAccessorRequired && !setterAccessorRequired) {
return descriptor; return descriptor;
@@ -625,13 +628,20 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
} }
else { else {
int flag = getVisibilityAccessFlag(unwrappedDescriptor); int flag = getVisibilityAccessFlag(unwrappedDescriptor);
if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) { if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, isSuperCallTarget)) {
return descriptor; return descriptor;
} }
return (D) descriptorContext.getAccessor(descriptor, superCallTarget); return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
} }
} }
private static boolean canGenerateAccessorInContext(
@NotNull CallableMemberDescriptor callableDescriptor,
@NotNull CodegenContext hostContext
) {
return Visibilities.isVisibleWithAnyReceiver(callableDescriptor, hostContext.contextDescriptor);
}
private static boolean isAccessorRequired( private static boolean isAccessorRequired(
int accessFlag, int accessFlag,
@NotNull CallableMemberDescriptor unwrappedDescriptor, @NotNull CallableMemberDescriptor unwrappedDescriptor,
@@ -0,0 +1,24 @@
// FILE: A.kt
package a
abstract class A {
protected var property: String = ""
private set
}
// FILE: B.kt
package b
import a.A
class B : A() {
init {
invoke { property }
}
fun invoke(func: () -> String): String = func()
}
// TESTED_OBJECT_KIND: function
// TESTED_OBJECTS: b/B, access$setProperty$p
// ABSENT: true
@@ -746,6 +746,21 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/property"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/property"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("compiler/testData/writeFlags/property/accessors")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Accessors extends AbstractWriteFlagsTest {
@TestMetadata("accessorForProtectedPropertyWithPrivateSetter.kt")
public void testAccessorForProtectedPropertyWithPrivateSetter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeFlags/property/accessors/accessorForProtectedPropertyWithPrivateSetter.kt");
doTest(fileName);
}
public void testAllFilesPresentInAccessors() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/property/accessors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
}
@TestMetadata("compiler/testData/writeFlags/property/classObject") @TestMetadata("compiler/testData/writeFlags/property/classObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)