diff --git a/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclaration.kt b/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclaration.kt index 2d3e3645756..9abfd0fface 100644 --- a/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclaration.kt +++ b/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclaration.kt @@ -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 diff --git a/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclarationBase.kt b/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclarationBase.kt index cbfb5732de0..63d29b9f657 100644 --- a/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclarationBase.kt +++ b/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/KtLightClassForDecompiledDeclarationBase.kt @@ -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 \ No newline at end of file +) : KtLightElementBase(clsParent), PsiClass, KtExtensibleLightClass \ No newline at end of file diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassBase.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassBase.kt index a525eee8cb3..7912a84a027 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassBase.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/FirLightClassBase.kt @@ -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, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt index cc534c77946..dabb59fac62 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KotlinClassInnerStuffCache.kt @@ -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, private val lazyCreator: LazyCreator, ) { @@ -27,182 +45,306 @@ class KotlinClassInnerStuffCache( abstract fun get(initializer: () -> T, dependencies: List): Lazy } - private fun get(initializer: () -> T): Lazy = lazyCreator.get(initializer, dependencies) + private fun cache(initializer: () -> T): Lazy = lazyCreator.get(initializer, dependencies) - private val _getConstructors: Array by get { PsiImplUtil.getConstructors(myClass) } + private val constructorsCache = cache { PsiImplUtil.getConstructors(myClass) } val constructors: Array - get() = _getConstructors + get() = copy(constructorsCache.value) - private val _getFields: Array 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 - get() = _getFields + get() = copy(fieldsCache.value) - private val _getMethods: Array by get { this.getAllMethods() } + private val methodsCache = cache { + val own = myClass.ownMethods + var ext = collectAugments(myClass, PsiMethod::class.java) + if (myClass.isEnum) { + ext = ArrayList(ext.size + 2).also { + it += ext + it.addIfNotNull(getValuesMethod()) + it.addIfNotNull(getValueOfMethod()) + } + } + ArrayUtil.mergeCollections(own, ext, PsiMethod.ARRAY_FACTORY) + } val methods: Array - get() = _getMethods + get() = copy(methodsCache.value) - private val _getAllInnerClasses: Array 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 - get() = _getAllInnerClasses + get() = copy(innerClassesCache.value) - private val _getFieldsMap: Map by get { this.getFieldsMap() } + private val recordComponentsCache = cache { + val header = myClass.recordHeader + header?.recordComponents ?: PsiRecordComponent.EMPTY_ARRAY + } + + val recordComponents: Array + get() = copy(recordComponentsCache.value) + + private val fieldByNameCache = cache { + val fields = this.fields.takeIf { it.isNotEmpty() } ?: return@cache emptyMap() + Collections.unmodifiableMap(THashMap(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> by get { this.getMethodsMap() } + private val methodByNameCache = cache { + val methods = this.methods.takeIf { it.isNotEmpty() } ?: return@cache emptyMap() + Collections.unmodifiableMap(THashMap>().apply { + for ((key, list) in methods.groupByTo(HashMap()) { it.name }) { + put(key, list.toTypedArray()) + } + }) + } fun findMethodsByName(name: String, checkBases: Boolean): Array { 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 by get { this.getInnerClassesMap() } + private val innerClassByNameCache = cache { + val classes = this.innerClasses.takeIf { it.isNotEmpty() } ?: return@cache emptyMap() + + Collections.unmodifiableMap(THashMap().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 copy(value: Array): Array { - return if (value.isEmpty()) value else value.clone() + return null } - private fun getAllFields(): Array { - 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 { - 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 { - 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 { - 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() - 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> { - 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>() - for (method in methods) { - var list: MutableList? = collectedMethods[method.name] - if (list == null) { - list = SmartList() - collectedMethods[method.name] = list - } - list.add(method) - } + private val annotations = arrayOf(makeNotNullAnnotation(enumClass)) - val cachedMethods = THashMap>() - 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 = copy(annotations) } - private fun getInnerClassesMap(): Map { - val classes = this.innerClasses - if (classes.isEmpty()) return emptyMap() + override fun getTextOffset(): Int = enumClass.textOffset + override fun toString(): String = enumClass.toString() - val cachedInners = THashMap() - 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 = PsiSuperMethodImplUtil.findSuperMethods(this) + override fun findSuperMethods(checkAccess: Boolean): Array = PsiSuperMethodImplUtil.findSuperMethods(this, checkAccess) + override fun findSuperMethods(parentClass: PsiClass): Array = PsiSuperMethodImplUtil.findSuperMethods(this, parentClass) + + override fun findSuperMethodSignaturesIncludingStatic(checkAccess: Boolean): List { + return PsiSuperMethodImplUtil.findSuperMethodSignaturesIncludingStatic(this, checkAccess) + } + + @Suppress("OVERRIDE_DEPRECATION") + override fun findDeepestSuperMethod(): PsiMethod? = PsiSuperMethodImplUtil.findDeepestSuperMethod(this) + + override fun findDeepestSuperMethods(): Array = 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.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 { + override fun findInnerClass(innerName: String, outerClass: PsiClass): PsiClass? = null + override fun accept(innerClass: PsiClass, visitor: StubBuildingVisitor) {} + } + + 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 copy(value: Array): Array { + return if (value.isEmpty()) value else value.clone() } \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClass.kt index 5594fbd06b2..9e9e0c4efc2 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClass.kt @@ -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, KtLightClassMarker + +interface KtExtensibleLightClass : KtLightClass, PsiExtensibleClass \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassBase.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassBase.kt index e79ec8b167f..a30457fecdb 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassBase.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassBase.kt @@ -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 = 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 diff --git a/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.java b/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.java index 38682f8f4a7..fa04b508453 100644 --- a/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.java +++ b/compiler/testData/asJava/lightClasses/AnnotatedParameterInEnumConstructor.java @@ -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) } \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.java b/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.java index 70d38298344..75a7fd99266 100644 --- a/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.java +++ b/compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.java @@ -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() } \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.java b/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.java index bc55d50cd3f..d0d6cd2975f 100644 --- a/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.java +++ b/compiler/testData/asJava/lightClasses/compilationErrors/EnumNameOverride.java @@ -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() } \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/enums.fir.java b/compiler/testData/asJava/ultraLightClasses/enums.fir.java index f4cd5c7836c..e75d33682a4 100644 --- a/compiler/testData/asJava/ultraLightClasses/enums.fir.java +++ b/compiler/testData/asJava/ultraLightClasses/enums.fir.java @@ -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() } diff --git a/compiler/testData/asJava/ultraLightClasses/enums.lib.java b/compiler/testData/asJava/ultraLightClasses/enums.lib.java index 9f1cc754dfc..1e0ea49be3d 100644 --- a/compiler/testData/asJava/ultraLightClasses/enums.lib.java +++ b/compiler/testData/asJava/ultraLightClasses/enums.lib.java @@ -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() diff --git a/compiler/testData/asJava/ultraLightClasses/inlineClasses.java b/compiler/testData/asJava/ultraLightClasses/inlineClasses.java index b0260f362bf..7f081d245f2 100644 --- a/compiler/testData/asJava/ultraLightClasses/inlineClasses.java +++ b/compiler/testData/asJava/ultraLightClasses/inlineClasses.java @@ -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() }