[SLC] generate static enum methods from symbols

^KT-55496 Fixed
This commit is contained in:
Dmitrii Gridin
2022-12-15 13:29:34 +01:00
committed by Space Team
parent c28e9d5253
commit 7d0c093da7
11 changed files with 88 additions and 24 deletions
@@ -31,6 +31,7 @@ class KotlinClassInnerStuffCache(
private val myClass: KtExtensibleLightClass,
private val dependencies: List<Any>,
private val lazyCreator: LazyCreator,
private val generateEnumMethods: Boolean = true,
) {
abstract class LazyCreator {
abstract fun <T : Any> get(initializer: () -> T, dependencies: List<Any>): Lazy<T>
@@ -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<PsiMethod>(ext.size + 2).also {
it += ext
it.addIfNotNull(getValuesMethod())
it.addIfNotNull(getValueOfMethod())
}
}
ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY)
}
@@ -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) {
@@ -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<PsiField> = myInnersCache.fields
@@ -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)
@@ -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)
@@ -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)
}
@@ -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()
}
@@ -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()
}
@@ -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()
}
@@ -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()
}
@@ -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()
}