Fix protected call to super method from lambda
Previously JVM back-end had an assumption that if we're calling a method declared in the super class from a lambda via a synthetic accessor, that should be a super call and it must be done with 'invokespecial'. Which is wrong because a method declared in the super class may be open and overridden in the subclass, so 'invokevirtual' should be used. Surprisingly, Java SE verifier allowed both instructions, but on Android only the latter is possible #KT-8899 Fixed #KT-9052 Fixed
This commit is contained in:
@@ -17,9 +17,14 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.psi.JetSuperExpression;
|
||||
|
||||
public interface AccessorForCallableDescriptor<T extends CallableMemberDescriptor> {
|
||||
@NotNull
|
||||
T getCalleeDescriptor();
|
||||
|
||||
@Nullable
|
||||
JetSuperExpression getSuperCallExpression();
|
||||
}
|
||||
|
||||
+13
-15
@@ -17,37 +17,35 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.JetSuperExpression
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import java.util.*
|
||||
|
||||
public class AccessorForConstructorDescriptor(
|
||||
private val calleeDescriptor: ConstructorDescriptor,
|
||||
containingDeclaration: DeclarationDescriptor
|
||||
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>"))
|
||||
, ConstructorDescriptor
|
||||
, AccessorForCallableDescriptor<ConstructorDescriptor> {
|
||||
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
private val superCallExpression: JetSuperExpression?
|
||||
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>")),
|
||||
ConstructorDescriptor,
|
||||
AccessorForCallableDescriptor<ConstructorDescriptor> {
|
||||
override fun getCalleeDescriptor(): ConstructorDescriptor = calleeDescriptor
|
||||
|
||||
override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.getContainingDeclaration()
|
||||
override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.containingDeclaration
|
||||
|
||||
override fun isPrimary(): Boolean = false
|
||||
|
||||
override fun getReturnType(): JetType = super<AbstractAccessorForFunctionDescriptor>.getReturnType()!!
|
||||
override fun getReturnType(): JetType = super.getReturnType()!!
|
||||
|
||||
override fun getSuperCallExpression(): JetSuperExpression? = superCallExpression
|
||||
|
||||
init {
|
||||
initialize(
|
||||
DescriptorUtils.getReceiverParameterType(getExtensionReceiverParameter()),
|
||||
calleeDescriptor.getDispatchReceiverParameter(),
|
||||
DescriptorUtils.getReceiverParameterType(extensionReceiverParameter),
|
||||
calleeDescriptor.dispatchReceiverParameter,
|
||||
copyTypeParameters(calleeDescriptor),
|
||||
copyValueParameters(calleeDescriptor),
|
||||
calleeDescriptor.getReturnType(),
|
||||
calleeDescriptor.returnType,
|
||||
Modality.FINAL,
|
||||
Visibilities.INTERNAL
|
||||
)
|
||||
|
||||
+11
-2
@@ -17,23 +17,27 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.JetSuperExpression;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
|
||||
public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor<FunctionDescriptor> {
|
||||
|
||||
private final FunctionDescriptor calleeDescriptor;
|
||||
private final JetSuperExpression superCallExpression;
|
||||
|
||||
public AccessorForFunctionDescriptor(
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
int index
|
||||
int index,
|
||||
@Nullable JetSuperExpression superCallExpression
|
||||
) {
|
||||
super(containingDeclaration,
|
||||
Name.identifier("access$" + (descriptor instanceof ConstructorDescriptor ? "init" : descriptor.getName()) + "$" + index));
|
||||
this.calleeDescriptor = descriptor;
|
||||
this.superCallExpression = superCallExpression;
|
||||
|
||||
initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()),
|
||||
descriptor instanceof ConstructorDescriptor || AnnotationsPackage.isPlatformStaticInObjectOrClass(descriptor)
|
||||
@@ -51,4 +55,9 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
|
||||
public FunctionDescriptor getCalleeDescriptor() {
|
||||
return calleeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetSuperExpression getSuperCallExpression() {
|
||||
return superCallExpression;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -23,13 +23,12 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
|
||||
public class AccessorForPropertyBackingFieldInOuterClass extends AccessorForPropertyDescriptor {
|
||||
|
||||
public AccessorForPropertyBackingFieldInOuterClass(
|
||||
@NotNull PropertyDescriptor pd,
|
||||
@NotNull PropertyDescriptor property,
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
int index,
|
||||
@Nullable JetType delegationType
|
||||
) {
|
||||
super(pd, delegationType != null ? delegationType : pd.getType(), null, null, containingDeclaration, index);
|
||||
super(property, delegationType != null ? delegationType : property.getType(), null, null, containingDeclaration, index, null);
|
||||
}
|
||||
}
|
||||
|
||||
+30
-3
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.JetSuperExpression;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
|
||||
@@ -33,9 +34,16 @@ import java.util.Collections;
|
||||
public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implements AccessorForCallableDescriptor<PropertyDescriptor> {
|
||||
private final PropertyDescriptor calleeDescriptor;
|
||||
private final int accessorIndex;
|
||||
private final JetSuperExpression superCallExpression;
|
||||
|
||||
public AccessorForPropertyDescriptor(@NotNull PropertyDescriptor pd, @NotNull DeclarationDescriptor containingDeclaration, int index) {
|
||||
this(pd, pd.getType(), DescriptorUtils.getReceiverParameterType(pd.getExtensionReceiverParameter()), pd.getDispatchReceiverParameter(), containingDeclaration, index);
|
||||
public AccessorForPropertyDescriptor(
|
||||
@NotNull PropertyDescriptor property,
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
int index,
|
||||
@Nullable JetSuperExpression superCallExpression
|
||||
) {
|
||||
this(property, property.getType(), DescriptorUtils.getReceiverParameterType(property.getExtensionReceiverParameter()),
|
||||
property.getDispatchReceiverParameter(), containingDeclaration, index, superCallExpression);
|
||||
}
|
||||
|
||||
protected AccessorForPropertyDescriptor(
|
||||
@@ -44,7 +52,8 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
|
||||
@Nullable JetType receiverType,
|
||||
@Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
int index
|
||||
int index,
|
||||
@Nullable JetSuperExpression superCallExpression
|
||||
) {
|
||||
super(containingDeclaration, null, Annotations.EMPTY, Modality.FINAL, Visibilities.LOCAL,
|
||||
original.isVar(), Name.identifier("access$" + getIndexedAccessorSuffix(original, index)),
|
||||
@@ -52,6 +61,7 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
|
||||
|
||||
this.calleeDescriptor = original;
|
||||
this.accessorIndex = index;
|
||||
this.superCallExpression = superCallExpression;
|
||||
setType(propertyType, Collections.<TypeParameterDescriptorImpl>emptyList(), dispatchReceiverParameter, receiverType);
|
||||
initialize(new Getter(this), new Setter(this));
|
||||
}
|
||||
@@ -69,6 +79,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
|
||||
//noinspection ConstantConditions
|
||||
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getGetter();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JetSuperExpression getSuperCallExpression() {
|
||||
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getSuperCallExpression();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Setter extends PropertySetterDescriptorImpl implements AccessorForCallableDescriptor<PropertySetterDescriptor>{
|
||||
@@ -84,6 +100,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
|
||||
//noinspection ConstantConditions
|
||||
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getSetter();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JetSuperExpression getSuperCallExpression() {
|
||||
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getSuperCallExpression();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -92,6 +114,11 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
|
||||
return calleeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetSuperExpression getSuperCallExpression() {
|
||||
return superCallExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getIndexedAccessorSuffix() {
|
||||
return getIndexedAccessorSuffix(calleeDescriptor, accessorIndex);
|
||||
|
||||
@@ -356,11 +356,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@Override
|
||||
public StackValue visitSuperExpression(@NotNull JetSuperExpression expression, StackValue data) {
|
||||
return StackValue.thisOrOuter(this, getSuperCallLabelTarget(expression), true, true);
|
||||
return StackValue.thisOrOuter(this, getSuperCallLabelTarget(context, expression), true, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor getSuperCallLabelTarget(JetSuperExpression expression) {
|
||||
public static ClassDescriptor getSuperCallLabelTarget(
|
||||
@NotNull CodegenContext<?> context,
|
||||
@NotNull JetSuperExpression expression
|
||||
) {
|
||||
BindingContext bindingContext = context.getState().getBindingContext();
|
||||
PsiElement labelPsi = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
|
||||
ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, labelPsi);
|
||||
DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
|
||||
@@ -2007,7 +2011,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
|
||||
JetSuperExpression superExpression =
|
||||
resolvedCall == null ? null : CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall());
|
||||
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor);
|
||||
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
|
||||
|
||||
if (directToField) {
|
||||
receiver = StackValue.receiverWithoutReceiverArgument(receiver);
|
||||
@@ -2137,14 +2141,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
@Nullable JetSuperExpression superExpression,
|
||||
@NotNull StackValue receiver
|
||||
) {
|
||||
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL, receiver);
|
||||
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false, receiver);
|
||||
}
|
||||
|
||||
public StackValue.Property intermediateValueForProperty(
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
boolean forceField,
|
||||
@Nullable JetSuperExpression superExpression,
|
||||
@NotNull MethodKind methodKind,
|
||||
boolean skipAccessorsForPrivateFieldInOuterClass,
|
||||
StackValue receiver
|
||||
) {
|
||||
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
|
||||
@@ -2165,56 +2169,54 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
CallableMethod callableGetter = null;
|
||||
CallableMethod callableSetter = null;
|
||||
|
||||
boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass;
|
||||
|
||||
CodegenContext backingFieldContext = context.getParentContext();
|
||||
boolean changeOwnerOnTypeMapping = isBackingFieldInAnotherClass;
|
||||
CodegenContext backingFieldContext;
|
||||
boolean changeOwnerOnTypeMapping;
|
||||
boolean skipPropertyAccessors;
|
||||
|
||||
if (isBackingFieldInAnotherClass && forceField) {
|
||||
backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
|
||||
int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
|
||||
skipPropertyAccessors =
|
||||
(flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
|
||||
skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
|
||||
if (!skipPropertyAccessors) {
|
||||
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType);
|
||||
changeOwnerOnTypeMapping =
|
||||
changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
|
||||
//noinspection ConstantConditions
|
||||
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
|
||||
propertyDescriptor, true, delegateType, superExpression
|
||||
);
|
||||
changeOwnerOnTypeMapping = !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
|
||||
}
|
||||
else {
|
||||
changeOwnerOnTypeMapping = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
backingFieldContext = context.getParentContext();
|
||||
changeOwnerOnTypeMapping = isBackingFieldInAnotherClass;
|
||||
skipPropertyAccessors = forceField;
|
||||
}
|
||||
|
||||
if (!skipPropertyAccessors) {
|
||||
if (couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
|
||||
callableGetter = null;
|
||||
}
|
||||
else {
|
||||
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
|
||||
if (isSuper && !isInterface(containingDeclaration)) {
|
||||
ClassDescriptor owner = getSuperCallLabelTarget(superExpression);
|
||||
ClassDescriptor owner = getSuperCallLabelTarget(context, superExpression);
|
||||
CodegenContext c = context.findParentContextWithDescriptor(owner);
|
||||
assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor;
|
||||
if (c != context.getParentContext()) {
|
||||
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor);
|
||||
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor, superExpression);
|
||||
}
|
||||
}
|
||||
|
||||
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor);
|
||||
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
|
||||
|
||||
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
|
||||
if (getter != null) {
|
||||
callableGetter =
|
||||
typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
|
||||
callableGetter = typeMapper.mapToCallableMethod(getter, isSuper, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (propertyDescriptor.isVar()) {
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
if (setter != null) {
|
||||
if (couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context)) {
|
||||
callableSetter = null;
|
||||
}
|
||||
else {
|
||||
callableSetter =
|
||||
typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
|
||||
}
|
||||
if (setter != null && !couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context)) {
|
||||
callableSetter = typeMapper.mapToCallableMethod(setter, isSuper, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2329,7 +2331,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
descriptor = originalIfSamAdapter;
|
||||
}
|
||||
// $default method is not private, so you need no accessor to call it
|
||||
return usesDefaultArguments(resolvedCall) ? descriptor : context.accessibleDescriptor(descriptor);
|
||||
return usesDefaultArguments(resolvedCall)
|
||||
? descriptor
|
||||
: context.accessibleDescriptor(descriptor, CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall()));
|
||||
}
|
||||
|
||||
private static boolean usesDefaultArguments(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
@@ -2355,11 +2359,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
boolean superCall = superCallExpression != null;
|
||||
|
||||
if (superCall && !isInterface(fd.getContainingDeclaration())) {
|
||||
ClassDescriptor owner = getSuperCallLabelTarget(superCallExpression);
|
||||
ClassDescriptor owner = getSuperCallLabelTarget(context, superCallExpression);
|
||||
CodegenContext c = context.findParentContextWithDescriptor(owner);
|
||||
assert c != null : "Couldn't find a context for a super-call: " + fd;
|
||||
if (c != context.getParentContext()) {
|
||||
fd = (FunctionDescriptor) c.getAccessor(fd);
|
||||
fd = (FunctionDescriptor) c.getAccessor(fd, superCallExpression);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ public class FunctionCodegen {
|
||||
mv.visitCode();
|
||||
FunctionDescriptor staticFunctionDescriptor = PlatformStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
|
||||
JvmMethodSignature jvmMethodSignature =
|
||||
typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor));
|
||||
typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
|
||||
Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
|
||||
generateDelegateToMethodBody(false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName());
|
||||
}
|
||||
|
||||
@@ -857,32 +857,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
protected void generateSyntheticAccessors() {
|
||||
Map<DeclarationDescriptor, DeclarationDescriptor> accessors = ((CodegenContext<?>) context).getAccessors();
|
||||
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) {
|
||||
generateSyntheticAccessor(entry);
|
||||
for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) {
|
||||
generateSyntheticAccessor(accessor);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) {
|
||||
if (entry.getValue() instanceof FunctionDescriptor) {
|
||||
final FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue();
|
||||
final FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
|
||||
private void generateSyntheticAccessor(@NotNull AccessorForCallableDescriptor<?> accessorForCallableDescriptor) {
|
||||
if (accessorForCallableDescriptor instanceof FunctionDescriptor) {
|
||||
final FunctionDescriptor accessor = (FunctionDescriptor) accessorForCallableDescriptor;
|
||||
final FunctionDescriptor original = (FunctionDescriptor) accessorForCallableDescriptor.getCalleeDescriptor();
|
||||
functionCodegen.generateMethod(
|
||||
Synthetic(null, original), bridge,
|
||||
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) {
|
||||
Synthetic(null, original), accessor,
|
||||
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, accessor) {
|
||||
@Override
|
||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||
markLineNumberForSyntheticFunction(descriptor, codegen.v);
|
||||
|
||||
generateMethodCallTo(original, bridge, codegen.v);
|
||||
generateMethodCallTo(original, accessor, codegen.v);
|
||||
codegen.v.areturn(signature.getReturnType());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (entry.getValue() instanceof PropertyDescriptor) {
|
||||
final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
|
||||
final PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
|
||||
else if (accessorForCallableDescriptor instanceof AccessorForPropertyDescriptor) {
|
||||
final AccessorForPropertyDescriptor accessor = (AccessorForPropertyDescriptor) accessorForCallableDescriptor;
|
||||
final PropertyDescriptor original = accessor.getCalleeDescriptor();
|
||||
|
||||
class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
|
||||
public PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) {
|
||||
@@ -892,10 +891,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
@Override
|
||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||
boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
|
||||
!isCompanionObject(bridge.getContainingDeclaration());
|
||||
StackValue property =
|
||||
codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR,
|
||||
StackValue.none());
|
||||
!isCompanionObject(accessor.getContainingDeclaration());
|
||||
StackValue property = codegen.intermediateValueForProperty(
|
||||
original, forceField, accessor.getSuperCallExpression(), true, StackValue.none()
|
||||
);
|
||||
|
||||
InstructionAdapter iv = codegen.v;
|
||||
|
||||
@@ -920,14 +919,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
PropertyGetterDescriptor getter = bridge.getGetter();
|
||||
PropertyGetterDescriptor getter = accessor.getGetter();
|
||||
assert getter != null;
|
||||
functionCodegen.generateMethod(Synthetic(null, original.getGetter() != null ? original.getGetter() : original),
|
||||
getter, new PropertyAccessorStrategy(getter));
|
||||
|
||||
|
||||
if (bridge.isVar()) {
|
||||
PropertySetterDescriptor setter = bridge.getSetter();
|
||||
if (accessor.isVar()) {
|
||||
PropertySetterDescriptor setter = accessor.getSetter();
|
||||
assert setter != null;
|
||||
|
||||
functionCodegen.generateMethod(Synthetic(null, original.getSetter() != null ? original.getSetter() : original),
|
||||
@@ -957,24 +956,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
private void generateMethodCallTo(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@Nullable FunctionDescriptor bridgeDescriptor,
|
||||
@Nullable FunctionDescriptor accessorDescriptor,
|
||||
@NotNull InstructionAdapter iv
|
||||
) {
|
||||
boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor;
|
||||
boolean bridgeIsAccessorConstructor = bridgeDescriptor instanceof AccessorForConstructorDescriptor;
|
||||
boolean callFromAccessor = bridgeIsAccessorConstructor
|
||||
|| (bridgeDescriptor != null && JetTypeMapper.isAccessor(bridgeDescriptor));
|
||||
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
|
||||
|
||||
boolean superCall = accessorDescriptor instanceof AccessorForCallableDescriptor &&
|
||||
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallExpression() != null;
|
||||
CallableMethod callableMethod = isConstructor ?
|
||||
typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) :
|
||||
typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor, context);
|
||||
typeMapper.mapToCallableMethod(functionDescriptor, superCall, context);
|
||||
|
||||
int reg = 1;
|
||||
if (isConstructor && !bridgeIsAccessorConstructor) {
|
||||
if (isConstructor && !accessorIsConstructor) {
|
||||
iv.anew(callableMethod.getOwner());
|
||||
iv.dup();
|
||||
reg = 0;
|
||||
}
|
||||
else if (callFromAccessor) {
|
||||
else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor))) {
|
||||
if (!AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor)) {
|
||||
iv.load(0, OBJECT_TYPE);
|
||||
}
|
||||
@@ -989,6 +989,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
reg += argType.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
callableMethod.genInvokeInstruction(iv);
|
||||
}
|
||||
|
||||
@@ -1074,8 +1075,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
|
||||
ExpressionCodegen codegen = createOrGetClInitCodegen();
|
||||
FunctionDescriptor constructor =
|
||||
(FunctionDescriptor) context.accessibleDescriptor(KotlinPackage.single(companionObject.getConstructors()));
|
||||
FunctionDescriptor constructor = (FunctionDescriptor) context.accessibleDescriptor(
|
||||
KotlinPackage.single(companionObject.getConstructors()), /* superCallExpression = */ null
|
||||
);
|
||||
generateMethodCallTo(constructor, null, codegen.v);
|
||||
codegen.v.dup();
|
||||
StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
|
||||
|
||||
@@ -360,8 +360,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
JetExpression initializer = property.getDelegateExpressionOrInitializer();
|
||||
assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
|
||||
|
||||
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER,
|
||||
StackValue.LOCAL_0);
|
||||
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, true, StackValue.LOCAL_0);
|
||||
|
||||
propValue.store(codegen.gen(initializer), codegen.v);
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
public enum MethodKind {
|
||||
GENERAL,
|
||||
INITIALIZER,
|
||||
SYNTHETIC_ACCESSOR
|
||||
}
|
||||
@@ -23,20 +23,19 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
class PlatformStaticGenerator(
|
||||
val descriptor: FunctionDescriptor,
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val state: GenerationState
|
||||
) : Function2<ImplementationBodyCodegen, ClassBuilder, Unit> {
|
||||
private val typeMapper = state.typeMapper
|
||||
|
||||
override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) {
|
||||
val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor)
|
||||
@@ -51,40 +50,37 @@ class PlatformStaticGenerator(
|
||||
frameMap: FrameMap,
|
||||
signature: JvmMethodSignature,
|
||||
context: MethodContext,
|
||||
parentCodegen: MemberCodegen<out JetElement>
|
||||
parentCodegen: MemberCodegen<*>
|
||||
) {
|
||||
val typeMapper = parentCodegen.typeMapper
|
||||
|
||||
val iv = InstructionAdapter(mv)
|
||||
val classDescriptor = descriptor.getContainingDeclaration() as ClassDescriptor
|
||||
val classDescriptor = descriptor.containingDeclaration as ClassDescriptor
|
||||
val singletonValue = StackValue.singleton(classDescriptor, typeMapper)
|
||||
singletonValue.put(singletonValue.type, iv);
|
||||
var index = 0;
|
||||
val asmMethod = signature.getAsmMethod()
|
||||
for (paramType in asmMethod.getArgumentTypes()) {
|
||||
iv.load(index, paramType);
|
||||
index += paramType.getSize();
|
||||
singletonValue.put(singletonValue.type, iv)
|
||||
var index = 0
|
||||
val asmMethod = signature.asmMethod
|
||||
for (paramType in asmMethod.argumentTypes) {
|
||||
iv.load(index, paramType)
|
||||
index += paramType.size
|
||||
}
|
||||
|
||||
val syntheticOrOriginalMethod = typeMapper.mapToCallableMethod(
|
||||
codegen.getContext().accessibleDescriptor(descriptor),
|
||||
codegen.getContext().accessibleDescriptor(descriptor, /* superCallExpression = */ null),
|
||||
false,
|
||||
codegen.getContext()
|
||||
)
|
||||
syntheticOrOriginalMethod.genInvokeInstruction(iv)
|
||||
iv.areturn(asmMethod.getReturnType());
|
||||
iv.areturn(asmMethod.returnType)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
if (originElement is JetNamedFunction) {
|
||||
codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@platformStatic
|
||||
@JvmStatic
|
||||
public fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.getCorrespondingProperty() else descriptor
|
||||
val copies = CodegenUtil.copyFunctions(
|
||||
|
||||
@@ -24,6 +24,7 @@ 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.psi.JetSuperExpression;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
@@ -47,8 +48,38 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
private final LocalLookup enclosingLocalLookup;
|
||||
private final NullableLazyValue<StackValue.Field> outerExpression;
|
||||
|
||||
private Map<DeclarationDescriptor, DeclarationDescriptor> accessors;
|
||||
private Map<DeclarationDescriptor, CodegenContext> childContexts;
|
||||
private Map<AccessorKey, AccessorForCallableDescriptor<?>> accessors;
|
||||
|
||||
private static class AccessorKey {
|
||||
public final DeclarationDescriptor descriptor;
|
||||
public final ClassDescriptor superCallLabelTarget;
|
||||
|
||||
public AccessorKey(@NotNull DeclarationDescriptor descriptor, @Nullable ClassDescriptor superCallLabelTarget) {
|
||||
this.descriptor = descriptor;
|
||||
this.superCallLabelTarget = superCallLabelTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof AccessorKey)) return false;
|
||||
AccessorKey other = (AccessorKey) obj;
|
||||
return descriptor.equals(other.descriptor) &&
|
||||
(superCallLabelTarget == null
|
||||
? other.superCallLabelTarget == null
|
||||
: superCallLabelTarget.equals(other.superCallLabelTarget));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * descriptor.hashCode() + (superCallLabelTarget == null ? 0 : superCallLabelTarget.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return descriptor.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public CodegenContext(
|
||||
@NotNull T contextDescriptor,
|
||||
@@ -227,20 +258,28 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor) {
|
||||
return getAccessor(descriptor, false, null);
|
||||
public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable JetSuperExpression superCallExpression) {
|
||||
return getAccessor(descriptor, false, null, superCallExpression);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
public <D extends CallableMemberDescriptor> D getAccessor(
|
||||
@NotNull D descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType
|
||||
@NotNull D possiblySubstitutedDescriptor,
|
||||
boolean isForBackingFieldInOuterClass,
|
||||
@Nullable JetType delegateType,
|
||||
@Nullable JetSuperExpression superCallExpression
|
||||
) {
|
||||
if (accessors == null) {
|
||||
accessors = new LinkedHashMap<DeclarationDescriptor, DeclarationDescriptor>();
|
||||
accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
|
||||
}
|
||||
descriptor = (D) descriptor.getOriginal();
|
||||
DeclarationDescriptor accessor = accessors.get(descriptor);
|
||||
|
||||
D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
|
||||
AccessorKey key = new AccessorKey(
|
||||
descriptor, superCallExpression == null ? null : ExpressionCodegen.getSuperCallLabelTarget(this, superCallExpression)
|
||||
);
|
||||
|
||||
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
|
||||
if (accessor != null) {
|
||||
assert !isForBackingFieldInOuterClass ||
|
||||
accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context";
|
||||
@@ -249,10 +288,12 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
|
||||
int accessorIndex = accessors.size();
|
||||
if (descriptor instanceof SimpleFunctionDescriptor) {
|
||||
accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex);
|
||||
accessor = new AccessorForFunctionDescriptor(
|
||||
(FunctionDescriptor) descriptor, contextDescriptor, accessorIndex, superCallExpression
|
||||
);
|
||||
}
|
||||
else if (descriptor instanceof ConstructorDescriptor) {
|
||||
accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor);
|
||||
accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallExpression);
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
if (isForBackingFieldInOuterClass) {
|
||||
@@ -260,13 +301,16 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
accessorIndex, delegateType);
|
||||
}
|
||||
else {
|
||||
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex);
|
||||
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor,
|
||||
accessorIndex, superCallExpression);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
|
||||
}
|
||||
accessors.put(descriptor, accessor);
|
||||
|
||||
accessors.put(key, accessor);
|
||||
|
||||
return (D) accessor;
|
||||
}
|
||||
|
||||
@@ -314,25 +358,29 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
|
||||
return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
|
||||
public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
|
||||
return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <D extends CallableMemberDescriptor> D accessibleDescriptor(D descriptor) {
|
||||
public <D extends CallableMemberDescriptor> D accessibleDescriptor(
|
||||
@NotNull D descriptor,
|
||||
@Nullable JetSuperExpression superCallExpression
|
||||
) {
|
||||
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
|
||||
if (!hasThisDescriptor() || enclosing == getThisDescriptor() ||
|
||||
enclosing == getClassOrPackageParentContext().getContextDescriptor()) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
return accessibleDescriptorIfNeeded(descriptor);
|
||||
return accessibleDescriptorIfNeeded(descriptor, superCallExpression);
|
||||
}
|
||||
|
||||
public void recordSyntheticAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BindingContext bindingContext) {
|
||||
if (hasThisDescriptor() &&
|
||||
(descriptor instanceof ConstructorDescriptor || Boolean.TRUE.equals(bindingContext.get(NEED_SYNTHETIC_ACCESSOR, descriptor)))) {
|
||||
accessibleDescriptorIfNeeded(descriptor);
|
||||
// Not a super call because neither constructors nor private members can be targets of super calls
|
||||
accessibleDescriptorIfNeeded(descriptor, /* superCallExpression = */ null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +400,10 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(@NotNull D descriptor) {
|
||||
private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
|
||||
@NotNull D descriptor,
|
||||
@Nullable JetSuperExpression superCallExpression
|
||||
) {
|
||||
CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
|
||||
int flag = getAccessFlags(unwrappedDescriptor);
|
||||
if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) {
|
||||
@@ -385,7 +436,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
}
|
||||
|
||||
return (D) descriptorContext.getAccessor(descriptor);
|
||||
return (D) descriptorContext.getAccessor(descriptor, superCallExpression);
|
||||
}
|
||||
|
||||
private void addChild(@NotNull CodegenContext child) {
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import test.A
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
open class B : A() {
|
||||
fun box(): String {
|
||||
val overriddenMethod: () -> String = {
|
||||
method()
|
||||
}
|
||||
assertEquals("C.method", overriddenMethod())
|
||||
|
||||
val superMethod: () -> String = {
|
||||
super.method()
|
||||
}
|
||||
assertEquals("A.method", superMethod())
|
||||
|
||||
val overriddenPropertyGetter: () -> String = {
|
||||
property
|
||||
}
|
||||
assertEquals("C.property", overriddenPropertyGetter())
|
||||
|
||||
val superPropertyGetter: () -> String = {
|
||||
super.property
|
||||
}
|
||||
assertEquals("A.property", superPropertyGetter())
|
||||
|
||||
val overriddenPropertySetter: () -> Unit = {
|
||||
property = ""
|
||||
}
|
||||
overriddenPropertySetter()
|
||||
|
||||
val superPropertySetter: () -> Unit = {
|
||||
super.property = ""
|
||||
}
|
||||
superPropertySetter()
|
||||
|
||||
assertEquals("C.property;A.property;", state)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
class C : B() {
|
||||
override fun method() = "C.method"
|
||||
override var property: String
|
||||
get() = "C.property"
|
||||
set(value) { state += "C.property;" }
|
||||
}
|
||||
|
||||
fun box() = C().box()
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package test
|
||||
|
||||
abstract class A {
|
||||
public var state = ""
|
||||
|
||||
// These implementations should not be called, because they are overridden in C
|
||||
|
||||
protected open fun method(): String = "A.method"
|
||||
|
||||
protected open var property: String
|
||||
get() = "A.property"
|
||||
set(value) { state += "A.property;" }
|
||||
}
|
||||
+6
@@ -37,6 +37,12 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg
|
||||
doTestMultiFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("accessorForProtectedInvokeVirtual")
|
||||
public void testAccessorForProtectedInvokeVirtual() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/accessorForProtectedInvokeVirtual/");
|
||||
doTestMultiFile(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInBoxMultiFile() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultiFile"), Pattern.compile("^([^\\.]+)$"), false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user