Implement kotlin.jvm.overloads annotation for generating all overloads of a method that has default parameter values.
#KT-2095 Fixed
This commit is contained in:
@@ -136,15 +136,14 @@ public class CallableMethod implements Callable {
|
||||
}
|
||||
|
||||
Method method = getAsmMethod();
|
||||
String desc = JetTypeMapper.getDefaultDescriptor(method, receiverParameterType != null);
|
||||
String desc = JetTypeMapper.getDefaultDescriptor(method,
|
||||
getInvokeOpcode() == INVOKESTATIC ? null : defaultImplParam.getDescriptor(),
|
||||
receiverParameterType != null);
|
||||
if ("<init>".equals(method.getName())) {
|
||||
v.aconst(null);
|
||||
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", desc, false);
|
||||
}
|
||||
else {
|
||||
if (getInvokeOpcode() != INVOKESTATIC) {
|
||||
desc = desc.replace("(", "(" + defaultImplParam.getDescriptor());
|
||||
}
|
||||
v.visitMethodInsn(INVOKESTATIC, defaultImplOwner.getInternalName(),
|
||||
method.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, desc, false);
|
||||
}
|
||||
|
||||
+131
-23
@@ -17,48 +17,144 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
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.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
/**
|
||||
* Generates Java overloads for functions and constructors that have the default
|
||||
* parameter values substituted.
|
||||
*/
|
||||
public class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
fun generateDefaultConstructorIfNeeded(method: CallableMethod,
|
||||
constructorDescriptor: ConstructorDescriptor,
|
||||
/**
|
||||
* If all of the parameters of the specified constructor declare default values,
|
||||
* generates a no-argument constructor that passes default values for all arguments.
|
||||
*/
|
||||
fun generateDefaultConstructorIfNeeded(constructorDescriptor: ConstructorDescriptor,
|
||||
classBuilder: ClassBuilder,
|
||||
context: CodegenContext<*>,
|
||||
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()))
|
||||
generateOverloadWithSubstitutedParameters(constructorDescriptor, constructorDescriptor, classBuilder, classOrObject,
|
||||
context,
|
||||
constructorDescriptor.countDefaultParameters())
|
||||
}
|
||||
|
||||
/**
|
||||
* If the function is annotated with [kotlin.jvm.overloads], generates Java methods that
|
||||
* have the default parameter values substituted. If a method has N parameters and M of which
|
||||
* have default values, M overloads are generated: the first one takes N-1 parameters (all but
|
||||
* the last one that takes a default value), the second takes N-2 parameters, and so on.
|
||||
*
|
||||
* @param functionDescriptor the method for which the overloads are generated
|
||||
* @param delegateFunctionDescriptor the method descriptor for the implementation that we need to call
|
||||
* (same as [functionDescriptor] in all cases except for companion object methods annotated with [platformStatic],
|
||||
* where [functionDescriptor] is the static method in the main class and [delegateFunctionDescriptor] is the
|
||||
* implementation in the companion object class)
|
||||
*/
|
||||
fun generateOverloadsIfNeeded(function: JetNamedFunction,
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
delegateFunctionDescriptor: FunctionDescriptor,
|
||||
owner: CodegenContext<*>,
|
||||
classBuilder: ClassBuilder) {
|
||||
val overloadsFqName = FqName.fromSegments(listOf("kotlin", "jvm", "overloads"))
|
||||
if (functionDescriptor.getAnnotations().findAnnotation(overloadsFqName) == null) return
|
||||
|
||||
val count = functionDescriptor.countDefaultParameters()
|
||||
val context = owner.intoFunction(functionDescriptor)
|
||||
|
||||
for (i in 1..count) {
|
||||
generateOverloadWithSubstitutedParameters(functionDescriptor, delegateFunctionDescriptor, classBuilder, function, context, i)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.countDefaultParameters() =
|
||||
getValueParameters().count { it.hasDefaultValue() }
|
||||
|
||||
/**
|
||||
* Generates an overload for [functionDescriptor] that substitutes default values for the last
|
||||
* [substituteCount] parameters that have default values.
|
||||
*
|
||||
* @param functionDescriptor the method for which the overloads are generated
|
||||
* @param delegateFunctionDescriptor the method descriptor for the implementation that we need to call
|
||||
* (same as [functionDescriptor] in all cases except for companion object methods annotated with [platformStatic],
|
||||
* where [functionDescriptor] is the static method in the main class and [delegateFunctionDescriptor] is the
|
||||
* implementation in the companion object class)
|
||||
* @param methodElement the PSI element for the method implementation (used in diagnostic messages only)
|
||||
*/
|
||||
fun generateOverloadWithSubstitutedParameters(functionDescriptor: FunctionDescriptor,
|
||||
delegateFunctionDescriptor: FunctionDescriptor,
|
||||
classBuilder: ClassBuilder,
|
||||
methodElement: JetElement?,
|
||||
context: CodegenContext<*>,
|
||||
substituteCount: Int) {
|
||||
val isStatic = AsmUtil.isStaticMethod(context.getContextKind(), functionDescriptor)
|
||||
val flags = AsmUtil.getVisibilityAccessFlag(functionDescriptor) or (if (isStatic) Opcodes.ACC_STATIC else 0)
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.getOriginal(), substituteCount)
|
||||
val signature = state.getTypeMapper().mapSignature(functionDescriptor, context.getContextKind(),
|
||||
remainingParameters)
|
||||
val mv = classBuilder.newMethod(OtherOrigin(functionDescriptor), flags,
|
||||
signature.getAsmMethod().getName(),
|
||||
signature.getAsmMethod().getDescriptor(), null,
|
||||
FunctionCodegen.getThrownExceptions(functionDescriptor, state.getTypeMapper()))
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return
|
||||
|
||||
val frameMap = FrameMap()
|
||||
val v = InstructionAdapter(mv)
|
||||
mv.visitCode()
|
||||
|
||||
val methodOwner = method.getOwner()
|
||||
v.load(0, methodOwner) // Load this on stack
|
||||
val methodOwner = state.getTypeMapper().mapToCallableMethod(delegateFunctionDescriptor, false, context).getOwner()
|
||||
if (!isStatic) {
|
||||
frameMap.enterTemp(AsmTypes.OBJECT_TYPE)
|
||||
v.load(0, methodOwner) // Load this on stack
|
||||
} else {
|
||||
val delegateOwner = delegateFunctionDescriptor.getContainingDeclaration()
|
||||
if (delegateOwner is ClassDescriptor && delegateOwner.isCompanionObject()) {
|
||||
val singletonValue = StackValue.singleton(delegateOwner, state.getTypeMapper())
|
||||
singletonValue.put(singletonValue.type, v);
|
||||
}
|
||||
}
|
||||
|
||||
val receiver = functionDescriptor.getExtensionReceiverParameter()
|
||||
if (receiver != null) {
|
||||
val receiverType = state.getTypeMapper().mapType(receiver)
|
||||
val receiverIndex = frameMap.enter(receiver, receiverType)
|
||||
StackValue.local(receiverIndex, receiverType).put(receiverType, v)
|
||||
}
|
||||
remainingParameters.forEach {
|
||||
frameMap.enter(it, state.getTypeMapper().mapType(it))
|
||||
}
|
||||
|
||||
var mask = 0
|
||||
val masks = arrayListOf<Int>()
|
||||
for (parameterDescriptor in constructorDescriptor.getValueParameters()) {
|
||||
for (parameterDescriptor in functionDescriptor.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
|
||||
if (parameterDescriptor in remainingParameters) {
|
||||
val index = frameMap.getIndex(parameterDescriptor)
|
||||
val type = state.getTypeMapper().mapType(parameterDescriptor)
|
||||
StackValue.local(index, type).put(type, v)
|
||||
} else {
|
||||
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))
|
||||
}
|
||||
mask = mask or (1 shl (i % Integer.SIZE))
|
||||
}
|
||||
masks.add(mask)
|
||||
for (m in masks) {
|
||||
@@ -66,12 +162,24 @@ public class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
}
|
||||
|
||||
// constructors with default arguments has last synthetic argument of specific type
|
||||
v.aconst(null)
|
||||
if (functionDescriptor is ConstructorDescriptor) {
|
||||
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)
|
||||
val defaultMethod = state.getTypeMapper().mapDefaultMethod(delegateFunctionDescriptor, context.getContextKind(), context)
|
||||
if (functionDescriptor is ConstructorDescriptor) {
|
||||
v.invokespecial(methodOwner.getInternalName(), defaultMethod.getName(), defaultMethod.getDescriptor(), false)
|
||||
} else {
|
||||
v.invokestatic(methodOwner.getInternalName(), defaultMethod.getName(), defaultMethod.getDescriptor(), false)
|
||||
}
|
||||
v.areturn(signature.getReturnType())
|
||||
FunctionCodegen.endVisit(mv, null, methodElement)
|
||||
}
|
||||
|
||||
private fun getRemainingParameters(functionDescriptor: FunctionDescriptor,
|
||||
substituteCount: Int): List<ValueParameterDescriptor> {
|
||||
var remainingCount = functionDescriptor.countDefaultParameters() - substituteCount
|
||||
return functionDescriptor.getValueParameters().filter { !it.declaresDefaultValue() || --remainingCount >= 0 }
|
||||
}
|
||||
|
||||
private fun isEmptyConstructorNeeded(constructorDescriptor: ConstructorDescriptor, classOrObject: JetClassOrObject): Boolean {
|
||||
|
||||
@@ -113,6 +113,16 @@ public class FunctionCodegen {
|
||||
|
||||
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(),
|
||||
DefaultParameterValueLoader.DEFAULT, function);
|
||||
|
||||
generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor);
|
||||
}
|
||||
|
||||
public void generateOverloadsWithDefaultValues(@NotNull JetNamedFunction function,
|
||||
FunctionDescriptor functionDescriptor, FunctionDescriptor delegateFunctionDescriptor) {
|
||||
new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded(function,
|
||||
functionDescriptor,
|
||||
delegateFunctionDescriptor,
|
||||
owner, v);
|
||||
}
|
||||
|
||||
public void generateMethod(
|
||||
|
||||
@@ -1076,8 +1076,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION,
|
||||
DefaultParameterValueLoader.DEFAULT, null);
|
||||
|
||||
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||
new DefaultParameterValueSubstitutor(state).generateDefaultConstructorIfNeeded(callableMethod, constructorDescriptor, v, myClass);
|
||||
new DefaultParameterValueSubstitutor(state).generateDefaultConstructorIfNeeded(constructorDescriptor, v,
|
||||
constructorContext, myClass);
|
||||
|
||||
if (isCompanionObject(descriptor)) {
|
||||
context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext);
|
||||
|
||||
@@ -16,19 +16,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
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.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
class PlatformStaticGenerator(
|
||||
@@ -40,8 +41,9 @@ class PlatformStaticGenerator(
|
||||
override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) {
|
||||
val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor)
|
||||
|
||||
val originElement = declarationOrigin.element
|
||||
codegen.functionCodegen.generateMethod(
|
||||
Synthetic(declarationOrigin.element, staticFunctionDescriptor),
|
||||
Synthetic(originElement, staticFunctionDescriptor),
|
||||
staticFunctionDescriptor,
|
||||
object : FunctionGenerationStrategy() {
|
||||
override fun generateBody(
|
||||
@@ -74,6 +76,11 @@ class PlatformStaticGenerator(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
if (originElement is JetNamedFunction) {
|
||||
codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -663,13 +663,22 @@ public class JetTypeMapper {
|
||||
|
||||
@NotNull
|
||||
public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind) {
|
||||
if (f instanceof ConstructorDescriptor) {
|
||||
return mapSignature(f, kind, f.getOriginal().getValueParameters());
|
||||
}
|
||||
return mapSignature(f, kind, f.getValueParameters());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind,
|
||||
List<ValueParameterDescriptor> valueParameters) {
|
||||
BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
|
||||
|
||||
if (f instanceof ConstructorDescriptor) {
|
||||
sw.writeParametersStart();
|
||||
writeAdditionalConstructorParameters((ConstructorDescriptor) f, sw);
|
||||
|
||||
for (ValueParameterDescriptor parameter : f.getOriginal().getValueParameters()) {
|
||||
for (ValueParameterDescriptor parameter : valueParameters) {
|
||||
writeParameter(sw, parameter.getType());
|
||||
}
|
||||
|
||||
@@ -686,7 +695,7 @@ public class JetTypeMapper {
|
||||
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.getType());
|
||||
}
|
||||
|
||||
for (ValueParameterDescriptor parameter : f.getValueParameters()) {
|
||||
for (ValueParameterDescriptor parameter : valueParameters) {
|
||||
writeParameter(sw, parameter.getType());
|
||||
}
|
||||
|
||||
@@ -706,7 +715,7 @@ public class JetTypeMapper {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getDefaultDescriptor(@NotNull Method method, boolean isExtension) {
|
||||
public static String getDefaultDescriptor(@NotNull Method method, @Nullable String dispatchReceiverDescriptor, boolean isExtension) {
|
||||
String descriptor = method.getDescriptor();
|
||||
int argumentsCount = Type.getArgumentTypes(descriptor).length;
|
||||
if (isExtension) {
|
||||
@@ -717,7 +726,11 @@ public class JetTypeMapper {
|
||||
if (isConstructor(method)) {
|
||||
additionalArgs += Type.getObjectType(DEFAULT_CONSTRUCTOR_MARKER_INTERNAL_CLASS_NAME).getDescriptor();
|
||||
}
|
||||
return descriptor.replace(")", additionalArgs + ")");
|
||||
String result = descriptor.replace(")", additionalArgs + ")");
|
||||
if (dispatchReceiverDescriptor != null && !isConstructor(method)) {
|
||||
return result.replace("(", "(" + dispatchReceiverDescriptor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isConstructor(@NotNull Method method) {
|
||||
@@ -728,11 +741,10 @@ public class JetTypeMapper {
|
||||
public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext<?> context) {
|
||||
Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod();
|
||||
Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
|
||||
String descriptor = getDefaultDescriptor(jvmSignature, functionDescriptor.getExtensionReceiverParameter() != null);
|
||||
boolean isConstructor = isConstructor(jvmSignature);
|
||||
if (!isStaticMethod(kind, functionDescriptor) && !isConstructor) {
|
||||
descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
|
||||
}
|
||||
String descriptor = getDefaultDescriptor(jvmSignature,
|
||||
isStaticMethod(kind, functionDescriptor) || isConstructor ? null : ownerType.getDescriptor(),
|
||||
functionDescriptor.getExtensionReceiverParameter() != null);
|
||||
|
||||
return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
class C {
|
||||
companion object {
|
||||
[kotlin.platform.platformStatic] [kotlin.jvm.overloads] public fun foo(o: String, k: String = "K"): String {
|
||||
return o + k
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val m = javaClass<C>().getMethod("foo", javaClass<String>())
|
||||
return m.invoke(null, "O") as String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
[kotlin.jvm.overloads] public fun foo(d1: Double, d2: Double, status: String = "OK"): String {
|
||||
return if (d1 + d2 == 3.0) status else "fail"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
val m = c.javaClass.getMethod("foo", javaClass<Double>(), javaClass<Double>())
|
||||
return m.invoke(c, 1.0, 2.0) as String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
}
|
||||
|
||||
[kotlin.jvm.overloads] fun C.foo(o: String, k: String = "K"): String {
|
||||
return o + k
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val m = javaClass<C>().getClassLoader().loadClass("_DefaultPackage").getMethod("foo", javaClass<C>(), javaClass<String>())
|
||||
return m.invoke(null, C(), "O") as String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
[kotlin.jvm.overloads] public fun foo(o: String = "O", k: String = "K"): String {
|
||||
return o + k
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
val m = c.javaClass.getMethod("foo")
|
||||
return m.invoke(c) as String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
[kotlin.jvm.overloads] public fun foo(o: String, k: String = "K"): String {
|
||||
return o + k
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
val m = c.javaClass.getMethod("foo", javaClass<String>())
|
||||
return m.invoke(c, "O") as String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
[kotlin.jvm.overloads] public fun foo(s: String = "OK"): String {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
val m = c.javaClass.getMethod("foo")
|
||||
return m.invoke(c) as String
|
||||
}
|
||||
+46
@@ -46,6 +46,7 @@ import java.util.regex.Pattern;
|
||||
BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class,
|
||||
BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class,
|
||||
BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class,
|
||||
BlackBoxWithStdlibCodegenTestGenerated.JvmOverloads.class,
|
||||
BlackBoxWithStdlibCodegenTestGenerated.LazyCodegen.class,
|
||||
BlackBoxWithStdlibCodegenTestGenerated.LocalFunInLambda.class,
|
||||
BlackBoxWithStdlibCodegenTestGenerated.MultiDeclForArray.class,
|
||||
@@ -1640,6 +1641,51 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class JvmOverloads extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInJvmOverloads() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/jvmOverloads"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("companionObject.kt")
|
||||
public void testCompanionObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads/companionObject.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doubleParameters.kt")
|
||||
public void testDoubleParameters() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads/doubleParameters.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionMethod.kt")
|
||||
public void testExtensionMethod() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads/extensionMethod.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleDefaultParameters.kt")
|
||||
public void testMultipleDefaultParameters() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads/multipleDefaultParameters.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nonDefaultParameter.kt")
|
||||
public void testNonDefaultParameter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads/nonDefaultParameter.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmOverloads/simple.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/lazyCodegen")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 kotlin.jvm
|
||||
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
|
||||
/**
|
||||
* Instructs the Kotlin compiler to generate overloads for this function that substitute default parameter values.
|
||||
*/
|
||||
Retention(RetentionPolicy.SOURCE)
|
||||
public annotation class overloads
|
||||
Reference in New Issue
Block a user