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:
-3
@@ -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
|
||||||
|
|||||||
+2
-3
@@ -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
|
||||||
+3
-8
@@ -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,
|
||||||
|
|||||||
+258
-116
@@ -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
|
||||||
|
|||||||
+6
@@ -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()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user