extract code for generating parameterless constructor into a separate class and rewrite it in Kotlin
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
public class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
fun generateDefaultConstructorIfNeeded(method: CallableMethod,
|
||||
constructorDescriptor: ConstructorDescriptor,
|
||||
classBuilder: ClassBuilder,
|
||||
classOrObject: JetClassOrObject) {
|
||||
if (!isEmptyConstructorNeeded(constructorDescriptor, classOrObject)) {
|
||||
return
|
||||
}
|
||||
|
||||
val flags = AsmUtil.getVisibilityAccessFlag(constructorDescriptor)
|
||||
val mv = classBuilder.newMethod(OtherOrigin(constructorDescriptor), flags, "<init>", "()V", null,
|
||||
FunctionCodegen.getThrownExceptions(constructorDescriptor, state.getTypeMapper()))
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return
|
||||
|
||||
val v = InstructionAdapter(mv)
|
||||
mv.visitCode()
|
||||
|
||||
val methodOwner = method.getOwner()
|
||||
v.load(0, methodOwner) // Load this on stack
|
||||
|
||||
var mask = 0
|
||||
val masks = arrayListOf<Int>()
|
||||
for (parameterDescriptor in constructorDescriptor.getValueParameters()) {
|
||||
val paramType = state.getTypeMapper().mapType(parameterDescriptor.getType())
|
||||
AsmUtil.pushDefaultValueOnStack(paramType, v)
|
||||
val i = parameterDescriptor.getIndex()
|
||||
if (i != 0 && i % Integer.SIZE == 0) {
|
||||
masks.add(mask)
|
||||
mask = 0
|
||||
}
|
||||
mask = mask or (1 shl (i % Integer.SIZE))
|
||||
}
|
||||
masks.add(mask)
|
||||
for (m in masks) {
|
||||
v.iconst(m)
|
||||
}
|
||||
|
||||
// constructors with default arguments has last synthetic argument of specific type
|
||||
v.aconst(null)
|
||||
|
||||
val desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false)
|
||||
v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false)
|
||||
v.areturn(Type.VOID_TYPE)
|
||||
FunctionCodegen.endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject)
|
||||
}
|
||||
|
||||
private fun isEmptyConstructorNeeded(constructorDescriptor: ConstructorDescriptor, classOrObject: JetClassOrObject): Boolean {
|
||||
val classDescriptor = constructorDescriptor.getContainingDeclaration()
|
||||
|
||||
if (classOrObject.isLocal()) return false
|
||||
|
||||
if (CodegenBinding.canHaveOuter(state.getBindingContext(), classDescriptor)) return false
|
||||
|
||||
if (Visibilities.isPrivate(classDescriptor.getVisibility()) || Visibilities.isPrivate(constructorDescriptor.getVisibility()))
|
||||
return false
|
||||
|
||||
if (constructorDescriptor.getValueParameters().isEmpty()) return false
|
||||
if (classOrObject is JetClass && hasSecondaryConstructorsWithNoParameters(classOrObject)) return false
|
||||
|
||||
return constructorDescriptor.getValueParameters().all { it.declaresDefaultValue() }
|
||||
}
|
||||
|
||||
private fun hasSecondaryConstructorsWithNoParameters(klass: JetClass) =
|
||||
klass.getSecondaryConstructors().any { it.getValueParameters().isEmpty() }
|
||||
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext;
|
||||
@@ -39,10 +38,7 @@ import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetClass;
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject;
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction;
|
||||
import org.jetbrains.kotlin.psi.JetSecondaryConstructor;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
@@ -68,7 +64,10 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
|
||||
@@ -548,54 +547,6 @@ public class FunctionCodegen {
|
||||
return ArrayUtil.toStringArray(strings);
|
||||
}
|
||||
|
||||
static void generateConstructorWithoutParametersIfNeeded(
|
||||
@NotNull GenerationState state,
|
||||
@NotNull CallableMethod method,
|
||||
@NotNull ConstructorDescriptor constructorDescriptor,
|
||||
@NotNull ClassBuilder classBuilder,
|
||||
@NotNull JetClassOrObject classOrObject
|
||||
) {
|
||||
if (!isEmptyConstructorNeeded(state.getBindingContext(), constructorDescriptor, classOrObject)) {
|
||||
return;
|
||||
}
|
||||
int flags = getVisibilityAccessFlag(constructorDescriptor);
|
||||
MethodVisitor mv = classBuilder.newMethod(OtherOrigin(constructorDescriptor), flags, "<init>", "()V", null,
|
||||
getThrownExceptions(constructorDescriptor, state.getTypeMapper()));
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
|
||||
|
||||
InstructionAdapter v = new InstructionAdapter(mv);
|
||||
mv.visitCode();
|
||||
|
||||
Type methodOwner = method.getOwner();
|
||||
v.load(0, methodOwner); // Load this on stack
|
||||
|
||||
int mask = 0;
|
||||
List<Integer> masks = new ArrayList<Integer>(1);
|
||||
for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
|
||||
Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
|
||||
pushDefaultValueOnStack(paramType, v);
|
||||
int i = parameterDescriptor.getIndex();
|
||||
if (i != 0 && i % Integer.SIZE == 0) {
|
||||
masks.add(mask);
|
||||
mask = 0;
|
||||
}
|
||||
mask |= (1 << (i % Integer.SIZE));
|
||||
}
|
||||
masks.add(mask);
|
||||
for (int m : masks) {
|
||||
v.iconst(m);
|
||||
}
|
||||
|
||||
// constructors with default arguments has last synthetic argument of specific type
|
||||
v.aconst(null);
|
||||
|
||||
String desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false);
|
||||
v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false);
|
||||
v.areturn(Type.VOID_TYPE);
|
||||
endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject);
|
||||
}
|
||||
|
||||
void generateDefaultIfNeeded(
|
||||
@NotNull MethodContext owner,
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@@ -775,38 +726,6 @@ public class FunctionCodegen {
|
||||
return needed;
|
||||
}
|
||||
|
||||
private static boolean isEmptyConstructorNeeded(
|
||||
@NotNull BindingContext context,
|
||||
@NotNull ConstructorDescriptor constructorDescriptor,
|
||||
@NotNull JetClassOrObject classOrObject
|
||||
) {
|
||||
ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
|
||||
|
||||
if (classOrObject.isLocal()) return false;
|
||||
|
||||
if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
|
||||
|
||||
if (Visibilities.isPrivate(classDescriptor.getVisibility()) ||
|
||||
Visibilities.isPrivate(constructorDescriptor.getVisibility())) return false;
|
||||
|
||||
if (constructorDescriptor.getValueParameters().isEmpty()) return false;
|
||||
if (classOrObject instanceof JetClass && hasSecondaryConstructorsWithNoParameters((JetClass) classOrObject)) return false;
|
||||
|
||||
for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
|
||||
if (!parameterDescriptor.declaresDefaultValue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean hasSecondaryConstructorsWithNoParameters(@NotNull JetClass klass) {
|
||||
for (JetSecondaryConstructor constructor : klass.getSecondaryConstructors()) {
|
||||
if (constructor.getValueParameters().isEmpty()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void generateBridge(
|
||||
@Nullable PsiElement origin,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
|
||||
@@ -1077,7 +1077,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
DefaultParameterValueLoader.DEFAULT, null);
|
||||
|
||||
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||
FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v, myClass);
|
||||
new DefaultParameterValueSubstitutor(state).generateDefaultConstructorIfNeeded(callableMethod, constructorDescriptor, v, myClass);
|
||||
|
||||
if (isCompanionObject(descriptor)) {
|
||||
context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext);
|
||||
|
||||
Reference in New Issue
Block a user