Generate @NotNull annotations on delegated functions
This commit is contained in:
@@ -42,6 +42,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DELEGATION;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
|
||||
|
||||
public abstract class AnnotationCodegen {
|
||||
@@ -93,7 +94,13 @@ public abstract class AnnotationCodegen {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiElement psiElement = descriptorToDeclaration(bindingContext, (DeclarationDescriptor) annotated);
|
||||
PsiElement psiElement;
|
||||
if (annotated instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) annotated).getKind() == DELEGATION) {
|
||||
psiElement = null;
|
||||
}
|
||||
else {
|
||||
psiElement = descriptorToDeclaration(bindingContext, (DeclarationDescriptor) annotated);
|
||||
}
|
||||
|
||||
JetModifierList modifierList = null;
|
||||
if (annotated instanceof ConstructorDescriptor && psiElement instanceof JetClass) {
|
||||
|
||||
@@ -1948,7 +1948,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
KotlinSyntheticClass.Kind.SAM_LAMBDA);
|
||||
}
|
||||
|
||||
Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingJetFile());
|
||||
Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingJetFile(), getParentCodegen());
|
||||
|
||||
v.anew(asmType);
|
||||
v.dup();
|
||||
|
||||
@@ -68,7 +68,6 @@ import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
|
||||
import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
@@ -764,48 +763,50 @@ public class FunctionCodegen extends ParentCodegenAware {
|
||||
|
||||
public void genDelegate(
|
||||
FunctionDescriptor functionDescriptor,
|
||||
ClassDescriptor toClass,
|
||||
StackValue field,
|
||||
JvmMethodSignature jvmDelegateMethodSignature,
|
||||
JvmMethodSignature jvmOverriddenMethodSignature
|
||||
final ClassDescriptor toClass,
|
||||
final StackValue field,
|
||||
final JvmMethodSignature jvmDelegateMethodSignature,
|
||||
final JvmMethodSignature jvmOverriddenMethodSignature
|
||||
) {
|
||||
Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
|
||||
Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
|
||||
generateMethod(OtherOrigin(functionDescriptor),
|
||||
jvmDelegateMethodSignature,
|
||||
functionDescriptor,
|
||||
new FunctionGenerationStrategy() {
|
||||
@Override
|
||||
public void generateBody(
|
||||
@NotNull MethodVisitor mv,
|
||||
@NotNull JvmMethodSignature signature,
|
||||
@NotNull MethodContext context,
|
||||
@NotNull MemberCodegen<?> parentCodegen
|
||||
) {
|
||||
Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
|
||||
Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
|
||||
|
||||
int flags = ACC_PUBLIC;
|
||||
Type[] argTypes = delegateMethod.getArgumentTypes();
|
||||
Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
|
||||
|
||||
MethodVisitor mv = v.newMethod(OtherOrigin(functionDescriptor), flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null,
|
||||
getThrownExceptions(functionDescriptor, typeMapper));
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.load(0, OBJECT_TYPE);
|
||||
field.put(field.type, iv);
|
||||
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
||||
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
|
||||
//noinspection AssignmentToForLoopParameter
|
||||
reg += argTypes[i].getSize();
|
||||
}
|
||||
|
||||
mv.visitCode();
|
||||
String internalName = typeMapper.mapType(toClass).getInternalName();
|
||||
if (toClass.getKind() == ClassKind.TRAIT) {
|
||||
iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
|
||||
}
|
||||
else {
|
||||
iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
|
||||
}
|
||||
|
||||
Type[] argTypes = delegateMethod.getArgumentTypes();
|
||||
Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
|
||||
StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
|
||||
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.load(0, OBJECT_TYPE);
|
||||
field.put(field.type, iv);
|
||||
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
||||
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
|
||||
//noinspection AssignmentToForLoopParameter
|
||||
reg += argTypes[i].getSize();
|
||||
}
|
||||
|
||||
String internalName = typeMapper.mapType(toClass).getInternalName();
|
||||
if (toClass.getKind() == ClassKind.TRAIT) {
|
||||
iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
|
||||
}
|
||||
else {
|
||||
iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
|
||||
}
|
||||
|
||||
StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
|
||||
|
||||
iv.areturn(delegateMethod.getReturnType());
|
||||
endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
|
||||
descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
|
||||
|
||||
generateBridges(functionDescriptor);
|
||||
iv.areturn(delegateMethod.getReturnType());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ public class SamWrapperClasses {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type getSamWrapperClass(@NotNull final SamType samType, @NotNull final JetFile file) {
|
||||
public Type getSamWrapperClass(@NotNull final SamType samType, @NotNull final JetFile file, @NotNull final MemberCodegen<?> parentCodegen) {
|
||||
return ContainerUtil.getOrCreate(samInterfaceToWrapperClass, Pair.create(samType, file),
|
||||
new Factory<Type>() {
|
||||
@Override
|
||||
public Type create() {
|
||||
return new SamWrapperCodegen(state, samType).genWrapper(file);
|
||||
return new SamWrapperCodegen(state, samType, parentCodegen).genWrapper(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
@@ -34,11 +34,12 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.NO_FLAG_PACKAGE_PRIVATE;
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation;
|
||||
import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
|
||||
import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class SamWrapperCodegen {
|
||||
@@ -47,21 +48,37 @@ public class SamWrapperCodegen {
|
||||
private final GenerationState state;
|
||||
private final JetTypeMapper typeMapper;
|
||||
private final SamType samType;
|
||||
private final MemberCodegen<?> parentCodegen;
|
||||
|
||||
public SamWrapperCodegen(@NotNull GenerationState state, @NotNull SamType samType) {
|
||||
public SamWrapperCodegen(@NotNull GenerationState state, @NotNull SamType samType, @NotNull MemberCodegen<?> parentCodegen) {
|
||||
this.state = state;
|
||||
this.typeMapper = state.getTypeMapper();
|
||||
this.samType = samType;
|
||||
this.parentCodegen = parentCodegen;
|
||||
}
|
||||
|
||||
public Type genWrapper(@NotNull JetFile file) {
|
||||
// Name for generated class, in form of whatever$1
|
||||
Type asmType = Type.getObjectType(getWrapperName(file));
|
||||
FqName fqName = getWrapperName(file);
|
||||
Type asmType = asmTypeByFqNameWithoutInnerClasses(fqName);
|
||||
|
||||
// e.g. (T, T) -> Int
|
||||
JetType functionType = samType.getKotlinFunctionType();
|
||||
|
||||
ClassDescriptor classDescriptor = new ClassDescriptorImpl(
|
||||
samType.getJavaClassDescriptor().getContainingDeclaration(),
|
||||
fqName.shortName(),
|
||||
Modality.FINAL,
|
||||
Collections.singleton(samType.getType())
|
||||
);
|
||||
// e.g. compare(T, T)
|
||||
SimpleFunctionDescriptor erasedInterfaceFunction = samType.getAbstractMethod().getOriginal();
|
||||
SimpleFunctionDescriptor erasedInterfaceFunction = samType.getAbstractMethod().getOriginal().copy(
|
||||
classDescriptor,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
/*copyOverrides=*/ false
|
||||
);
|
||||
|
||||
ClassBuilder cv = state.getFactory().newVisitor(OtherOrigin(erasedInterfaceFunction), asmType, file);
|
||||
cv.defineClass(file,
|
||||
@@ -124,7 +141,8 @@ public class SamWrapperCodegen {
|
||||
JetType functionJetType
|
||||
) {
|
||||
// using static context to avoid creating ClassDescriptor and everything else
|
||||
FunctionCodegen codegen = new FunctionCodegen(CodegenContext.STATIC, cv, state, null);
|
||||
FunctionCodegen codegen = new FunctionCodegen(CodegenContext.STATIC.intoClass(
|
||||
(ClassDescriptor) erasedInterfaceFunction.getContainingDeclaration(), OwnerKind.IMPLEMENTATION, state), cv, state, parentCodegen);
|
||||
|
||||
FunctionDescriptor invokeFunction = functionJetType.getMemberScope()
|
||||
.getFunctions(Name.identifier("invoke")).iterator().next().getOriginal();
|
||||
@@ -133,14 +151,14 @@ public class SamWrapperCodegen {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getWrapperName(@NotNull JetFile containingFile) {
|
||||
private FqName getWrapperName(@NotNull JetFile containingFile) {
|
||||
FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(containingFile.getPackageFqName());
|
||||
String packageInternalName = AsmUtil.internalNameByFqNameWithoutInnerClasses(packageClassFqName);
|
||||
JavaClassDescriptor descriptor = samType.getJavaClassDescriptor();
|
||||
return packageInternalName + "$sam$" + descriptor.getName().asString() + "$" +
|
||||
Integer.toHexString(
|
||||
PackagePartClassUtils.getPathHashCode(containingFile.getVirtualFile()) * 31 +
|
||||
DescriptorUtils.getFqNameSafe(descriptor).hashCode()
|
||||
);
|
||||
String shortName = packageClassFqName.shortName().asString() + "$sam$" + descriptor.getName().asString() + "$" +
|
||||
Integer.toHexString(
|
||||
PackagePartClassUtils.getPathHashCode(containingFile.getVirtualFile()) * 31 +
|
||||
DescriptorUtils.getFqNameSafe(descriptor).hashCode()
|
||||
);
|
||||
return packageClassFqName.parent().child(Name.identifier(shortName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
public final class Derived implements kotlin.jvm.internal.KObject, Base {
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public Derived(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "x") Base x) { /* compiled code */ }
|
||||
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public java.lang.String baz(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "s") java.lang.String s) { /* compiled code */ }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Derived
|
||||
|
||||
trait Base {
|
||||
fun baz(s: String): String
|
||||
}
|
||||
|
||||
class Derived(x: Base): Base by x
|
||||
@@ -0,0 +1,7 @@
|
||||
public final class Derived implements kotlin.jvm.internal.KObject, Base {
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public Derived(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "x") Base x) { /* compiled code */ }
|
||||
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public java.lang.String getBoo() { /* compiled code */ }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Derived
|
||||
|
||||
trait Base {
|
||||
val boo: String
|
||||
}
|
||||
|
||||
class Derived(x: Base): Base by x
|
||||
@@ -16,24 +16,45 @@
|
||||
|
||||
package org.jetbrains.jet.asJava;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jetbrains.jet.asJava.AbstractKotlinLightClassTest;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("compiler/testData/asJava/lightClasses")
|
||||
@InnerTestClasses({KotlinLightClassTestGenerated.NullabilityAnnotations.class})
|
||||
@InnerTestClasses({KotlinLightClassTestGenerated.Delegation.class, KotlinLightClassTestGenerated.NullabilityAnnotations.class})
|
||||
public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest {
|
||||
public void testAllFilesPresentInLightClasses() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/asJava/lightClasses/delegation")
|
||||
public static class Delegation extends AbstractKotlinLightClassTest {
|
||||
public void testAllFilesPresentInDelegation() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("Function.kt")
|
||||
public void testFunction() throws Exception {
|
||||
doTest("compiler/testData/asJava/lightClasses/delegation/Function.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Property.kt")
|
||||
public void testProperty() throws Exception {
|
||||
doTest("compiler/testData/asJava/lightClasses/delegation/Property.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/asJava/lightClasses/nullabilityAnnotations")
|
||||
public static class NullabilityAnnotations extends AbstractKotlinLightClassTest {
|
||||
public void testAllFilesPresentInNullabilityAnnotations() throws Exception {
|
||||
@@ -105,6 +126,7 @@ public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite("KotlinLightClassTestGenerated");
|
||||
suite.addTestSuite(KotlinLightClassTestGenerated.class);
|
||||
suite.addTestSuite(Delegation.class);
|
||||
suite.addTestSuite(NullabilityAnnotations.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user