diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index b1c257a9429..43c4bf67211 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -27,10 +27,7 @@ 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.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations; -import org.jetbrains.kotlin.codegen.context.CodegenContext; -import org.jetbrains.kotlin.codegen.context.CodegenContextUtil; -import org.jetbrains.kotlin.codegen.context.DelegatingFacadeContext; -import org.jetbrains.kotlin.codegen.context.MethodContext; +import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; @@ -39,6 +36,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo; +import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.JetNamedFunction; @@ -228,6 +226,22 @@ public class FunctionCodegen { else { annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType()); } + + writePackageFacadeMethodAnnotationsIfNeeded(mv); + } + + private void writePackageFacadeMethodAnnotationsIfNeeded(MethodVisitor mv) { + if (owner instanceof PackageFacadeContext) { + PackageFacadeContext packageFacadeContext = (PackageFacadeContext) owner; + Type delegateToClassType = packageFacadeContext.getDelegateToClassType(); + if (delegateToClassType != null) { + String className = delegateToClassType.getClassName(); + AnnotationVisitor + av = mv.visitAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_DELEGATED_METHOD), true); + av.visit(JvmAnnotationNames.IMPLEMENTATION_CLASS_NAME_FIELD_NAME, className); + av.visitEnd(); + } + } } private void generateParameterAnnotations( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java index 9ee7a1d8cff..98bec291a00 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java @@ -219,7 +219,7 @@ public class PackageCodegen { for (JetFile file : files) { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); try { - ClassBuilder builder = generate(file, generateCallableMemberTasks); + ClassBuilder builder = generatePart(file, generateCallableMemberTasks); if (builder != null) { bindings.add(builder.getSerializationBindings()); } @@ -257,7 +257,8 @@ public class PackageCodegen { } bindings.add(v.getSerializationBindings()); - writeKotlinPackageAnnotationIfNeeded(JvmSerializationBindings.union(bindings), tasks.keySet()); + writeDeprecatedAnnotation(); + writeKotlinPackageAnnotationIfNeeded(JvmSerializationBindings.union(bindings)); } private void generateKotlinPackageReflectionField() { @@ -269,15 +270,12 @@ public class PackageCodegen { FunctionCodegen.endVisit(mv, "package facade static initializer", null); } - private void writeKotlinPackageAnnotationIfNeeded( - @NotNull JvmSerializationBindings bindings, - @NotNull final Collection relevantCallables - ) { + private void writeKotlinPackageAnnotationIfNeeded(@NotNull JvmSerializationBindings bindings) { if (state.getClassBuilderMode() != ClassBuilderMode.FULL) { return; } - // SCRIPT: Do not write annotations for scripts (if any is??) + // SCRIPT: Do not write KotlinPackage annotation for scripts (if any is??) for (JetFile file : files) { if (file.isScript()) return; } @@ -289,7 +287,6 @@ public class PackageCodegen { ProtoBuf.Package packageProto = serializer.packageProto(packageFragments, new Function1() { @Override public Boolean invoke(DeclarationDescriptor descriptor) { -// return !(descriptor instanceof CallableMemberDescriptor && relevantCallables.contains(descriptor)); return true; } }).build(); @@ -306,8 +303,13 @@ public class PackageCodegen { av.visitEnd(); } + private void writeDeprecatedAnnotation() { + AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.JAVA_LANG_DEPRECATED), true); + av.visitEnd(); + } + @Nullable - private ClassBuilder generate(@NotNull JetFile file, @NotNull Map generateCallableMemberTasks) { + private ClassBuilder generatePart(@NotNull JetFile file, @NotNull Map generateCallableMemberTasks) { boolean generatePackagePart = false; Type packagePartType = FileClassesPackage.getFileClassType(state.getFileClassesProvider(), file); PackageContext packagePartContext = state.getRootContext().intoPackagePart(packageFragment, packagePartType); diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java index c4eae18b754..99e3a8daeb7 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java @@ -1,4 +1,6 @@ +@java.lang.Deprecated public final class _DefaultPackage { + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "NullableUnitReturnKt") @org.jetbrains.annotations.Nullable public static final kotlin.Unit foo() { /* compiled code */ } } \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java index b4a2a94978a..6b53f1e493a 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java @@ -1,3 +1,5 @@ +@java.lang.Deprecated public final class _DefaultPackage { + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "UnitParameterKt") public static final void foo(@org.jetbrains.annotations.NotNull kotlin.Unit s) { /* compiled code */ } } \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java index 17eb6d488d9..adebde7c1ab 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java @@ -1,3 +1,5 @@ +@java.lang.Deprecated public final class _DefaultPackage { + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "VoidReturnKt") public static final void foo(@org.jetbrains.annotations.NotNull java.lang.String s) { /* compiled code */ } } \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java index 7200fd00117..fb95bde5bad 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java @@ -1,68 +1,90 @@ +@java.lang.Deprecated public final class _DefaultPackage { + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull public static final java.lang.String getNotNullVal() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable @org.jetbrains.annotations.NotNull public static final java.lang.String getNotNullValWithGet() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull public static final java.lang.String getNotNullVar() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") public static final void setNotNullVar(@org.jetbrains.annotations.NotNull java.lang.String p) { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable @org.jetbrains.annotations.NotNull public static final java.lang.String getNotNullVarWithGetSet() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final void setNotNullVarWithGetSet(@org.jetbrains.annotations.NotNull java.lang.String v) { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final java.lang.String getNullableVal() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull @org.jetbrains.annotations.Nullable public static final java.lang.String getNullableValWithGet() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final java.lang.String getNullableVar() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") public static final void setNullableVar(@org.jetbrains.annotations.Nullable java.lang.String p) { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull @org.jetbrains.annotations.Nullable public static final java.lang.String getNullableVarWithGetSet() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull public static final void setNullableVarWithGetSet(@org.jetbrains.annotations.Nullable java.lang.String v) { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final java.lang.String getPrivateN() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull public static final java.lang.String getPrivateNn() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull public static final java.lang.String notNull(@org.jetbrains.annotations.NotNull java.lang.String a) { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable @org.jetbrains.annotations.NotNull public static final java.lang.String notNullWithN() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull public static final java.lang.String notNullWithNN() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final java.lang.String nullable(@org.jetbrains.annotations.Nullable java.lang.String a) { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final java.lang.String nullableWithN() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.NotNull @org.jetbrains.annotations.Nullable public static final java.lang.String nullableWithNN() { /* compiled code */ } + @kotlin.jvm.internal.KotlinDelegatedMethod(implementationClassName = "_DefaultPackageKt") @org.jetbrains.annotations.Nullable public static final java.lang.String privateFun(@org.jetbrains.annotations.NotNull java.lang.String a, @org.jetbrains.annotations.Nullable java.lang.String b) { /* compiled code */ } } \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeIsDeprecated.kt b/compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeIsDeprecated.kt new file mode 100644 index 00000000000..76eb3f7f84c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeIsDeprecated.kt @@ -0,0 +1,18 @@ +package test + +fun findClassOrFail(className: String): Class<*> = + try { + Class.forName(className) + } + catch (e: Exception) { + throw AssertionError("Class $className not found") + } + +fun box(): String { + val testPackage = findClassOrFail("test.TestPackage") + val deprecated = findClassOrFail("java.lang.Deprecated") as Class + val ann = testPackage.getAnnotation(deprecated) + assert(ann != null) { "Package facade ${testPackage.name} is not deprecated" } + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeMethodsAnnotation.kt b/compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeMethodsAnnotation.kt new file mode 100644 index 00000000000..1ae95fa7a98 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeMethodsAnnotation.kt @@ -0,0 +1,47 @@ +package test + +import kotlin.jvm.internal.KotlinDelegatedMethod + +fun findClassOrFail(className: String): Class<*> = + try { + Class.forName(className) + } + catch (e: Exception) { + throw AssertionError("Class $className not found") + } + +fun box(): String { + val testPackage = findClassOrFail("test.TestPackage") + val kotlinDelegatedMethod = findClassOrFail("kotlin.jvm.internal.KotlinDelegatedMethod") as Class + + assert(testPackage.declaredMethods.size() > 0) { "Class ${testPackage.name} has no declared methods" } + + for (method in testPackage.declaredMethods) { + val ann = method.getAnnotation(kotlinDelegatedMethod) as? KotlinDelegatedMethod + if (ann == null) { + throw AssertionError("Method ${method.name} has no ${kotlinDelegatedMethod.simpleName} annotation.") + } + + val implementationClassName = ann.implementationClassName() + val implementationClass = try { + Class.forName(implementationClassName) + } + catch (e: Exception) { + throw AssertionError("Implementation class $implementationClassName for method ${method.name} not found.") + } + + val implementationMethod = try { + implementationClass.getMethod(method.name, *method.parameterTypes) + } + catch (e: Exception) { + throw AssertionError("Implementation class $implementationClassName for method ${method.name} has no corresponding implementation method.") + } + + assert(implementationMethod.modifiers == method.modifiers) { + "Implementation method for ${method.name} in $implementationClassName: " + + "expected modifiers: ${method.modifiers}; actual modifiers: ${implementationMethod.modifiers}" + } + } + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/annotations/onReceiver.txt b/compiler/testData/codegen/bytecodeListing/annotations/onReceiver.txt index 3f042a15c1a..108f7aae796 100644 --- a/compiler/testData/codegen/bytecodeListing/annotations/onReceiver.txt +++ b/compiler/testData/codegen/bytecodeListing/annotations/onReceiver.txt @@ -13,10 +13,10 @@ @org.jetbrains.annotations.NotNull method getTopLevelP(@Ann p0: java.lang.String): java.lang.String } -@kotlin.jvm.internal.KotlinPackage _DefaultPackage { +@java.lang.Deprecated @kotlin.jvm.internal.KotlinPackage _DefaultPackage { field $kotlinPackage: kotlin.reflect.KPackage field $moduleName: java.lang.String method (): void - @org.jetbrains.annotations.NotNull method getTopLevelP(@Ann p0: java.lang.String): java.lang.String - @org.jetbrains.annotations.NotNull method topLevelF(@Ann p0: java.lang.String): java.lang.String + @kotlin.jvm.internal.KotlinDelegatedMethod @org.jetbrains.annotations.NotNull method getTopLevelP(@Ann p0: java.lang.String): java.lang.String + @kotlin.jvm.internal.KotlinDelegatedMethod @org.jetbrains.annotations.NotNull method topLevelF(@Ann p0: java.lang.String): java.lang.String } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 8fb3b880498..92da717e6be 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -106,6 +106,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("packageFacadeIsDeprecated.kt") + public void testPackageFacadeIsDeprecated() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeIsDeprecated.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("packageFacadeMethodsAnnotation.kt") + public void testPackageFacadeMethodsAnnotation() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/packageFacadeMethodsAnnotation.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("parameterWithPrimitiveType.kt") public void testParameterWithPrimitiveType() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/parameterWithPrimitiveType.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java index 33c212dfcff..ee335c6aa36 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java @@ -35,6 +35,11 @@ public final class JvmAnnotationNames { public static final FqName KOTLIN_MULTIFILE_CLASS_PART = new FqName("kotlin.jvm.internal.KotlinMultifileClassPart"); public static final FqName KOTLIN_CALLABLE = new FqName("kotlin.jvm.internal.KotlinCallable"); + public static final FqName JAVA_LANG_DEPRECATED = new FqName("java.lang.Deprecated"); + + public static final FqName KOTLIN_DELEGATED_METHOD = new FqName("kotlin.jvm.internal.KotlinDelegatedMethod"); + public static final String IMPLEMENTATION_CLASS_NAME_FIELD_NAME = "implementationClassName"; + public static final FqName KOTLIN_SIGNATURE = new FqName("kotlin.jvm.KotlinSignature"); public static final FqName OLD_KOTLIN_SIGNATURE = new FqName("jet.runtime.typeinfo.KotlinSignature"); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinDelegatedMethod.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinDelegatedMethod.java new file mode 100644 index 00000000000..00159cd944c --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinDelegatedMethod.java @@ -0,0 +1,28 @@ +/* + * 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.internal; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface KotlinDelegatedMethod { + String implementationClassName(); +}