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?,
|
||||
place: PsiElement
|
||||
): Boolean {
|
||||
if (isEnum) {
|
||||
if (!KotlinClassInnerStuffCache.processDeclarationsInEnum(processor, state, myInnersCache)) return false
|
||||
}
|
||||
return PsiClassImplUtil.processDeclarationsInClass(
|
||||
this, processor, state, null,
|
||||
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.PsiElement
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtExtensibleLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
@@ -13,4 +12,4 @@ abstract class KtLightClassForDecompiledDeclarationBase(
|
||||
override val clsDelegate: PsiClass,
|
||||
clsParent: PsiElement,
|
||||
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.impl.*
|
||||
import com.intellij.psi.impl.light.LightElement
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass
|
||||
import com.intellij.psi.javadoc.PsiDocComment
|
||||
import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.annotations.NonNls
|
||||
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.analysis.api.tokens.HackToForceAllowRunningAnalyzeOnEDT
|
||||
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 javax.swing.Icon
|
||||
|
||||
abstract class FirLightClassBase protected constructor(manager: PsiManager) : LightElement(manager, KotlinLanguage.INSTANCE), PsiClass,
|
||||
KtLightClass, PsiExtensibleClass {
|
||||
|
||||
abstract class FirLightClassBase protected constructor(
|
||||
manager: PsiManager
|
||||
) : LightElement(manager, KotlinLanguage.INSTANCE), PsiClass, KtExtensibleLightClass {
|
||||
override val clsDelegate: PsiClass
|
||||
get() = invalidAccess()
|
||||
|
||||
@@ -96,9 +94,6 @@ abstract class FirLightClassBase protected constructor(manager: PsiManager) : Li
|
||||
override fun processDeclarations(
|
||||
processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement
|
||||
): Boolean {
|
||||
|
||||
if (isEnum && !processDeclarationsInEnum(processor, state, myInnersCache)) return false
|
||||
|
||||
return PsiClassImplUtil.processDeclarationsInClass(
|
||||
this,
|
||||
processor,
|
||||
|
||||
+258
-116
@@ -6,20 +6,38 @@
|
||||
package org.jetbrains.kotlin.asJava.classes
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.PsiClassImplUtil
|
||||
import com.intellij.psi.impl.PsiImplUtil
|
||||
import com.intellij.psi.impl.light.LightMethod
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass
|
||||
import com.intellij.psi.scope.ElementClassHint
|
||||
import com.intellij.psi.scope.NameHint
|
||||
import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.intellij.psi.impl.PsiSuperMethodImplUtil
|
||||
import com.intellij.psi.impl.compiled.ClsClassImpl
|
||||
import com.intellij.psi.impl.compiled.InnerClassSourceStrategy
|
||||
import com.intellij.psi.impl.compiled.StubBuildingVisitor
|
||||
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.IncorrectOperationException
|
||||
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(
|
||||
private val myClass: PsiExtensibleClass,
|
||||
private val myClass: KtExtensibleLightClass,
|
||||
private val dependencies: List<Any>,
|
||||
private val lazyCreator: LazyCreator,
|
||||
) {
|
||||
@@ -27,182 +45,306 @@ class KotlinClassInnerStuffCache(
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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? {
|
||||
return if (checkBases) {
|
||||
PsiClassImplUtil.findFieldByName(myClass, name, true)
|
||||
} 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> {
|
||||
return if (checkBases) {
|
||||
PsiClassImplUtil.findMethodsByName(myClass, name, true)
|
||||
} 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? {
|
||||
return if (checkBases) {
|
||||
PsiClassImplUtil.findInnerByName(myClass, name, true)
|
||||
} 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() }
|
||||
|
||||
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()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getAllFields(): Array<PsiField> {
|
||||
val own = myClass.ownFields
|
||||
val ext = collectAugments(myClass, PsiField::class.java)
|
||||
return ArrayUtil.mergeCollections(own, ext, PsiField.ARRAY_FACTORY)
|
||||
private val valueOfMethodCache = cache { KotlinEnumSyntheticMethod(myClass, KotlinEnumSyntheticMethod.Kind.VALUE_OF) }
|
||||
|
||||
fun getValueOfMethod(): PsiMethod? {
|
||||
if (myClass.isEnum && !myClass.isAnonymous) {
|
||||
return valueOfMethodCache.value
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getAllMethods(): Array<PsiMethod> {
|
||||
val own = myClass.ownMethods
|
||||
val ext = collectAugments(myClass, PsiMethod::class.java)
|
||||
return ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY)
|
||||
private fun isClassNameSealed(): Boolean {
|
||||
return myClass.name == PsiKeyword.SEALED && PsiUtil.getLanguageLevel(myClass).toJavaVersion().feature >= 16
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
val own = myClass.ownInnerClasses
|
||||
val ext = collectAugments(myClass, PsiClass::class.java)
|
||||
return ArrayUtil.mergeCollections(own, ext, PsiClass.ARRAY_FACTORY)
|
||||
private val returnType = run {
|
||||
val enumType = JavaPsiFacade.getElementFactory(project).createType(enumClass)
|
||||
.annotate { arrayOf(makeNotNullAnnotation(enumClass)) }
|
||||
|
||||
when (kind) {
|
||||
Kind.VALUE_OF -> enumType
|
||||
Kind.VALUES -> enumType.createArrayType().annotate { arrayOf(makeNotNullAnnotation(enumClass)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFieldsMap(): Map<String, PsiField> {
|
||||
val fields = this.fields
|
||||
if (fields.isEmpty()) return emptyMap()
|
||||
private val parameterList = LightParameterListBuilder(manager, language).apply {
|
||||
if (kind == Kind.VALUE_OF) {
|
||||
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>()
|
||||
for (field in fields) {
|
||||
val name = field.name
|
||||
if (!cachedFields.containsKey(name)) {
|
||||
cachedFields[name] = field
|
||||
override fun getParent(): PsiElement = this@KotlinEnumSyntheticMethod
|
||||
override fun getContainingFile(): PsiFile = this@KotlinEnumSyntheticMethod.containingFile
|
||||
|
||||
override fun getText(): String = name
|
||||
override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
|
||||
}
|
||||
nameParameter.setModifierList(NotNullModifierList(manager))
|
||||
addParameter(nameParameter)
|
||||
}
|
||||
return cachedFields
|
||||
}
|
||||
|
||||
private fun getMethodsMap(): Map<String, Array<PsiMethod>> {
|
||||
val methods = this.methods
|
||||
if (methods.isEmpty()) return emptyMap()
|
||||
private val modifierList = object : LightModifierList(manager, language, PsiModifier.PUBLIC, PsiModifier.STATIC) {
|
||||
override fun getParent() = this@KotlinEnumSyntheticMethod
|
||||
|
||||
val collectedMethods = hashMapOf<String, MutableList<PsiMethod>>()
|
||||
for (method in methods) {
|
||||
var list: MutableList<PsiMethod>? = collectedMethods[method.name]
|
||||
if (list == null) {
|
||||
list = SmartList()
|
||||
collectedMethods[method.name] = list
|
||||
}
|
||||
list.add(method)
|
||||
}
|
||||
private val annotations = arrayOf(makeNotNullAnnotation(enumClass))
|
||||
|
||||
val cachedMethods = THashMap<String, Array<PsiMethod>>()
|
||||
for ((key, list) in collectedMethods) {
|
||||
cachedMethods[key] = list.toTypedArray()
|
||||
}
|
||||
return cachedMethods
|
||||
override fun findAnnotation(fqn: String): PsiAnnotation? = annotations.firstOrNull { it.hasQualifiedName(fqn) }
|
||||
override fun getAnnotations(): Array<PsiAnnotation> = copy(annotations)
|
||||
}
|
||||
|
||||
private fun getInnerClassesMap(): Map<String, PsiClass> {
|
||||
val classes = this.innerClasses
|
||||
if (classes.isEmpty()) return emptyMap()
|
||||
override fun getTextOffset(): Int = enumClass.textOffset
|
||||
override fun toString(): String = enumClass.toString()
|
||||
|
||||
val cachedInners = THashMap<String, PsiClass>()
|
||||
for (psiClass in classes) {
|
||||
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
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this === other || (other is KotlinEnumSyntheticMethod && enumClass == other.enumClass && kind == other.kind)
|
||||
}
|
||||
|
||||
private fun makeValuesMethod(): PsiMethod {
|
||||
return getSyntheticMethod("public static " + myClass.name + "[] values() { }")
|
||||
}
|
||||
override fun hashCode() = Objects.hash(enumClass, kind)
|
||||
|
||||
private fun makeValueOfMethod(): PsiMethod {
|
||||
return getSyntheticMethod("public static " + myClass.name + " valueOf(java.lang.String name) throws java.lang.IllegalArgumentException { }")
|
||||
}
|
||||
override fun isDeprecated(): Boolean = false
|
||||
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 {
|
||||
val factory = JavaPsiFacade.getElementFactory(myClass.project)
|
||||
val method = factory.createMethodFromText(text, myClass)
|
||||
return object : LightMethod(myClass.manager, method, myClass) {
|
||||
override fun getTextOffset(): Int {
|
||||
return myClass.textOffset
|
||||
override fun getThrowsList(): PsiReferenceList {
|
||||
return LightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST).apply {
|
||||
if (kind == Kind.VALUE_OF) {
|
||||
addReference("java.lang.IllegalArgumentException")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val VALUES_METHOD = "values"
|
||||
private const val VALUE_OF_METHOD = "valueOf"
|
||||
override fun getParent(): PsiElement = enumClass
|
||||
override fun getContainingClass(): KtExtensibleLightClass = enumClass
|
||||
override fun getContainingFile(): PsiFile = enumClass.containingFile
|
||||
|
||||
// Copy of PsiClassImplUtil.processDeclarationsInEnum for own cache class
|
||||
@JvmStatic
|
||||
fun processDeclarationsInEnum(
|
||||
processor: PsiScopeProcessor,
|
||||
state: ResolveState,
|
||||
innerStuffCache: KotlinClassInnerStuffCache
|
||||
): 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
|
||||
}
|
||||
}
|
||||
override fun getBody(): PsiCodeBlock? = null
|
||||
override fun isConstructor(): Boolean = false
|
||||
override fun isVarArgs(): Boolean = false
|
||||
override fun getSignature(substitutor: PsiSubstitutor): MethodSignature = MethodSignatureBackedByPsiMethod.create(this, substitutor)
|
||||
override fun getNameIdentifier(): PsiIdentifier = LightIdentifier(manager, name)
|
||||
override fun getName() = kind.methodName
|
||||
|
||||
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
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass
|
||||
import org.jetbrains.kotlin.asJava.KtLightClassMarker
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
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.impl.PsiClassImplUtil
|
||||
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.asJava.classes.KotlinClassInnerStuffCache.Companion.processDeclarationsInEnum
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
|
||||
abstract class KtLightClassBase protected constructor(manager: PsiManager)
|
||||
: AbstractLightClass(manager, KotlinLanguage.INSTANCE), KtLightClass, PsiExtensibleClass {
|
||||
abstract class KtLightClassBase protected constructor(
|
||||
manager: PsiManager
|
||||
) : AbstractLightClass(manager, KotlinLanguage.INSTANCE), KtExtensibleLightClass {
|
||||
protected open val myInnersCache = KotlinClassInnerStuffCache(
|
||||
myClass = this,
|
||||
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 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 {
|
||||
val origin = kotlinOrigin
|
||||
return if (origin == null) "" else origin.text
|
||||
|
||||
+6
@@ -1,6 +1,12 @@
|
||||
public enum AnnotatedParameterInEnumConstructor /* test.AnnotatedParameterInEnumConstructor*/ {
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -3,6 +3,12 @@ public enum E /* p.E*/ {
|
||||
Entry2,
|
||||
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()
|
||||
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
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()
|
||||
|
||||
}
|
||||
@@ -4,6 +4,12 @@ public enum Direction /* Direction*/ {
|
||||
WEST,
|
||||
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()
|
||||
|
||||
}
|
||||
@@ -15,6 +21,12 @@ public enum Color /* Color*/ {
|
||||
|
||||
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(java.lang.String);// .ctor(java.lang.String)
|
||||
@@ -42,6 +54,12 @@ public enum ProtocolState /* ProtocolState*/ {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
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()
|
||||
|
||||
}
|
||||
@@ -79,6 +97,12 @@ public enum IntArithmetics /* IntArithmetics*/ {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
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()
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,12 @@ public abstract enum ProtocolState /* ProtocolState*/ {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
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()
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@ public final class UInt /* UInt*/ {
|
||||
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()
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user