From 7d0c093da7366442ef01a5afd982f75fa244bec0 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Thu, 15 Dec 2022 13:29:34 +0100 Subject: [PATCH] [SLC] generate static enum methods from symbols ^KT-55496 Fixed --- .../classes/KotlinClassInnerStuffCache.kt | 4 ++- .../annotations/symbolAnnotationsUtils.kt | 6 +++++ .../symbol/classes/SymbolLightClassBase.kt | 1 + .../SymbolLightClassForClassOrObject.kt | 27 ++++++++----------- .../symbol/methods/SymbolLightSimpleMethod.kt | 2 +- ...notatedParameterInEnumConstructor.fir.java | 12 +++++++++ .../lightClasses/DeprecatedEnumEntry.fir.java | 14 ++++++++++ .../asJava/lightClasses/EnumClass.fir.java | 14 ++++++++++ .../EnumClassWithEnumEntries.fir.java | 14 ++++++++++ .../EnumNameOverride.fir.java | 12 +++++++++ .../ultraLightClasses/inlineClasses.fir.java | 6 ----- 11 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.fir.java create mode 100644 compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.fir.java create mode 100644 compiler/testData/asJava/lightClasses/EnumClass.fir.java create mode 100644 compiler/testData/asJava/lightClasses/EnumClassWithEnumEntries.fir.java create mode 100644 compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.fir.java diff --git a/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt b/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt index 29d916d3bf2..a5a7f994006 100644 --- a/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt +++ b/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt @@ -31,6 +31,7 @@ class KotlinClassInnerStuffCache( private val myClass: KtExtensibleLightClass, private val dependencies: List, private val lazyCreator: LazyCreator, + private val generateEnumMethods: Boolean = true, ) { abstract class LazyCreator { abstract fun get(initializer: () -> T, dependencies: List): Lazy @@ -55,13 +56,14 @@ class KotlinClassInnerStuffCache( private val methodsCache = cache { val own = myClass.ownMethods var ext = collectAugments(myClass, PsiMethod::class.java) - if (myClass.isEnum) { + if (generateEnumMethods && myClass.isEnum) { ext = ArrayList(ext.size + 2).also { it += ext it.addIfNotNull(getValuesMethod()) it.addIfNotNull(getValueOfMethod()) } } + ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY) } diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/symbolAnnotationsUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/symbolAnnotationsUtils.kt index da46ca6101e..f39303abf83 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/symbolAnnotationsUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/symbolAnnotationsUtils.kt @@ -14,9 +14,11 @@ import org.jetbrains.kotlin.analysis.api.annotations.* import org.jetbrains.kotlin.analysis.api.annotations.KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue import org.jetbrains.kotlin.analysis.api.components.buildClassType import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotatedSymbol import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames.DEFAULT_VALUE_PARAMETER import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.light.classes.symbol.NullabilityType @@ -324,6 +326,10 @@ internal fun KtAnnotatedSymbol.computeThrowsList( containingClass: SymbolLightClassBase, strictUseSite: Boolean = true, ) { + if (containingClass.isEnum && this is KtFunctionSymbol && name == StandardNames.ENUM_VALUE_OF && isStatic) { + builder.addReference("java.lang.IllegalArgumentException") + } + val annoApp = findAnnotation(JVM_THROWS_ANNOTATION_FQ_NAME, annotationUseSiteTarget, strictUseSite) ?: return fun handleAnnotationValue(annotationValue: KtAnnotationValue) = when (annotationValue) { diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassBase.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassBase.kt index 08383355978..1044ecf4efa 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassBase.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassBase.kt @@ -52,6 +52,7 @@ abstract class SymbolLightClassBase protected constructor(val ktModule: KtModule myClass = this@SymbolLightClassBase, dependencies = listOf(manager.project.createProjectWideOutOfBlockModificationTracker()), lazyCreator = SymbolLightClassesLazyCreator(project), + generateEnumMethods = false, ) override fun getFields(): Array = myInnersCache.fields diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForClassOrObject.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForClassOrObject.kt index e976a7c4628..7978ca0cd49 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForClassOrObject.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForClassOrObject.kt @@ -20,8 +20,6 @@ import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_FOR_NON_ORIGIN_METHOD import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod -import org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUES -import org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUE_OF import org.jetbrains.kotlin.builtins.StandardNames.HASHCODE_NAME import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.light.classes.symbol.NullabilityType @@ -122,21 +120,18 @@ internal open class SymbolLightClassForClassOrObject : SymbolLightClassForNamedC val declaredMemberScope = classOrObjectSymbol.getDeclaredMemberScope() - val visibleDeclarations = declaredMemberScope.getCallableSymbols().applyIf(isEnum) { - filterNot { function -> - function is KtFunctionSymbol && (function.name == ENUM_VALUES || function.name == ENUM_VALUE_OF) + val visibleDeclarations = declaredMemberScope.getCallableSymbols() + .applyIf(isObject) { + filterNot { + it is KtKotlinPropertySymbol && it.isConst + } + }.applyIf(classOrObjectSymbol.isData) { + // Technically, synthetic members of `data` class, such as `componentN` or `copy`, are visible. + // They're just needed to be added later (to be in a backward-compatible order of members). + filterNot { function -> + function is KtFunctionSymbol && function.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED + } } - }.applyIf(isObject) { - filterNot { - it is KtKotlinPropertySymbol && it.isConst - } - }.applyIf(classOrObjectSymbol.isData) { - // Technically, synthetic members of `data` class, such as `componentN` or `copy`, are visible. - // They're just needed to be added later (to be in a backward-compatible order of members). - filterNot { function -> - function is KtFunctionSymbol && function.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED - } - } val suppressStatic = isCompanionObject createMethods(visibleDeclarations, result, suppressStatic = suppressStatic) diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/SymbolLightSimpleMethod.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/SymbolLightSimpleMethod.kt index 156de7ffaf9..85c498f3650 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/SymbolLightSimpleMethod.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/SymbolLightSimpleMethod.kt @@ -107,7 +107,7 @@ internal class SymbolLightSimpleMethod( val isStatic = if (suppressStatic) { false } else { - isTopLevel || withFunctionSymbol { it.hasJvmStaticAnnotation() } + isTopLevel || withFunctionSymbol { it.isStatic || it.hasJvmStaticAnnotation() } } mapOf(modifier to isStatic) diff --git a/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.fir.java b/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.fir.java new file mode 100644 index 00000000000..db6958a10c4 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.fir.java @@ -0,0 +1,12 @@ +public enum AnnotatedParameterInEnumConstructor /* test.AnnotatedParameterInEnumConstructor*/ { + A; + + @org.jetbrains.annotations.NotNull() + public static final test.AnnotatedParameterInEnumConstructor valueOf(java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String) + + @org.jetbrains.annotations.NotNull() + public static final test.AnnotatedParameterInEnumConstructor[] values();// values() + + private AnnotatedParameterInEnumConstructor(@test.Anno(x = "a") java.lang.String, @test.Anno(x = "b") java.lang.String);// .ctor(java.lang.String, java.lang.String) + +} diff --git a/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.fir.java b/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.fir.java new file mode 100644 index 00000000000..1e186425d9b --- /dev/null +++ b/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.fir.java @@ -0,0 +1,14 @@ +public enum E /* p.E*/ { + @kotlin.Deprecated(message = "a") Entry1, + Entry2, + @kotlin.Deprecated(message = "b") Entry3; + + @org.jetbrains.annotations.NotNull() + public static final p.E valueOf(java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String) + + @org.jetbrains.annotations.NotNull() + public static final p.E[] values();// values() + + private E();// .ctor() + +} diff --git a/compiler/testData/asJava/lightClasses/EnumClass.fir.java b/compiler/testData/asJava/lightClasses/EnumClass.fir.java new file mode 100644 index 00000000000..fc97a5d073f --- /dev/null +++ b/compiler/testData/asJava/lightClasses/EnumClass.fir.java @@ -0,0 +1,14 @@ +public enum MyEnumClass /* one.MyEnumClass*/ { + Entry; + + @org.jetbrains.annotations.NotNull() + public static final one.MyEnumClass valueOf(java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String) + + @org.jetbrains.annotations.NotNull() + public static final one.MyEnumClass[] values();// values() + + private MyEnumClass();// .ctor() + + public final int foo();// foo() + +} diff --git a/compiler/testData/asJava/lightClasses/EnumClassWithEnumEntries.fir.java b/compiler/testData/asJava/lightClasses/EnumClassWithEnumEntries.fir.java new file mode 100644 index 00000000000..4de4ef4f94b --- /dev/null +++ b/compiler/testData/asJava/lightClasses/EnumClassWithEnumEntries.fir.java @@ -0,0 +1,14 @@ +public enum MyEnumClass /* one.MyEnumClass*/ { + Entry; + + @org.jetbrains.annotations.NotNull() + public static final one.MyEnumClass valueOf(java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String) + + @org.jetbrains.annotations.NotNull() + public static final one.MyEnumClass[] values();// values() + + private MyEnumClass();// .ctor() + + public final int doo();// doo() + +} diff --git a/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.fir.java b/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.fir.java new file mode 100644 index 00000000000..be6800ced58 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.fir.java @@ -0,0 +1,12 @@ +public enum EnumNameOverride /* EnumNameOverride*/ implements Bar { + ; + + @org.jetbrains.annotations.NotNull() + public static final EnumNameOverride valueOf(java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String) + + @org.jetbrains.annotations.NotNull() + public static final EnumNameOverride[] values();// values() + + private EnumNameOverride();// .ctor() + +} diff --git a/compiler/testData/asJava/ultraLightClasses/inlineClasses.fir.java b/compiler/testData/asJava/ultraLightClasses/inlineClasses.fir.java index 132994763bf..f90bada22e9 100644 --- a/compiler/testData/asJava/ultraLightClasses/inlineClasses.fir.java +++ b/compiler/testData/asJava/ultraLightClasses/inlineClasses.fir.java @@ -8,12 +8,6 @@ public enum Foo /* Foo*/ { private final int x; - @org.jetbrains.annotations.NotNull() - public static Foo valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String) - - @org.jetbrains.annotations.NotNull() - public static Foo[] values();// values() - public final int getX();// getX() }