LC: rework modality of enum class
It is abstract if it has abstract member. It is final if it doesn't have enum entries that need subclass. Otherwise, it is open (i.e., no modifier) ^KT-57567 Fixed
This commit is contained in:
committed by
Ilya Kirillov
parent
7930885131
commit
7f1424737e
+4
-1
@@ -142,7 +142,10 @@ abstract class SymbolLightClassForNamedClassLike : SymbolLightClassForClassLike<
|
|||||||
GranularModifiersBox.computeVisibilityForClass(ktModule, classOrObjectSymbolPointer, isTopLevel)
|
GranularModifiersBox.computeVisibilityForClass(ktModule, classOrObjectSymbolPointer, isTopLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
in GranularModifiersBox.MODALITY_MODIFIERS -> GranularModifiersBox.computeSimpleModality(ktModule, classOrObjectSymbolPointer)
|
in GranularModifiersBox.MODALITY_MODIFIERS -> {
|
||||||
|
GranularModifiersBox.computeSimpleModality(ktModule, classOrObjectSymbolPointer)
|
||||||
|
}
|
||||||
|
|
||||||
PsiModifier.STATIC -> {
|
PsiModifier.STATIC -> {
|
||||||
val isStatic = !isTopLevel && !isInner
|
val isStatic = !isTopLevel && !isInner
|
||||||
mapOf(modifier to isStatic)
|
mapOf(modifier to isStatic)
|
||||||
|
|||||||
+8
-1
@@ -8,10 +8,13 @@ package org.jetbrains.kotlin.light.classes.symbol.modifierLists
|
|||||||
import com.intellij.psi.PsiModifier
|
import com.intellij.psi.PsiModifier
|
||||||
import kotlinx.collections.immutable.PersistentMap
|
import kotlinx.collections.immutable.PersistentMap
|
||||||
import kotlinx.collections.immutable.toPersistentHashMap
|
import kotlinx.collections.immutable.toPersistentHashMap
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
|
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
|
import org.jetbrains.kotlin.light.classes.symbol.*
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.computeSimpleModality
|
import org.jetbrains.kotlin.light.classes.symbol.computeSimpleModality
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.toPsiVisibilityForClass
|
import org.jetbrains.kotlin.light.classes.symbol.toPsiVisibilityForClass
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.toPsiVisibilityForMember
|
import org.jetbrains.kotlin.light.classes.symbol.toPsiVisibilityForMember
|
||||||
@@ -89,7 +92,11 @@ internal class GranularModifiersBox(
|
|||||||
declarationPointer: KtSymbolPointer<KtSymbolWithModality>,
|
declarationPointer: KtSymbolPointer<KtSymbolWithModality>,
|
||||||
): PersistentMap<String, Boolean> {
|
): PersistentMap<String, Boolean> {
|
||||||
val modality = declarationPointer.withSymbol(ktModule) {
|
val modality = declarationPointer.withSymbol(ktModule) {
|
||||||
it.computeSimpleModality()
|
if ((it as? KtClassOrObjectSymbol)?.classKind == KtClassKind.ENUM_CLASS) {
|
||||||
|
it.enumClassModality()
|
||||||
|
} else {
|
||||||
|
it.computeSimpleModality()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MODALITY_MODIFIERS_MAP.with(modality)
|
return MODALITY_MODIFIERS_MAP.with(modality)
|
||||||
|
|||||||
+19
-3
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
|||||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||||
import org.jetbrains.kotlin.analysis.api.components.DefaultTypeClassIds
|
import org.jetbrains.kotlin.analysis.api.components.DefaultTypeClassIds
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
|
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithTypeParameters
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithTypeParameters
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
|
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
|
||||||
@@ -78,6 +76,24 @@ internal fun KtSymbolWithModality.computeSimpleModality(): String? = when (modal
|
|||||||
Modality.OPEN -> null
|
Modality.OPEN -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
internal fun KtClassOrObjectSymbol.enumClassModality(): String? {
|
||||||
|
if (getMemberScope().getCallableSymbols().any { (it as? KtSymbolWithModality)?.modality == Modality.ABSTRACT }) {
|
||||||
|
return PsiModifier.ABSTRACT
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getDeclaredMemberScope().getCallableSymbols().none { it is KtEnumEntrySymbol && it.requiresSubClass() }) {
|
||||||
|
return PsiModifier.FINAL
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
context(KtAnalysisSession)
|
||||||
|
private fun KtEnumEntrySymbol.requiresSubClass(): Boolean {
|
||||||
|
return getDeclaredMemberScope().getAllSymbols().any { it !is KtConstructorSymbol }
|
||||||
|
}
|
||||||
|
|
||||||
internal fun KtSymbolWithVisibility.toPsiVisibilityForMember(): String = visibility.toPsiVisibilityForMember()
|
internal fun KtSymbolWithVisibility.toPsiVisibilityForMember(): String = visibility.toPsiVisibilityForMember()
|
||||||
|
|
||||||
internal fun KtSymbolWithVisibility.toPsiVisibilityForClass(isNested: Boolean): String = visibility.toPsiVisibilityForClass(isNested)
|
internal fun KtSymbolWithVisibility.toPsiVisibilityForClass(isNested: Boolean): String = visibility.toPsiVisibilityForClass(isNested)
|
||||||
|
|||||||
@@ -15,10 +15,14 @@ import org.jetbrains.kotlin.asJava.toLightClass
|
|||||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.config.JvmDefaultMode
|
import org.jetbrains.kotlin.config.JvmDefaultMode
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.psi.KtClassBody
|
import org.jetbrains.kotlin.psi.KtClassBody
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtConstructor
|
||||||
|
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
|
||||||
// light class for top level or (inner/nested of top level) source declarations
|
// light class for top level or (inner/nested of top level) source declarations
|
||||||
@@ -69,7 +73,7 @@ abstract class KtLightClassImpl(
|
|||||||
protected open fun computeIsFinal(): Boolean = when {
|
protected open fun computeIsFinal(): Boolean = when {
|
||||||
classOrObject.hasModifier(KtTokens.FINAL_KEYWORD) -> true
|
classOrObject.hasModifier(KtTokens.FINAL_KEYWORD) -> true
|
||||||
isAbstract() || isSealed() -> false
|
isAbstract() || isSealed() -> false
|
||||||
isEnum -> false
|
isEnum -> !hasEnumEntryWhichRequiresSubclass()
|
||||||
!classOrObject.hasModifier(KtTokens.OPEN_KEYWORD) -> {
|
!classOrObject.hasModifier(KtTokens.OPEN_KEYWORD) -> {
|
||||||
val descriptor = lazy { getDescriptor() }
|
val descriptor = lazy { getDescriptor() }
|
||||||
var modifier = PsiModifier.FINAL
|
var modifier = PsiModifier.FINAL
|
||||||
@@ -83,7 +87,21 @@ abstract class KtLightClassImpl(
|
|||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isAbstract(): Boolean = classOrObject.hasModifier(KtTokens.ABSTRACT_KEYWORD) || isInterface
|
private fun hasEnumEntryWhichRequiresSubclass(): Boolean {
|
||||||
|
return classOrObject.declarations.any { declaration ->
|
||||||
|
declaration is KtEnumEntry && declaration.declarations.any { it !is KtConstructor<*> }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isAbstract(): Boolean =
|
||||||
|
classOrObject.hasModifier(KtTokens.ABSTRACT_KEYWORD) || isInterface || (isEnum && hasAbstractMember())
|
||||||
|
|
||||||
|
private fun hasAbstractMember(): Boolean {
|
||||||
|
val descriptor = getDescriptor() ?: return false
|
||||||
|
return descriptor.unsubstitutedMemberScope.getContributedDescriptors().any {
|
||||||
|
(it as? MemberDescriptor)?.modality == Modality.ABSTRACT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isSealed(): Boolean = classOrObject.hasModifier(KtTokens.SEALED_KEYWORD)
|
private fun isSealed(): Boolean = classOrObject.hasModifier(KtTokens.SEALED_KEYWORD)
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ static final class PLUS /* IntArithmetics.PLUS*/ extends IntArithmetics {
|
|||||||
public int apply(int, int);// apply(int, int)
|
public int apply(int, int);// apply(int, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ProtocolState /* ProtocolState*/ {
|
public abstract enum ProtocolState /* ProtocolState*/ {
|
||||||
WAITING {
|
WAITING {
|
||||||
WAITING();// .ctor()
|
WAITING();// .ctor()
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public enum Direction /* Direction*/ {
|
|||||||
private Direction();// .ctor()
|
private Direction();// .ctor()
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum IntArithmetics /* IntArithmetics*/ implements java.util.function.BinaryOperator<java.lang.Integer>, java.util.function.IntBinaryOperator {
|
public abstract enum IntArithmetics /* IntArithmetics*/ implements java.util.function.BinaryOperator<java.lang.Integer>, java.util.function.IntBinaryOperator {
|
||||||
PLUS {
|
PLUS {
|
||||||
PLUS();// .ctor()
|
PLUS();// .ctor()
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ public static final class PLUS /* IntArithmetics.PLUS*/ extends IntArithmetics {
|
|||||||
public java.lang.Integer apply(int, int);// apply(int, int)
|
public java.lang.Integer apply(int, int);// apply(int, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ProtocolState /* ProtocolState*/ {
|
public abstract enum ProtocolState /* ProtocolState*/ {
|
||||||
WAITING {
|
WAITING {
|
||||||
WAITING();// .ctor()
|
WAITING();// .ctor()
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public abstract class KotlinLightClassStructureTest extends KotlinAsJavaTestBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testEnum() {
|
public void testEnum() {
|
||||||
checkModifiers("test.Enum", PUBLIC, ENUM);
|
checkModifiers("test.Enum", PUBLIC, FINAL, ENUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testTrait() {
|
public void testTrait() {
|
||||||
|
|||||||
Reference in New Issue
Block a user