Update KotlinClassInnerStuffCache implementation

'KotlinClassInnerStuffCache' was copy-pasted from the platform's
'ClassInnerStuffCache' several years ago. After J2K and other changes,
it became quite dirty.

Besides cleaning things up, enum synthetic method handling have
significantly improved. Before, such methods were handled only in
'processDeclarationsInEnum', and 'getMethods()' didn't return them.
This led to inconsistent behavior and was reason for providing special
ad-hoc support in '1b6ded600518176b21cc308ed3e032ef8d04cc90'.
This commit is contained in:
Yan Zhulanow
2022-03-03 19:13:02 +09:00
parent 955d0841bd
commit fa4dadf9b7
12 changed files with 323 additions and 145 deletions
@@ -95,9 +95,6 @@ open class KtLightClassForDecompiledDeclaration(
lastParent: PsiElement?, lastParent: PsiElement?,
place: PsiElement place: PsiElement
): Boolean { ): Boolean {
if (isEnum) {
if (!KotlinClassInnerStuffCache.processDeclarationsInEnum(processor, state, myInnersCache)) return false
}
return PsiClassImplUtil.processDeclarationsInClass( return PsiClassImplUtil.processDeclarationsInClass(
this, processor, state, null, this, processor, state, null,
lastParent, place, PsiUtil.getLanguageLevel(place), false lastParent, place, PsiUtil.getLanguageLevel(place), false
@@ -4,8 +4,7 @@ package org.jetbrains.kotlin.analysis.decompiled.light.classes
import com.intellij.psi.PsiClass import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.PsiExtensibleClass import org.jetbrains.kotlin.asJava.classes.KtExtensibleLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -13,4 +12,4 @@ abstract class KtLightClassForDecompiledDeclarationBase(
override val clsDelegate: PsiClass, override val clsDelegate: PsiClass,
clsParent: PsiElement, clsParent: PsiElement,
final override val kotlinOrigin: KtClassOrObject? final override val kotlinOrigin: KtClassOrObject?
) : KtLightElementBase(clsParent), PsiClass, KtLightClass, PsiExtensibleClass ) : KtLightElementBase(clsParent), PsiClass, KtExtensibleLightClass
@@ -24,14 +24,12 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.impl.* import com.intellij.psi.impl.*
import com.intellij.psi.impl.light.LightElement import com.intellij.psi.impl.light.LightElement
import com.intellij.psi.impl.source.PsiExtensibleClass
import com.intellij.psi.javadoc.PsiDocComment import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.scope.PsiScopeProcessor import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.PsiUtil
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
import org.jetbrains.kotlin.asJava.classes.KotlinClassInnerStuffCache.Companion.processDeclarationsInEnum
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.analysis.api.tokens.HackToForceAllowRunningAnalyzeOnEDT import org.jetbrains.kotlin.analysis.api.tokens.HackToForceAllowRunningAnalyzeOnEDT
import org.jetbrains.kotlin.analysis.api.tokens.hackyAllowRunningOnEdt import org.jetbrains.kotlin.analysis.api.tokens.hackyAllowRunningOnEdt
@@ -39,9 +37,9 @@ import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.light.classes.symbol.classes.checkIsInheritor import org.jetbrains.kotlin.light.classes.symbol.classes.checkIsInheritor
import javax.swing.Icon import javax.swing.Icon
abstract class FirLightClassBase protected constructor(manager: PsiManager) : LightElement(manager, KotlinLanguage.INSTANCE), PsiClass, abstract class FirLightClassBase protected constructor(
KtLightClass, PsiExtensibleClass { manager: PsiManager
) : LightElement(manager, KotlinLanguage.INSTANCE), PsiClass, KtExtensibleLightClass {
override val clsDelegate: PsiClass override val clsDelegate: PsiClass
get() = invalidAccess() get() = invalidAccess()
@@ -96,9 +94,6 @@ abstract class FirLightClassBase protected constructor(manager: PsiManager) : Li
override fun processDeclarations( override fun processDeclarations(
processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement
): Boolean { ): Boolean {
if (isEnum && !processDeclarationsInEnum(processor, state, myInnersCache)) return false
return PsiClassImplUtil.processDeclarationsInClass( return PsiClassImplUtil.processDeclarationsInClass(
this, this,
processor, processor,
@@ -6,20 +6,38 @@
package org.jetbrains.kotlin.asJava.classes package org.jetbrains.kotlin.asJava.classes
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.TextRange
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.impl.PsiClassImplUtil import com.intellij.psi.impl.PsiClassImplUtil
import com.intellij.psi.impl.PsiImplUtil import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.light.LightMethod import com.intellij.psi.impl.PsiSuperMethodImplUtil
import com.intellij.psi.impl.source.PsiExtensibleClass import com.intellij.psi.impl.compiled.ClsClassImpl
import com.intellij.psi.scope.ElementClassHint import com.intellij.psi.impl.compiled.InnerClassSourceStrategy
import com.intellij.psi.scope.NameHint import com.intellij.psi.impl.compiled.StubBuildingVisitor
import com.intellij.psi.scope.PsiScopeProcessor import com.intellij.psi.impl.java.stubs.PsiClassStub
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
import com.intellij.psi.impl.light.*
import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.util.*
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import com.intellij.util.IncorrectOperationException
import gnu.trove.THashMap import gnu.trove.THashMap
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.annotations.NotNull
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightParameter
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.org.objectweb.asm.Opcodes
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
class KotlinClassInnerStuffCache( class KotlinClassInnerStuffCache(
private val myClass: PsiExtensibleClass, private val myClass: KtExtensibleLightClass,
private val dependencies: List<Any>, private val dependencies: List<Any>,
private val lazyCreator: LazyCreator, private val lazyCreator: LazyCreator,
) { ) {
@@ -27,182 +45,306 @@ class KotlinClassInnerStuffCache(
abstract fun <T : Any> get(initializer: () -> T, dependencies: List<Any>): Lazy<T> abstract fun <T : Any> get(initializer: () -> T, dependencies: List<Any>): Lazy<T>
} }
private fun <T : Any> get(initializer: () -> T): Lazy<T> = lazyCreator.get(initializer, dependencies) private fun <T : Any> cache(initializer: () -> T): Lazy<T> = lazyCreator.get(initializer, dependencies)
private val _getConstructors: Array<PsiMethod> by get { PsiImplUtil.getConstructors(myClass) } private val constructorsCache = cache { PsiImplUtil.getConstructors(myClass) }
val constructors: Array<PsiMethod> val constructors: Array<PsiMethod>
get() = _getConstructors get() = copy(constructorsCache.value)
private val _getFields: Array<PsiField> by get { this.getAllFields() } private val fieldsCache = cache {
val own = myClass.ownFields
val ext = collectAugments(myClass, PsiField::class.java)
ArrayUtil.mergeCollections(own, ext, PsiField.ARRAY_FACTORY)
}
val fields: Array<PsiField> val fields: Array<PsiField>
get() = _getFields get() = copy(fieldsCache.value)
private val _getMethods: Array<PsiMethod> by get { this.getAllMethods() } private val methodsCache = cache {
val own = myClass.ownMethods
var ext = collectAugments(myClass, PsiMethod::class.java)
if (myClass.isEnum) {
ext = ArrayList<PsiMethod>(ext.size + 2).also {
it += ext
it.addIfNotNull(getValuesMethod())
it.addIfNotNull(getValueOfMethod())
}
}
ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY)
}
val methods: Array<PsiMethod> val methods: Array<PsiMethod>
get() = _getMethods get() = copy(methodsCache.value)
private val _getAllInnerClasses: Array<PsiClass> by get { this.getAllInnerClasses() } private val innerClassesCache = cache {
val own = myClass.ownInnerClasses
val ext = collectAugments(myClass, PsiClass::class.java)
ArrayUtil.mergeCollections(own, ext, PsiClass.ARRAY_FACTORY)
}
val innerClasses: Array<out PsiClass> val innerClasses: Array<out PsiClass>
get() = _getAllInnerClasses get() = copy(innerClassesCache.value)
private val _getFieldsMap: Map<String, PsiField> by get { this.getFieldsMap() } private val recordComponentsCache = cache {
val header = myClass.recordHeader
header?.recordComponents ?: PsiRecordComponent.EMPTY_ARRAY
}
val recordComponents: Array<PsiRecordComponent>
get() = copy(recordComponentsCache.value)
private val fieldByNameCache = cache {
val fields = this.fields.takeIf { it.isNotEmpty() } ?: return@cache emptyMap()
Collections.unmodifiableMap(THashMap<String, PsiField>(fields.size).apply {
for (field in fields) {
putIfAbsent(field.name, field)
}
})
}
fun findFieldByName(name: String, checkBases: Boolean): PsiField? { fun findFieldByName(name: String, checkBases: Boolean): PsiField? {
return if (checkBases) { return if (checkBases) {
PsiClassImplUtil.findFieldByName(myClass, name, true) PsiClassImplUtil.findFieldByName(myClass, name, true)
} else { } else {
_getFieldsMap[name] fieldByNameCache.value[name]
} }
} }
private val _getMethodsMap: Map<String, Array<PsiMethod>> by get { this.getMethodsMap() } private val methodByNameCache = cache {
val methods = this.methods.takeIf { it.isNotEmpty() } ?: return@cache emptyMap()
Collections.unmodifiableMap(THashMap<String, Array<PsiMethod>>().apply {
for ((key, list) in methods.groupByTo(HashMap()) { it.name }) {
put(key, list.toTypedArray())
}
})
}
fun findMethodsByName(name: String, checkBases: Boolean): Array<PsiMethod> { fun findMethodsByName(name: String, checkBases: Boolean): Array<PsiMethod> {
return if (checkBases) { return if (checkBases) {
PsiClassImplUtil.findMethodsByName(myClass, name, true) PsiClassImplUtil.findMethodsByName(myClass, name, true)
} else { } else {
copy(_getMethodsMap[name] ?: PsiMethod.EMPTY_ARRAY) copy(methodByNameCache.value[name] ?: PsiMethod.EMPTY_ARRAY)
} }
} }
private val _getInnerClassesMap: Map<String, PsiClass> by get { this.getInnerClassesMap() } private val innerClassByNameCache = cache {
val classes = this.innerClasses.takeIf { it.isNotEmpty() } ?: return@cache emptyMap()
Collections.unmodifiableMap(THashMap<String, PsiClass>().apply {
for (psiClass in classes) {
val name = psiClass.name
if (name == null) {
Logger.getInstance(KotlinClassInnerStuffCache::class.java).error(psiClass)
} else if (psiClass !is ExternallyDefinedPsiElement || !containsKey(name)) {
put(name, psiClass)
}
}
})
}
fun findInnerClassByName(name: String, checkBases: Boolean): PsiClass? { fun findInnerClassByName(name: String, checkBases: Boolean): PsiClass? {
return if (checkBases) { return if (checkBases) {
PsiClassImplUtil.findInnerByName(myClass, name, true) PsiClassImplUtil.findInnerByName(myClass, name, true)
} else { } else {
_getInnerClassesMap[name] innerClassByNameCache.value[name]
} }
} }
private val _makeValuesMethod: PsiMethod by get { this.makeValuesMethod() } private val valuesMethodCache = cache { KotlinEnumSyntheticMethod(myClass, KotlinEnumSyntheticMethod.Kind.VALUES) }
fun getValuesMethod(): PsiMethod? = if (myClass.isEnum && myClass.name != null) _makeValuesMethod else null private fun getValuesMethod(): PsiMethod? {
if (myClass.isEnum && !myClass.isAnonymous && !isClassNameSealed()) {
return valuesMethodCache.value
}
private val _makeValueOfMethod: PsiMethod by get { this.makeValueOfMethod() } return null
fun getValueOfMethod(): PsiMethod? = if (myClass.isEnum && myClass.name != null) _makeValueOfMethod else null
private fun <T> copy(value: Array<T>): Array<T> {
return if (value.isEmpty()) value else value.clone()
} }
private fun getAllFields(): Array<PsiField> { private val valueOfMethodCache = cache { KotlinEnumSyntheticMethod(myClass, KotlinEnumSyntheticMethod.Kind.VALUE_OF) }
val own = myClass.ownFields
val ext = collectAugments(myClass, PsiField::class.java) fun getValueOfMethod(): PsiMethod? {
return ArrayUtil.mergeCollections(own, ext, PsiField.ARRAY_FACTORY) if (myClass.isEnum && !myClass.isAnonymous) {
return valueOfMethodCache.value
}
return null
} }
private fun getAllMethods(): Array<PsiMethod> { private fun isClassNameSealed(): Boolean {
val own = myClass.ownMethods return myClass.name == PsiKeyword.SEALED && PsiUtil.getLanguageLevel(myClass).toJavaVersion().feature >= 16
val ext = collectAugments(myClass, PsiMethod::class.java) }
return ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY) }
private class KotlinEnumSyntheticMethod(
private val enumClass: KtExtensibleLightClass,
private val kind: Kind
) : LightElement(enumClass.manager, enumClass.language), KtLightMethod, SyntheticElement {
enum class Kind(val methodName: String) {
VALUE_OF("valueOf"), VALUES("values")
} }
private fun getAllInnerClasses(): Array<PsiClass> { private val returnType = run {
val own = myClass.ownInnerClasses val enumType = JavaPsiFacade.getElementFactory(project).createType(enumClass)
val ext = collectAugments(myClass, PsiClass::class.java) .annotate { arrayOf(makeNotNullAnnotation(enumClass)) }
return ArrayUtil.mergeCollections(own, ext, PsiClass.ARRAY_FACTORY)
when (kind) {
Kind.VALUE_OF -> enumType
Kind.VALUES -> enumType.createArrayType().annotate { arrayOf(makeNotNullAnnotation(enumClass)) }
}
} }
private fun getFieldsMap(): Map<String, PsiField> { private val parameterList = LightParameterListBuilder(manager, language).apply {
val fields = this.fields if (kind == Kind.VALUE_OF) {
if (fields.isEmpty()) return emptyMap() val stringType = PsiType.getJavaLangString(manager, GlobalSearchScope.allScope(project))
val nameParameter = object : LightParameter("name", stringType, this, language, false), KtLightParameter {
override val method: KtLightMethod get() = this@KotlinEnumSyntheticMethod
override val kotlinOrigin: KtParameter? get() = null
override val clsDelegate: PsiParameter get() = this@KotlinEnumSyntheticMethod.clsDelegate.parameterList.parameters.single()
val cachedFields = THashMap<String, PsiField>() override fun getParent(): PsiElement = this@KotlinEnumSyntheticMethod
for (field in fields) { override fun getContainingFile(): PsiFile = this@KotlinEnumSyntheticMethod.containingFile
val name = field.name
if (!cachedFields.containsKey(name)) { override fun getText(): String = name
cachedFields[name] = field override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
} }
nameParameter.setModifierList(NotNullModifierList(manager))
addParameter(nameParameter)
} }
return cachedFields
} }
private fun getMethodsMap(): Map<String, Array<PsiMethod>> { private val modifierList = object : LightModifierList(manager, language, PsiModifier.PUBLIC, PsiModifier.STATIC) {
val methods = this.methods override fun getParent() = this@KotlinEnumSyntheticMethod
if (methods.isEmpty()) return emptyMap()
val collectedMethods = hashMapOf<String, MutableList<PsiMethod>>() private val annotations = arrayOf(makeNotNullAnnotation(enumClass))
for (method in methods) {
var list: MutableList<PsiMethod>? = collectedMethods[method.name]
if (list == null) {
list = SmartList()
collectedMethods[method.name] = list
}
list.add(method)
}
val cachedMethods = THashMap<String, Array<PsiMethod>>() override fun findAnnotation(fqn: String): PsiAnnotation? = annotations.firstOrNull { it.hasQualifiedName(fqn) }
for ((key, list) in collectedMethods) { override fun getAnnotations(): Array<PsiAnnotation> = copy(annotations)
cachedMethods[key] = list.toTypedArray()
}
return cachedMethods
} }
private fun getInnerClassesMap(): Map<String, PsiClass> { override fun getTextOffset(): Int = enumClass.textOffset
val classes = this.innerClasses override fun toString(): String = enumClass.toString()
if (classes.isEmpty()) return emptyMap()
val cachedInners = THashMap<String, PsiClass>() override fun equals(other: Any?): Boolean {
for (psiClass in classes) { return this === other || (other is KotlinEnumSyntheticMethod && enumClass == other.enumClass && kind == other.kind)
val name = psiClass.name
if (name == null) {
Logger.getInstance(KotlinClassInnerStuffCache::class.java).error(psiClass)
} else if (psiClass !is ExternallyDefinedPsiElement || !cachedInners.containsKey(name)) {
cachedInners[name] = psiClass
}
}
return cachedInners
} }
private fun makeValuesMethod(): PsiMethod { override fun hashCode() = Objects.hash(enumClass, kind)
return getSyntheticMethod("public static " + myClass.name + "[] values() { }")
}
private fun makeValueOfMethod(): PsiMethod { override fun isDeprecated(): Boolean = false
return getSyntheticMethod("public static " + myClass.name + " valueOf(java.lang.String name) throws java.lang.IllegalArgumentException { }") override fun getDocComment(): PsiDocComment? = null
} override fun getReturnType(): PsiType = returnType
override fun getReturnTypeElement(): PsiTypeElement? = null
override fun getParameterList(): PsiParameterList = parameterList
private fun getSyntheticMethod(text: String): PsiMethod { override fun getThrowsList(): PsiReferenceList {
val factory = JavaPsiFacade.getElementFactory(myClass.project) return LightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST).apply {
val method = factory.createMethodFromText(text, myClass) if (kind == Kind.VALUE_OF) {
return object : LightMethod(myClass.manager, method, myClass) { addReference("java.lang.IllegalArgumentException")
override fun getTextOffset(): Int {
return myClass.textOffset
} }
} }
} }
companion object { override fun getParent(): PsiElement = enumClass
private const val VALUES_METHOD = "values" override fun getContainingClass(): KtExtensibleLightClass = enumClass
private const val VALUE_OF_METHOD = "valueOf" override fun getContainingFile(): PsiFile = enumClass.containingFile
// Copy of PsiClassImplUtil.processDeclarationsInEnum for own cache class override fun getBody(): PsiCodeBlock? = null
@JvmStatic override fun isConstructor(): Boolean = false
fun processDeclarationsInEnum( override fun isVarArgs(): Boolean = false
processor: PsiScopeProcessor, override fun getSignature(substitutor: PsiSubstitutor): MethodSignature = MethodSignatureBackedByPsiMethod.create(this, substitutor)
state: ResolveState, override fun getNameIdentifier(): PsiIdentifier = LightIdentifier(manager, name)
innerStuffCache: KotlinClassInnerStuffCache override fun getName() = kind.methodName
): Boolean {
val classHint = processor.getHint(ElementClassHint.KEY)
if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) {
val nameHint = processor.getHint(NameHint.KEY)
if (nameHint == null || VALUES_METHOD == nameHint.getName(state)) {
val method = innerStuffCache.getValuesMethod()
if (method != null && !processor.execute(method, ResolveState.initial())) return false
}
if (nameHint == null || VALUE_OF_METHOD == nameHint.getName(state)) {
val method = innerStuffCache.getValueOfMethod()
if (method != null && !processor.execute(method, ResolveState.initial())) return false
}
}
return true override fun findSuperMethods(): Array<PsiMethod> = PsiSuperMethodImplUtil.findSuperMethods(this)
override fun findSuperMethods(checkAccess: Boolean): Array<PsiMethod> = PsiSuperMethodImplUtil.findSuperMethods(this, checkAccess)
override fun findSuperMethods(parentClass: PsiClass): Array<PsiMethod> = PsiSuperMethodImplUtil.findSuperMethods(this, parentClass)
override fun findSuperMethodSignaturesIncludingStatic(checkAccess: Boolean): List<MethodSignatureBackedByPsiMethod> {
return PsiSuperMethodImplUtil.findSuperMethodSignaturesIncludingStatic(this, checkAccess)
}
@Suppress("OVERRIDE_DEPRECATION")
override fun findDeepestSuperMethod(): PsiMethod? = PsiSuperMethodImplUtil.findDeepestSuperMethod(this)
override fun findDeepestSuperMethods(): Array<PsiMethod> = PsiMethod.EMPTY_ARRAY
override fun getModifierList(): PsiModifierList = modifierList
override fun hasModifierProperty(name: String) = name == PsiModifier.PUBLIC || name == PsiModifier.STATIC
override fun setName(name: String): PsiElement = throw IncorrectOperationException()
override fun getHierarchicalMethodSignature() = PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this)
override fun getDefaultValue(): PsiAnnotationMemberValue? = null
override fun hasTypeParameters(): Boolean = false
override fun getTypeParameterList(): PsiTypeParameterList? = null
override fun getTypeParameters(): Array<PsiTypeParameter> = PsiTypeParameter.EMPTY_ARRAY
override val isMangled: Boolean get() = false
override val lightMemberOrigin: LightMemberOrigin? get() = null
override val kotlinOrigin: KtDeclaration? get() = null
override fun getText(): String = ""
override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
// As you can see, the implementation is quite dumb, yet it is still better than throwing an exception,
// as 'clsDelegate' is used for verifying light class consistency.
// See 'org.jetbrains.kotlin.idea.caches.resolve.LightClassLazinessChecker.LazinessInfo#checkConsistency' for more information.
override val clsDelegate: PsiMethod by lazy {
val emptyStrategy = object : InnerClassSourceStrategy<PsiClass> {
override fun findInnerClass(innerName: String, outerClass: PsiClass): PsiClass? = null
override fun accept(innerClass: PsiClass, visitor: StubBuildingVisitor<PsiClass>) {}
}
val containingFile = enumClass.containingFile as PsiJavaFile
var parent = PsiJavaFileStubImpl(containingFile, containingFile.packageName, null, true) as StubElement<*>
fun process(clazz: PsiClass): PsiClassStub<*> {
clazz.containingClass?.let { process(it) }
val access = getAccess(clazz)
val superName = clazz.superClass?.let { ClassUtil.getJVMClassName(it) } ?: "java/lang/Object"
val interfaceNames = clazz.interfaces.mapNotNull { ClassUtil.getJVMClassName(it) }.toTypedArray()
val stub = StubBuildingVisitor(clazz, emptyStrategy, parent, access, clazz.name).apply {
visit(Opcodes.V1_8, access, ClassUtil.getJVMClassName(clazz), null, superName, interfaceNames)
visitEnd()
}.result
parent = stub
return stub
}
ClsClassImpl(process(enumClass)).methods.single { it.name == name }
}
private companion object {
private fun getAccess(clazz: PsiClass): Int {
var result = 0
if (clazz.hasModifierProperty(PsiModifier.PUBLIC)) result = result or Opcodes.ACC_PUBLIC
if (clazz.hasModifierProperty(PsiModifier.PROTECTED)) result = result or Opcodes.ACC_PROTECTED
if (clazz.hasModifierProperty(PsiModifier.PRIVATE)) result = result or Opcodes.ACC_PRIVATE
if (clazz.hasModifierProperty(PsiModifier.FINAL)) result = result or Opcodes.ACC_FINAL
if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) result = result or Opcodes.ACC_ABSTRACT
if (clazz.isDeprecated) result = result or Opcodes.ACC_DEPRECATED
if (clazz.isEnum) result = result or Opcodes.ACC_ENUM
if (clazz.isAnnotationType) result = result or Opcodes.ACC_ANNOTATION
if (clazz.isInterface) result = result or Opcodes.ACC_INTERFACE
return result
}
private fun makeNotNullAnnotation(context: PsiClass): PsiAnnotation {
return PsiElementFactory.getInstance(context.project).createAnnotationFromText("@" + NotNull::class.java.name, context)
} }
} }
}
private val PsiClass.isAnonymous: Boolean
get() = name == null || this is PsiAnonymousClass
private class NotNullModifierList(manager: PsiManager) : LightModifierList(manager) {
private val annotation = PsiElementFactory.getInstance(project).createAnnotationFromText("@" + NotNull::class.java.name, context)
override fun getAnnotations() = arrayOf(annotation)
}
private fun <T> copy(value: Array<T>): Array<T> {
return if (value.isEmpty()) value else value.clone()
} }
@@ -17,8 +17,11 @@
package org.jetbrains.kotlin.asJava.classes package org.jetbrains.kotlin.asJava.classes
import com.intellij.psi.PsiClass import com.intellij.psi.PsiClass
import com.intellij.psi.impl.source.PsiExtensibleClass
import org.jetbrains.kotlin.asJava.KtLightClassMarker import org.jetbrains.kotlin.asJava.KtLightClassMarker
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
interface KtLightClass : PsiClass, KtLightDeclaration<KtClassOrObject, PsiClass>, KtLightClassMarker interface KtLightClass : PsiClass, KtLightDeclaration<KtClassOrObject, PsiClass>, KtLightClassMarker
interface KtExtensibleLightClass : KtLightClass, PsiExtensibleClass
@@ -20,16 +20,14 @@ import com.intellij.navigation.ItemPresentationProviders
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.impl.PsiClassImplUtil import com.intellij.psi.impl.PsiClassImplUtil
import com.intellij.psi.impl.light.AbstractLightClass import com.intellij.psi.impl.light.AbstractLightClass
import com.intellij.psi.impl.source.PsiExtensibleClass
import com.intellij.psi.scope.PsiScopeProcessor
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.asJava.classes.KotlinClassInnerStuffCache.Companion.processDeclarationsInEnum
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
abstract class KtLightClassBase protected constructor(manager: PsiManager) abstract class KtLightClassBase protected constructor(
: AbstractLightClass(manager, KotlinLanguage.INSTANCE), KtLightClass, PsiExtensibleClass { manager: PsiManager
) : AbstractLightClass(manager, KotlinLanguage.INSTANCE), KtExtensibleLightClass {
protected open val myInnersCache = KotlinClassInnerStuffCache( protected open val myInnersCache = KotlinClassInnerStuffCache(
myClass = this, myClass = this,
dependencies = listOf(KotlinModificationTrackerService.getInstance(manager.project).outOfBlockModificationTracker), dependencies = listOf(KotlinModificationTrackerService.getInstance(manager.project).outOfBlockModificationTracker),
@@ -62,16 +60,6 @@ abstract class KtLightClassBase protected constructor(manager: PsiManager)
override fun getOwnMethods(): List<PsiMethod> = KtLightMethodImpl.fromClsMethods(delegate, this) override fun getOwnMethods(): List<PsiMethod> = KtLightMethodImpl.fromClsMethods(delegate, this)
override fun processDeclarations(
processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement
): Boolean {
if (isEnum) {
if (!processDeclarationsInEnum(processor, state, myInnersCache)) return false
}
return super.processDeclarations(processor, state, lastParent, place)
}
override fun getText(): String { override fun getText(): String {
val origin = kotlinOrigin val origin = kotlinOrigin
return if (origin == null) "" else origin.text return if (origin == null) "" else origin.text
@@ -1,6 +1,12 @@
public enum AnnotatedParameterInEnumConstructor /* test.AnnotatedParameterInEnumConstructor*/ { public enum AnnotatedParameterInEnumConstructor /* test.AnnotatedParameterInEnumConstructor*/ {
A; A;
@org.jetbrains.annotations.NotNull()
public static test.AnnotatedParameterInEnumConstructor valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static 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) private AnnotatedParameterInEnumConstructor(@test.Anno(x = "a") java.lang.String, @test.Anno(x = "b") java.lang.String);// .ctor(java.lang.String, java.lang.String)
} }
@@ -3,6 +3,12 @@ public enum E /* p.E*/ {
Entry2, Entry2,
Entry3; Entry3;
@org.jetbrains.annotations.NotNull()
public static p.E valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static p.E[] values();// values()
private E();// .ctor() private E();// .ctor()
} }
@@ -1,6 +1,12 @@
public enum EnumNameOverride /* EnumNameOverride*/ implements Bar { public enum EnumNameOverride /* EnumNameOverride*/ implements Bar {
; ;
@org.jetbrains.annotations.NotNull()
public static EnumNameOverride valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static EnumNameOverride[] values();// values()
private EnumNameOverride();// .ctor() private EnumNameOverride();// .ctor()
} }
@@ -4,6 +4,12 @@ public enum Direction /* Direction*/ {
WEST, WEST,
EAST; EAST;
@org.jetbrains.annotations.NotNull()
public static Direction valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static Direction[] values();// values()
private Direction();// .ctor() private Direction();// .ctor()
} }
@@ -15,6 +21,12 @@ public enum Color /* Color*/ {
private final int rgb; private final int rgb;
@org.jetbrains.annotations.NotNull()
public static Color valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static Color[] values();// values()
private Color(int);// .ctor(int) private Color(int);// .ctor(int)
private Color(java.lang.String);// .ctor(java.lang.String) private Color(java.lang.String);// .ctor(java.lang.String)
@@ -42,6 +54,12 @@ public enum ProtocolState /* ProtocolState*/ {
@org.jetbrains.annotations.NotNull() @org.jetbrains.annotations.NotNull()
public abstract ProtocolState signal();// signal() public abstract ProtocolState signal();// signal()
@org.jetbrains.annotations.NotNull()
public static ProtocolState valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static ProtocolState[] values();// values()
private ProtocolState();// .ctor() private ProtocolState();// .ctor()
} }
@@ -79,6 +97,12 @@ public enum IntArithmetics /* IntArithmetics*/ {
@org.jetbrains.annotations.NotNull() @org.jetbrains.annotations.NotNull()
public IntArithmetics applyAsInt(int, int);// applyAsInt(int, int) public IntArithmetics applyAsInt(int, int);// applyAsInt(int, int)
@org.jetbrains.annotations.NotNull()
public static IntArithmetics valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static IntArithmetics[] values();// values()
private IntArithmetics();// .ctor() private IntArithmetics();// .ctor()
} }
@@ -5,6 +5,12 @@ public abstract enum ProtocolState /* ProtocolState*/ {
@org.jetbrains.annotations.NotNull() @org.jetbrains.annotations.NotNull()
public abstract ProtocolState signal();// signal() public abstract ProtocolState signal();// signal()
@org.jetbrains.annotations.NotNull()
public static ProtocolState valueOf(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.lang.IllegalArgumentException;// valueOf(java.lang.String)
@org.jetbrains.annotations.NotNull()
public static ProtocolState[] values();// values()
private ProtocolState();// .ctor() private ProtocolState();// .ctor()
@@ -4,6 +4,12 @@ public final class UInt /* UInt*/ {
public enum Foo /* Foo*/ { public enum Foo /* Foo*/ {
; ;
@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() public final int getX();// getX()
} }