From f2bf81e799a512219ff791bae76607e637a938cc Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 13 Feb 2019 17:49:03 +0100 Subject: [PATCH] Fix UOE when using Java annotation with infinity/NaN as default value The root problem is the fact that ConstantExpressionEvaluator returns null for values such as infinity and NaN loaded from cls psi (see IDEA-207252). This commit simply reverts a part of 8ab9226805 where we started to compute default values more often than needed. In LazyJavaClassMemberScope, we only need to check whether or not there _is_ a default value, not compute its value. #KT-29792 Fixed --- .../java/structure/impl/JavaMethodImpl.java | 6 +++++ .../annotations/divisionByZeroInJava.kt | 23 +++++++++++++++++++ .../AbstractBlackBoxAgainstJavaCodegenTest.kt | 6 ++++- ...ackBoxAgainstJavaCodegenTestGenerated.java | 5 ++++ ...ackBoxAgainstJavaCodegenTestGenerated.java | 5 ++++ .../descriptors/LazyJavaClassMemberScope.kt | 2 +- .../load/java/structure/javaElements.kt | 5 ++++ .../infinityAndNanInJavaAnnotation.kt | 8 +++++++ .../infinityAndNanInJavaAnnotationSrc/J.java | 13 +++++++++++ .../ReferenceResolveWithLibTestGenerated.java | 5 ++++ 10 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/boxAgainstJava/annotations/divisionByZeroInJava.kt create mode 100644 idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotation.kt create mode 100644 idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotationSrc/J.java diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaMethodImpl.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaMethodImpl.java index 64f6316ba65..7ee10914c77 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaMethodImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/JavaMethodImpl.java @@ -69,6 +69,12 @@ public class JavaMethodImpl extends JavaMemberImpl implements JavaMet return null; } + @Override + public boolean getHasAnnotationParameterDefaultValue() { + PsiMethod psiMethod = getPsi(); + return psiMethod instanceof PsiAnnotationMethod && ((PsiAnnotationMethod) psiMethod).getDefaultValue() != null; + } + @Override @NotNull public JavaType getReturnType() { diff --git a/compiler/testData/codegen/boxAgainstJava/annotations/divisionByZeroInJava.kt b/compiler/testData/codegen/boxAgainstJava/annotations/divisionByZeroInJava.kt new file mode 100644 index 00000000000..692535b68f2 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/annotations/divisionByZeroInJava.kt @@ -0,0 +1,23 @@ +// KOTLIN_CONFIGURATION_FLAGS: -JVM.USE_FAST_CLASS_FILES_READING +// FILE: J.java + +public @interface J { + double minusInf() default Double.NEGATIVE_INFINITY; + double plusInf() default Double.POSITIVE_INFINITY; + double nan() default Double.NaN; + double divisionByZero() default 1.0 / 0.0; + + float minusInfFloat() default Float.NEGATIVE_INFINITY; + float plusInfFloat() default Float.POSITIVE_INFINITY; + float nanFloat() default Float.NaN; + float divisionByZeroFloat() default 1.0f / 0.0f; +} + +// FILE: K.kt + +fun box(): String { + // Only check that the compiler loads the class for J + J::class + + return "OK" +} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxAgainstJavaCodegenTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxAgainstJavaCodegenTest.kt index 50855c2e788..1c48829d9a0 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxAgainstJavaCodegenTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxAgainstJavaCodegenTest.kt @@ -33,7 +33,11 @@ abstract class AbstractBlackBoxAgainstJavaCodegenTest : AbstractBlackBoxCodegenT override fun updateConfiguration(configuration: CompilerConfiguration) { configuration.addJvmClasspathRoot(javaClassesOutputDirectory) - configuration.put(JVMConfigurationKeys.USE_FAST_CLASS_FILES_READING, true) + + if (configuration.get(JVMConfigurationKeys.USE_FAST_CLASS_FILES_READING) == null) { + // By default (unless disabled in the test with a directive), use the fast class reading mode + configuration.put(JVMConfigurationKeys.USE_FAST_CLASS_FILES_READING, true) + } } override fun extractConfigurationKind(files: MutableList): ConfigurationKind { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java index 6baf5d2ec78..905441dfcde 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -41,6 +41,11 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxAga KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("divisionByZeroInJava.kt") + public void testDivisionByZeroInJava() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/annotations/divisionByZeroInJava.kt"); + } + @TestMetadata("javaAnnotationArrayValueDefault.kt") public void testJavaAnnotationArrayValueDefault() throws Exception { runTest("compiler/testData/codegen/boxAgainstJava/annotations/javaAnnotationArrayValueDefault.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java index 05c9d98e7b0..2c3ab3c4539 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxAgainstJavaCodegenTestGenerated.java @@ -41,6 +41,11 @@ public class IrBlackBoxAgainstJavaCodegenTestGenerated extends AbstractIrBlackBo KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("divisionByZeroInJava.kt") + public void testDivisionByZeroInJava() throws Exception { + runTest("compiler/testData/codegen/boxAgainstJava/annotations/divisionByZeroInJava.kt"); + } + @TestMetadata("javaAnnotationArrayValueDefault.kt") public void testJavaAnnotationArrayValueDefault() throws Exception { runTest("compiler/testData/codegen/boxAgainstJava/annotations/javaAnnotationArrayValueDefault.kt"); diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt index 8b748ab8440..63a8827f02f 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassMemberScope.kt @@ -675,7 +675,7 @@ class LazyJavaClassMemberScope( method.name, // Parameters of annotation constructors in Java are never nullable TypeUtils.makeNotNullable(returnType), - method.annotationParameterDefaultValue != null, + method.hasAnnotationParameterDefaultValue, /* isCrossinline = */ false, /* isNoinline = */ false, // Nulls are not allowed in annotation arguments in Java diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt index 83beaeb474d..907cdb44995 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt @@ -105,7 +105,12 @@ interface JavaMethod : JavaMember, JavaTypeParameterListOwner { val valueParameters: List val returnType: JavaType + // WARNING: computing the default value may lead to an exception in the compiler because of IDEA-207252. + // If you only need to check default value presence, use `hasAnnotationParameterDefaultValue` instead. val annotationParameterDefaultValue: JavaAnnotationArgument? + + val hasAnnotationParameterDefaultValue: Boolean + get() = annotationParameterDefaultValue != null } interface JavaField : JavaMember { diff --git a/idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotation.kt b/idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotation.kt new file mode 100644 index 00000000000..2b6c8253e03 --- /dev/null +++ b/idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotation.kt @@ -0,0 +1,8 @@ +package test + +import dependency.* + +@J +fun test() {} + +// REF: (dependency).J diff --git a/idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotationSrc/J.java b/idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotationSrc/J.java new file mode 100644 index 00000000000..e4b1897d4ba --- /dev/null +++ b/idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotationSrc/J.java @@ -0,0 +1,13 @@ +package dependency; + +public @interface J { + double minusInf() default Double.NEGATIVE_INFINITY; + double plusInf() default Double.POSITIVE_INFINITY; + double nan() default Double.NaN; + double divisionByZero() default 1.0 / 0.0; + + float minusInfFloat() default Float.NEGATIVE_INFINITY; + float plusInfFloat() default Float.POSITIVE_INFINITY; + float nanFloat() default Float.NaN; + float divisionByZeroFloat() default 1.0f / 0.0f; +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveWithLibTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveWithLibTestGenerated.java index d2f1e9f8732..853eea91507 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveWithLibTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveWithLibTestGenerated.java @@ -44,6 +44,11 @@ public class ReferenceResolveWithLibTestGenerated extends AbstractReferenceResol runTest("idea/testData/resolve/referenceWithLib/fakeOverride2.kt"); } + @TestMetadata("infinityAndNanInJavaAnnotation.kt") + public void testInfinityAndNanInJavaAnnotation() throws Exception { + runTest("idea/testData/resolve/referenceWithLib/infinityAndNanInJavaAnnotation.kt"); + } + @TestMetadata("innerClassFromLib.kt") public void testInnerClassFromLib() throws Exception { runTest("idea/testData/resolve/referenceWithLib/innerClassFromLib.kt");