JVM: generate 'Deprecated' on method as runtime-visible annotation
We generate @java.lang.Deprecated annotation on methods of $DefaultImpls classes in compatibility mode. This annotation has RUNTIME retention and should be visible. Also, get rid of representing annotations as Class'es (yes we know that these annotations are in compiler CLASSPATH, but we should not rely on such classes and associated information).
This commit is contained in:
@@ -50,6 +50,9 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getA
|
||||
|
||||
public abstract class AnnotationCodegen {
|
||||
|
||||
private static final String ORG_JETBRAINS_ANNOTATIONS_NOTNULL = Type.getType(NotNull.class).getDescriptor();
|
||||
private static final String ORG_JETBRAINS_ANNOTATIONS_NULLABLE = Type.getType(Nullable.class).getDescriptor();
|
||||
|
||||
public static final class JvmFlagAnnotation {
|
||||
private final FqName fqName;
|
||||
private final int jvmFlag;
|
||||
@@ -120,7 +123,7 @@ public abstract class AnnotationCodegen {
|
||||
@Nullable Type returnType,
|
||||
@Nullable KotlinType typeForTypeAnnotations,
|
||||
@Nullable DeclarationDescriptorWithVisibility parameterContainer,
|
||||
@NotNull List<Class<?>> additionalAnnotations
|
||||
@NotNull List<String> additionalVisibleAnnotations
|
||||
) {
|
||||
if (annotated == null) return;
|
||||
|
||||
@@ -155,9 +158,9 @@ public abstract class AnnotationCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
for (Class<?> annotation : additionalAnnotations) {
|
||||
String descriptor = generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotation);
|
||||
annotationDescriptorsAlreadyPresent.add(descriptor);
|
||||
for (String annotation : additionalVisibleAnnotations) {
|
||||
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotation, true);
|
||||
annotationDescriptorsAlreadyPresent.add(annotation);
|
||||
}
|
||||
|
||||
generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent, parameterContainer);
|
||||
@@ -248,17 +251,15 @@ public abstract class AnnotationCodegen {
|
||||
if (!TypeUtils.isNullableType(flexibleType.getLowerBound()) && TypeUtils.isNullableType(flexibleType.getUpperBound())) {
|
||||
AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
|
||||
if (notNull != null) {
|
||||
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class);
|
||||
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, ORG_JETBRAINS_ANNOTATIONS_NOTNULL, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isNullableType = TypeUtils.isNullableType(type);
|
||||
|
||||
Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class;
|
||||
|
||||
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
|
||||
String annotationDescriptor =
|
||||
TypeUtils.isNullableType(type) ? ORG_JETBRAINS_ANNOTATIONS_NULLABLE : ORG_JETBRAINS_ANNOTATIONS_NOTNULL;
|
||||
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationDescriptor, false);
|
||||
}
|
||||
|
||||
private static final Map<JvmTarget, Map<KotlinTarget, ElementType>> annotationTargetMaps = new EnumMap<>(JvmTarget.class);
|
||||
@@ -338,13 +339,14 @@ public abstract class AnnotationCodegen {
|
||||
visitor.visitEnd();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) {
|
||||
String descriptor = Type.getType(annotationClass).getDescriptor();
|
||||
if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
|
||||
visitAnnotation(descriptor, false).visitEnd();
|
||||
private void generateAnnotationIfNotPresent(
|
||||
Set<String> annotationDescriptorsAlreadyPresent,
|
||||
String annotationDescriptor,
|
||||
boolean visible
|
||||
) {
|
||||
if (!annotationDescriptorsAlreadyPresent.contains(annotationDescriptor)) {
|
||||
visitAnnotation(annotationDescriptor, visible).visitEnd();
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull KotlinType type) {
|
||||
|
||||
@@ -83,6 +83,8 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class FunctionCodegen {
|
||||
private static final String JAVA_LANG_DEPRECATED = Type.getType(Deprecated.class).getDescriptor();
|
||||
|
||||
public final GenerationState state;
|
||||
private final KotlinTypeMapper typeMapper;
|
||||
private final BindingContext bindingContext;
|
||||
@@ -221,7 +223,7 @@ public class FunctionCodegen {
|
||||
InlineClassDescriptorResolver.isSpecializedEqualsMethod(functionDescriptor);
|
||||
generateMethodAnnotationsIfRequired(
|
||||
functionDescriptor, asmMethod, jvmSignature, mv,
|
||||
isCompatibilityStubInDefaultImpls ? Collections.singletonList(Deprecated.class) : Collections.emptyList(),
|
||||
isCompatibilityStubInDefaultImpls ? Collections.singletonList(JAVA_LANG_DEPRECATED) : Collections.emptyList(),
|
||||
skipNullabilityAnnotations
|
||||
);
|
||||
GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0);
|
||||
@@ -285,7 +287,7 @@ public class FunctionCodegen {
|
||||
@NotNull Method asmMethod,
|
||||
@NotNull JvmMethodGenericSignature jvmSignature,
|
||||
@NotNull MethodVisitor mv,
|
||||
@NotNull List<Class<?>> additionalNoArgAnnotations,
|
||||
@NotNull List<String> additionalVisibleAnnotations,
|
||||
boolean skipNullabilityAnnotations
|
||||
) {
|
||||
FunctionDescriptor annotationsOwner;
|
||||
@@ -302,7 +304,7 @@ public class FunctionCodegen {
|
||||
}
|
||||
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, state, skipNullabilityAnnotations)
|
||||
.genAnnotations(annotationsOwner, asmMethod.getReturnType(), functionDescriptor.getReturnType(), null, additionalNoArgAnnotations);
|
||||
.genAnnotations(annotationsOwner, asmMethod.getReturnType(), functionDescriptor.getReturnType(), null, additionalVisibleAnnotations);
|
||||
|
||||
generateParameterAnnotations(
|
||||
annotationsOwner, mv, jvmSignature,
|
||||
|
||||
Generated
+5
@@ -15640,6 +15640,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("deprecatedAnnotation.kt")
|
||||
public void testDeprecatedAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/deprecatedAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
|
||||
public void testInheritedFunctionWithDefaultParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// !JVM_DEFAULT_MODE: compatibility
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// FULL_JDK
|
||||
// WITH_RUNTIME
|
||||
|
||||
interface IFoo {
|
||||
@JvmDefault
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val iFoo = IFoo::class.java
|
||||
val iFooDefaultImpls = Class.forName("${iFoo.name}\$DefaultImpls")
|
||||
val fooMethod = iFooDefaultImpls.declaredMethods.find { it.name == "foo" }
|
||||
?: throw AssertionError("No method 'foo' in class ${iFooDefaultImpls.name}")
|
||||
fooMethod.getAnnotation(java.lang.Deprecated::class.java)
|
||||
?: throw AssertionError("No java.lang.Deprecated annotation on method 'foo'")
|
||||
return "OK"
|
||||
}
|
||||
+5
@@ -16865,6 +16865,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("deprecatedAnnotation.kt")
|
||||
public void testDeprecatedAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/deprecatedAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
|
||||
public void testInheritedFunctionWithDefaultParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
|
||||
|
||||
+5
@@ -16865,6 +16865,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("deprecatedAnnotation.kt")
|
||||
public void testDeprecatedAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/deprecatedAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
|
||||
public void testInheritedFunctionWithDefaultParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
|
||||
|
||||
+5
@@ -15640,6 +15640,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("deprecatedAnnotation.kt")
|
||||
public void testDeprecatedAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/deprecatedAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
|
||||
public void testInheritedFunctionWithDefaultParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
|
||||
|
||||
Reference in New Issue
Block a user