diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt index f1b28a246e1..6c90bb22adb 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt @@ -103,6 +103,8 @@ abstract class KtAnalysisSession(override val token: ValidityToken) : ValidityTo fun KtProperty.getVariableSymbol(): KtVariableSymbol = symbolProvider.getVariableSymbol(this) + fun KtObjectLiteralExpression.getAnonymousObjectSymbol(): KtAnonymousObjectSymbol = symbolProvider.getAnonymousObjectSymbol(this) + fun KtClassOrObject.getClassOrObjectSymbol(): KtClassOrObjectSymbol = symbolProvider.getClassOrObjectSymbol(this) fun KtPropertyAccessor.getPropertyAccessorSymbol(): KtPropertyAccessorSymbol = symbolProvider.getPropertyAccessorSymbol(this) diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtAnonymousObjectSymbol.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtAnonymousObjectSymbol.kt new file mode 100644 index 00000000000..f2376418551 --- /dev/null +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtAnonymousObjectSymbol.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.frontend.api.symbols + +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithDeclarations +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithKind +import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtSymbolPointer +import org.jetbrains.kotlin.idea.frontend.api.types.KtType + +abstract class KtAnonymousObjectSymbol : KtSymbolWithKind, KtAnnotatedSymbol, KtSymbolWithDeclarations { + abstract val superTypes: List + + abstract override fun createPointer(): KtSymbolPointer +} \ No newline at end of file diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbolProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbolProvider.kt index 308f0ea0e87..cbb9955aeb7 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbolProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtSymbolProvider.kt @@ -21,7 +21,10 @@ abstract class KtSymbolProvider : KtAnalysisSessionComponent() { is KtEnumEntry -> getEnumEntrySymbol(psi) is KtLambdaExpression -> getAnonymousFunctionSymbol(psi) is KtProperty -> getVariableSymbol(psi) - is KtClassOrObject -> getClassOrObjectSymbol(psi) + is KtClassOrObject -> { + val literalExpression = (psi as? KtObjectDeclaration)?.parent as? KtObjectLiteralExpression + literalExpression?.let(::getAnonymousObjectSymbol) ?: getClassOrObjectSymbol(psi) + } is KtPropertyAccessor -> getPropertyAccessorSymbol(psi) else -> error("Cannot build symbol for ${psi::class}") } @@ -35,6 +38,7 @@ abstract class KtSymbolProvider : KtAnalysisSessionComponent() { abstract fun getAnonymousFunctionSymbol(psi: KtNamedFunction): KtAnonymousFunctionSymbol abstract fun getAnonymousFunctionSymbol(psi: KtLambdaExpression): KtAnonymousFunctionSymbol abstract fun getVariableSymbol(psi: KtProperty): KtVariableSymbol + abstract fun getAnonymousObjectSymbol(psi: KtObjectLiteralExpression): KtAnonymousObjectSymbol abstract fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol abstract fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt index 894ec2ed04d..e3bb6fed783 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/symbols/KtVariableLikeSymbol.kt @@ -59,6 +59,8 @@ abstract class KtPropertySymbol : KtVariableSymbol(), abstract val isOverride: Boolean + abstract val initializer: KtConstantValue? + abstract override fun createPointer(): KtSymbolPointer } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt index 0fe9d4fda11..6abf1c19627 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.psi +import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo @@ -106,7 +107,10 @@ internal class FirModuleResolveStateImpl( firLazyDeclarationResolver.lazyResolveDeclaration(container, cache, FirResolvePhase.BODY_RESOLVE, checkPCE = false /*TODO*/) } val firDeclaration = FirElementFinder.findElementIn(container) { firDeclaration -> - firDeclaration.psi == ktDeclaration + when (val realPsi = firDeclaration.realPsi) { + is KtObjectLiteralExpression -> realPsi.objectDeclaration == ktDeclaration + else -> realPsi == ktDeclaration + } } return firDeclaration ?: error("FirDeclaration was not found for\n${ktDeclaration.getElementTextInContext()}") diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt index 19e5d90a6f0..496a9dfa09f 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/FirLightAnnotationForAnnotationCall.kt @@ -7,10 +7,8 @@ package org.jetbrains.kotlin.idea.asJava import com.intellij.psi.* import com.intellij.psi.impl.PsiImplUtil -import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall -import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue import org.jetbrains.kotlin.psi.KtCallElement internal class FirLightAnnotationForAnnotationCall( @@ -46,36 +44,4 @@ internal class FirLightAnnotationForAnnotationCall( override fun isEquivalentTo(another: PsiElement?): Boolean = basicIsEquivalentTo(this, another as? PsiAnnotation) -} - -private fun escapeString(str: String): String = buildString { - str.forEach { char -> - val escaped = when (char) { - '\n' -> "\\n" - '\r' -> "\\r" - '\t' -> "\\t" - '\"' -> "\\\"" - '\\' -> "\\\\" - else -> "$char" - } - append(escaped) - } -} - -private fun KtSimpleConstantValue<*>.asStringForPsiLiteral(parent: PsiElement): String = - when (val value = this.constant) { - is String -> "\"${escapeString(value)}\"" - is Long -> "${value}L" - is Float -> "${value}f" - else -> value?.toString() ?: "null" - } - -internal fun KtSimpleConstantValue<*>.createPsiLiteral(parent: PsiElement): PsiExpression? { - val asString = asStringForPsiLiteral(parent) - val instance = PsiElementFactory.getInstance(parent.project) - return try { - instance.createExpressionFromText(asString, parent) - } catch (_: IncorrectOperationException) { - null - } -} +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt index 2a48a8ec550..a150a9ff1c2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/annotations/annotationsUtils.kt @@ -10,20 +10,14 @@ import com.intellij.psi.PsiElement import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget -import org.jetbrains.kotlin.fir.FirSymbolOwner import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirNamedReference -import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirAnnotationCall import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.utils.mapAnnotationParameters import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue -import org.jetbrains.kotlin.psi.KtAnnotationUseSiteTarget import org.jetbrains.kotlin.psi.KtFile internal fun KtAnnotatedSymbol.hasJvmSyntheticAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean = @@ -42,8 +36,6 @@ internal fun KtAnnotatedSymbol.getJvmNameFromAnnotation(annotationUseSiteTarget: } internal fun KtAnnotatedSymbol.isHiddenByDeprecation(annotationUseSiteTarget: AnnotationUseSiteTarget?): Boolean { - - //TODO Move it to HL API require(this is KtFirSymbol<*>) return this.firRef.withFir(FirResolvePhase.TYPES) { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt index 3e74e931ff1..9c21a75b77c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnnotationClassSymbol.kt @@ -31,16 +31,15 @@ internal class FirLightAnnotationClassSymbol( override fun isAnnotationType(): Boolean = true private val _ownFields: List by lazyPub { -//TODO mutableListOf().also { - it.addCompanionObjectFieldIfNeeded() + addCompanionObjectFieldIfNeeded(it) } } override fun getOwnFields(): List = _ownFields private val _ownMethods: List by lazyPub { -//TODO + val result = mutableListOf() analyzeWithSymbolAsContext(classOrObjectSymbol) { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnonymousClassForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnonymousClassForSymbol.kt new file mode 100644 index 00000000000..7144e063f74 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightAnonymousClassForSymbol.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.asJava.classes + +import com.intellij.psi.* +import com.intellij.psi.impl.InheritanceImplUtil +import com.intellij.psi.impl.PsiClassImplUtil +import com.intellij.psi.search.SearchScope +import com.intellij.psi.stubs.IStubElementType +import com.intellij.psi.stubs.StubElement +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.asJava.FirLightClassBase +import org.jetbrains.kotlin.idea.asJava.FirLightClassForSymbol +import org.jetbrains.kotlin.idea.asJava.FirLightField +import org.jetbrains.kotlin.idea.asJava.hasJvmFieldAnnotation +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtAnonymousObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.debugText.getDebugText +import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub + +internal class FirLightAnonymousClassForSymbol( + private val anonymousObjectSymbol: KtAnonymousObjectSymbol, + manager: PsiManager +) : FirLightClassBase(manager), + StubBasedPsiElement>, PsiAnonymousClass { + + private val _baseClassType: PsiClassType by lazyPub { + extendsListTypes.firstOrNull() + ?: implementsListTypes.firstOrNull() + ?: PsiType.getJavaLangObject(manager, resolveScope) + } + + override fun getBaseClassReference(): PsiJavaCodeReferenceElement = + JavaPsiFacade.getElementFactory(manager.project).createReferenceElementByType(baseClassType) + + override fun getBaseClassType(): PsiClassType = _baseClassType + + private val _extendsList by lazyPub { createInheritanceList(forExtendsList = true, anonymousObjectSymbol.superTypes) } + private val _implementsList by lazyPub { createInheritanceList(forExtendsList = false, anonymousObjectSymbol.superTypes) } + + override fun getExtendsList(): PsiReferenceList? = _extendsList + override fun getImplementsList(): PsiReferenceList? = _implementsList + + override fun getOwnFields(): List = _ownFields + override fun getOwnMethods(): List = _ownMethods + + + private val _ownMethods: List by lazyPub { + + val result = mutableListOf() + + analyzeWithSymbolAsContext(anonymousObjectSymbol) { + val callableSymbols = anonymousObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + createMethods(callableSymbols, isTopLevel = false, result) + } + + result + } + + private val _ownFields: List by lazyPub { + val result = mutableListOf() + val nameGenerator = FirLightField.FieldNameGenerator() + + analyzeWithSymbolAsContext(anonymousObjectSymbol) { + anonymousObjectSymbol.getDeclaredMemberScope().getCallableSymbols() + .filterIsInstance() + .forEach { propertySymbol -> + createField( + propertySymbol, + nameGenerator, + isTopLevel = false, + forceStatic = false, + takePropertyVisibility = propertySymbol.hasJvmFieldAnnotation(), + result + ) + } + } + + result + } + + private val _ownInnerClasses: List by lazyPub { + anonymousObjectSymbol.createInnerClasses(manager) + } + + override fun getOwnInnerClasses(): List = _ownInnerClasses + + override fun getScope(): PsiElement? = parent + override fun getInterfaces(): Array = PsiClassImplUtil.getInterfaces(this) + override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this) + override fun getSupers(): Array = PsiClassImplUtil.getSupers(this) + override fun getSuperTypes(): Array = PsiClassImplUtil.getSuperTypes(this) + override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean = + InheritanceImplUtil.isInheritor(this, baseClass, checkDeep) + + override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean = + baseClass?.let { InheritanceImplUtil.isInheritorDeep(this, it, classToByPass) } ?: false + + override val kotlinOrigin: KtClassOrObject? = anonymousObjectSymbol.psi as? KtClassOrObject + + override val originKind: LightClassOriginKind + get() = LightClassOriginKind.SOURCE + + override fun getArgumentList(): PsiExpressionList? = null + override fun isInQualifiedNew(): Boolean = false + override fun getName(): String? = null + override fun getNameIdentifier(): KtLightIdentifier? = null + override fun getModifierList(): PsiModifierList? = null + override fun hasModifierProperty(name: String): Boolean = name == PsiModifier.FINAL + override fun getContainingClass(): PsiClass? = null + override fun isDeprecated(): Boolean = false //TODO + override fun getTypeParameters(): Array = PsiTypeParameter.EMPTY_ARRAY + override fun isInterface() = false + override fun isAnnotationType() = false + override fun getTypeParameterList(): PsiTypeParameterList? = null + override fun getQualifiedName(): String? = null + override fun isEnum() = false + override fun getUseScope(): SearchScope = kotlinOrigin?.useScope ?: TODO() + override fun getElementType(): IStubElementType, *>? = kotlinOrigin?.elementType + override fun getStub(): KotlinClassOrObjectStub? = kotlinOrigin?.stub + + override fun isEquivalentTo(another: PsiElement?): Boolean = equals(another) //TODO + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightAnonymousClassForSymbol && anonymousObjectSymbol == other.anonymousObjectSymbol) + + override fun hashCode(): Int = anonymousObjectSymbol.hashCode() + + override fun copy() = + FirLightAnonymousClassForSymbol(anonymousObjectSymbol, manager) + + override fun toString() = + "${this::class.java.simpleName}:${kotlinOrigin?.getDebugText()}" +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt index dd0a31ffe6e..1bcd44dd548 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForClassOrObjectSymbol.kt @@ -13,18 +13,15 @@ import com.intellij.psi.search.SearchScope import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.stubs.StubElement import org.jetbrains.annotations.NonNls -import org.jetbrains.kotlin.asJava.classes.KotlinSuperTypeListBuilder import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier import org.jetbrains.kotlin.asJava.elements.KtLightField -import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.idea.asJava.classes.getOrCreateFirLightClass import org.jetbrains.kotlin.idea.asJava.elements.FirLightTypeParameterListForSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind -import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType -import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.idea.util.ifFalse import org.jetbrains.kotlin.idea.util.ifTrue import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind @@ -61,7 +58,6 @@ internal abstract class FirLightClassForClassOrObjectSymbol( abstract override fun getExtendsList(): PsiReferenceList? abstract override fun getImplementsList(): PsiReferenceList? - private val _typeParameterList: PsiTypeParameterList? by lazyPub { hasTypeParameters().ifTrue { val shiftCount = classOrObjectSymbol.isInner.ifTrue { @@ -90,45 +86,16 @@ internal abstract class FirLightClassForClassOrObjectSymbol( override fun isWritable() = false override val kotlinOrigin: KtClassOrObject? = classOrObjectSymbol.psi as? KtClassOrObject - protected fun createInheritanceList(forExtendsList: Boolean): PsiReferenceList { - - val role = if (forExtendsList) PsiReferenceList.Role.EXTENDS_LIST else PsiReferenceList.Role.IMPLEMENTS_LIST - - val listBuilder = KotlinSuperTypeListBuilder( - kotlinOrigin = kotlinOrigin?.getSuperTypeList(), - manager = manager, - language = language, - role = role - ) - - fun KtType.needToAddTypeIntoList(): Boolean { - if (this !is KtClassType) return false - - // Do not add redundant "extends java.lang.Object" anywhere - if (this.classId == StandardClassIds.Any) return false - - // We don't have Enum among enums supertype in sources neither we do for decompiled class-files and light-classes - if (isEnum && this.classId == StandardClassIds.Enum) return false - - val isInterfaceType = - (this.classSymbol as? KtClassOrObjectSymbol)?.classKind == KtClassKind.INTERFACE - - return forExtendsList == !isInterfaceType - } - - //TODO Add support for kotlin.collections. - classOrObjectSymbol.superTypes - .filterIsInstance() - .filter { it.needToAddTypeIntoList() } - .mapNotNull { it.mapSupertype(this, kotlinCollectionAsIs = true) } - .forEach { listBuilder.addReference(it) } - - return listBuilder - } - - protected fun MutableList.addCompanionObjectFieldIfNeeded() { + protected fun addCompanionObjectFieldIfNeeded(result: MutableList) { classOrObjectSymbol.companionObject?.run { - add(FirLightFieldForObjectSymbol(this, this@FirLightClassForClassOrObjectSymbol, null)) + result.add( + FirLightFieldForObjectSymbol( + objectSymbol = this, + containingClass = this@FirLightClassForClassOrObjectSymbol, + name = name.asString(), + lightMemberOrigin = null + ) + ) } } @@ -153,7 +120,7 @@ internal abstract class FirLightClassForClassOrObjectSymbol( abstract override fun hashCode(): Int - override fun getName(): String = classOrObjectSymbol.name.asString() + override fun getName(): String? = classOrObjectSymbol.name.asString() override fun hasModifierProperty(@NonNls name: String): Boolean = modifierList?.hasModifierProperty(name) ?: false diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt index 52ee3e692a2..47bb64d8140 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForFacade.kt @@ -21,10 +21,11 @@ import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.idea.KotlinLanguage -import org.jetbrains.kotlin.idea.asJava.classes.createFields +import org.jetbrains.kotlin.idea.asJava.classes.createField import org.jetbrains.kotlin.idea.asJava.classes.createMethods import org.jetbrains.kotlin.idea.frontend.api.analyze import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind import org.jetbrains.kotlin.name.FqName @@ -97,7 +98,7 @@ class FirLightClassForFacade( private fun loadFieldsFromFile( file: KtFile, - usedFieldNames: MutableSet, + nameGenerator: FirLightField.FieldNameGenerator, result: MutableList ) { val properties = file.declarations @@ -108,20 +109,31 @@ class FirLightClassForFacade( if (properties.isEmpty()) return - val symbols = analyze(file) { + val propertySymbols = analyze(file) { properties.mapNotNull { - it.getSymbol() as? KtCallableSymbol + it.getSymbol() as? KtPropertySymbol } } - createFields(symbols.asSequence(), usedFieldNames, isTopLevel = true, result) + for (propertySymbol in propertySymbols) { + val forceStaticAndPropertyVisibility = propertySymbol.hasJvmStaticAnnotation() + createField( + propertySymbol, + nameGenerator, + isTopLevel = true, + forceStatic = forceStaticAndPropertyVisibility, + takePropertyVisibility = forceStaticAndPropertyVisibility, + result + ) + } + } private val _ownFields: List by lazyPub { val result = mutableListOf() - val usedFieldNames = mutableSetOf() + val nameGenerator = FirLightField.FieldNameGenerator() for (file in files) { - loadFieldsFromFile(file, usedFieldNames, result) + loadFieldsFromFile(file, nameGenerator, result) } result } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt index 0a1db55e788..1388a8dcfee 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForSymbol.kt @@ -10,7 +10,9 @@ import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_FOR_DEFAULT_CTOR import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod -import org.jetbrains.kotlin.idea.asJava.classes.createFields +import org.jetbrains.kotlin.idea.asJava.classes.* +import org.jetbrains.kotlin.idea.asJava.classes.createInheritanceList +import org.jetbrains.kotlin.idea.asJava.classes.createInnerClasses import org.jetbrains.kotlin.idea.asJava.classes.createMethods import org.jetbrains.kotlin.idea.asJava.fields.FirLightFieldForEnumEntry import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext @@ -19,7 +21,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility -internal class FirLightClassForSymbol( +internal open class FirLightClassForSymbol( private val classOrObjectSymbol: KtClassOrObjectSymbol, manager: PsiManager ) : FirLightClassForClassOrObjectSymbol(classOrObjectSymbol, manager) { @@ -73,28 +75,14 @@ internal class FirLightClassForSymbol( override fun getExtendsList(): PsiReferenceList? = _extendsList override fun getImplementsList(): PsiReferenceList? = _implementsList - override fun getOwnInnerClasses(): List { - val result = ArrayList() - - // workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927 - // inner classes with null names can't be searched for and can't be used from java anyway - // we can't prohibit creating light classes with null names either since they can contain members - - analyzeWithSymbolAsContext(classOrObjectSymbol) { - classOrObjectSymbol.getDeclaredMemberScope().getAllSymbols().filterIsInstance().mapTo(result) { - FirLightClassForSymbol(it, manager) - } - } - - //TODO - //if (classOrObject.hasInterfaceDefaultImpls) { - // result.add(KtLightClassForInterfaceDefaultImpls(classOrObject)) - //} - return result + private val _ownInnerClasses: List by lazyPub { + classOrObjectSymbol.createInnerClasses(manager) } - private val _extendsList by lazyPub { createInheritanceList(forExtendsList = true) } - private val _implementsList by lazyPub { createInheritanceList(forExtendsList = false) } + override fun getOwnInnerClasses(): List = _ownInnerClasses + + private val _extendsList by lazyPub { createInheritanceList(forExtendsList = true, classOrObjectSymbol.superTypes) } + private val _implementsList by lazyPub { createInheritanceList(forExtendsList = false, classOrObjectSymbol.superTypes) } private val _ownMethods: List by lazyPub { @@ -106,6 +94,10 @@ internal class FirLightClassForSymbol( filterNot { function -> function is KtFunctionSymbol && function.name.asString().let { it == "values" || it == "valueOf" } } + }.applyIf(classOrObjectSymbol.classKind == KtClassKind.OBJECT) { + filterNot { + it is KtPropertySymbol && it.isConst + } } createMethods(visibleDeclarations, isTopLevel = false, result) @@ -127,14 +119,7 @@ internal class FirLightClassForSymbol( result } - private val _ownFields: List by lazyPub { - - val result = mutableListOf() - - result.addCompanionObjectFieldIfNeeded() - - val usedNames = mutableSetOf() - + private fun addFieldsFromCompanionIfNeeded(result: MutableList, nameGenerator: FirLightField.FieldNameGenerator) { classOrObjectSymbol.companionObject?.run { analyzeWithSymbolAsContext(this) { getDeclaredMemberScope().getCallableSymbols() @@ -143,36 +128,96 @@ internal class FirLightClassForSymbol( .mapTo(result) { FirLightFieldForPropertySymbol( propertySymbol = it, - usedNames = usedNames, + nameGenerator = nameGenerator, containingClass = this@FirLightClassForSymbol, lightMemberOrigin = null, isTopLevel = false, - forceStatic = true + forceStatic = true, + takePropertyVisibility = true ) } } } + } + + private fun addObjectFields(result: MutableList, nameGenerator: FirLightField.FieldNameGenerator) { + analyzeWithSymbolAsContext(classOrObjectSymbol) { + classOrObjectSymbol.getDeclaredMemberScope().getAllSymbols() + .filterIsInstance() + .filter { it.classKind == KtClassKind.OBJECT } + .mapTo(result) { + FirLightFieldForObjectSymbol( + objectSymbol = it, + containingClass = this@FirLightClassForSymbol, + name = nameGenerator.generateUniqueFieldName(it.name.asString()), + lightMemberOrigin = null + ) + } + } + } + + private fun addInstanceFieldIfNeeded(result: MutableList) { val isNamedObject = classOrObjectSymbol.classKind == KtClassKind.OBJECT if (isNamedObject && classOrObjectSymbol.symbolKind != KtSymbolKind.LOCAL) { - result.add(FirLightFieldForObjectSymbol(classOrObjectSymbol, this@FirLightClassForSymbol, null)) + result.add( + FirLightFieldForObjectSymbol( + objectSymbol = classOrObjectSymbol, + containingClass = this@FirLightClassForSymbol, + name = "INSTANCE", + lightMemberOrigin = null + ) + ) } + } + private fun addPropertyBackingFields(result: MutableList, nameGenerator: FirLightField.FieldNameGenerator) { analyzeWithSymbolAsContext(classOrObjectSymbol) { val propertySymbols = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() .filterIsInstance() .applyIf(classOrObjectSymbol.classKind == KtClassKind.COMPANION_OBJECT) { filterNot { it.hasJvmFieldAnnotation() || it.isConst } } - createFields(propertySymbols, usedNames, isTopLevel = false, result) + + val isObject = classOrObjectSymbol.classKind == KtClassKind.OBJECT + + for (propertySymbol in propertySymbols) { + val isJvmStatic = propertySymbol.hasJvmStaticAnnotation() + val forceStatic = isObject || isJvmStatic + val takePropertyVisibility = (isObject && propertySymbol.isConst) || isJvmStatic + + createField( + declaration = propertySymbol, + nameGenerator = nameGenerator, + isTopLevel = false, + forceStatic = forceStatic, + takePropertyVisibility = takePropertyVisibility, + result = result + ) + } + + if (isEnum) { classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols() .filterIsInstance() .mapTo(result) { FirLightFieldForEnumEntry(it, this@FirLightClassForSymbol, null) } } - } + } + + private val _ownFields: List by lazyPub { + + val result = mutableListOf() + + addCompanionObjectFieldIfNeeded(result) + addInstanceFieldIfNeeded(result) + + val nameGenerator = FirLightField.FieldNameGenerator() + + addObjectFields(result, nameGenerator) + addFieldsFromCompanionIfNeeded(result, nameGenerator) + addPropertyBackingFields(result, nameGenerator) result } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt index 44a14f165de..34797721b82 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceClassSymbol.kt @@ -29,7 +29,7 @@ internal class FirLightInterfaceClassSymbol( private val _ownFields: List by lazyPub { mutableListOf().also { - it.addCompanionObjectFieldIfNeeded() + addCompanionObjectFieldIfNeeded(it) } } @@ -62,7 +62,7 @@ internal class FirLightInterfaceClassSymbol( FirLightInterfaceClassSymbol(classOrObjectSymbol, manager) private val _extendsList: PsiReferenceList by lazyPub { - createInheritanceList(forExtendsList = false) + createInheritanceList(forExtendsList = false, classOrObjectSymbol.superTypes) } override fun getExtendsList(): PsiReferenceList? = _extendsList diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt index 77d9eafa9f1..400f73b6dc1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightInterfaceOrAnnotationClassSymbol.kt @@ -18,7 +18,11 @@ internal abstract class FirLightInterfaceOrAnnotationClassSymbol( ) : FirLightClassForClassOrObjectSymbol(classOrObjectSymbol, manager) { init { - require(classOrObjectSymbol.classKind == KtClassKind.INTERFACE || classOrObjectSymbol.classKind == KtClassKind.ANNOTATION_CLASS) + require( + classOrObjectSymbol.classKind == KtClassKind.OBJECT || + classOrObjectSymbol.classKind == KtClassKind.INTERFACE || + classOrObjectSymbol.classKind == KtClassKind.ANNOTATION_CLASS + ) } private val _modifierList: PsiModifierList? by lazyPub { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt index 532f9f595dc..5ce844cb4f8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt @@ -5,29 +5,33 @@ package org.jetbrains.kotlin.idea.asJava.classes +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiReferenceList import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.classes.KotlinSuperTypeListBuilder import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_BASE import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.idea.asJava.* import org.jetbrains.kotlin.idea.asJava.fields.FirLightFieldForEnumEntry import org.jetbrains.kotlin.idea.frontend.api.analyze +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtCommonSymbolModality import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithDeclarations +import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType +import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtCodeFragment -import org.jetbrains.kotlin.psi.KtEnumEntry -import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClass -import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral import java.util.* fun getOrCreateFirLightClass(classOrObject: KtClassOrObject): KtLightClass? = @@ -53,10 +57,17 @@ fun createFirLightClassNoCache(classOrObject: KtClassOrObject): KtLightClass? { return null } + val anonymousObject = classOrObject.parent as? KtObjectLiteralExpression + if (anonymousObject != null) { + return analyze(anonymousObject) { + FirLightAnonymousClassForSymbol(anonymousObject.getAnonymousObjectSymbol(), anonymousObject.manager) + } + } + return when { classOrObject is KtEnumEntry -> lightClassForEnumEntry(classOrObject) - classOrObject.isObjectLiteral() -> return null //TODO classOrObject.hasModifier(KtTokens.INLINE_KEYWORD) -> return null //TODO + else -> { analyze(classOrObject) { val symbol = classOrObject.getClassOrObjectSymbol() @@ -192,10 +203,12 @@ internal fun FirLightClassBase.createMethods( } } -internal fun FirLightClassBase.createFields( - declarations: Sequence, - usedNames: MutableSet, +internal fun FirLightClassBase.createField( + declaration: KtPropertySymbol, + nameGenerator: FirLightField.FieldNameGenerator, isTopLevel: Boolean, + forceStatic: Boolean, + takePropertyVisibility: Boolean, result: MutableList ) { fun hasBackingField(property: KtPropertySymbol): Boolean { @@ -207,18 +220,73 @@ internal fun FirLightClassBase.createFields( return property.hasBackingField } - for (declaration in declarations) { - if (declaration !is KtPropertySymbol) continue - if (!hasBackingField(declaration)) continue + if (!hasBackingField(declaration)) return - result.add( - FirLightFieldForPropertySymbol( - propertySymbol = declaration, - usedNames = usedNames, - containingClass = this@createFields, - lightMemberOrigin = null, - isTopLevel = isTopLevel - ) + result.add( + FirLightFieldForPropertySymbol( + propertySymbol = declaration, + nameGenerator = nameGenerator, + containingClass = this, + lightMemberOrigin = null, + isTopLevel = isTopLevel, + forceStatic = forceStatic, + takePropertyVisibility = takePropertyVisibility ) + ) +} + +internal fun FirLightClassBase.createInheritanceList(forExtendsList: Boolean, superTypes: List): PsiReferenceList { + + val role = if (forExtendsList) PsiReferenceList.Role.EXTENDS_LIST else PsiReferenceList.Role.IMPLEMENTS_LIST + + val listBuilder = KotlinSuperTypeListBuilder( + kotlinOrigin = kotlinOrigin?.getSuperTypeList(), + manager = manager, + language = language, + role = role + ) + + fun KtType.needToAddTypeIntoList(): Boolean { + if (this !is KtClassType) return false + + // Do not add redundant "extends java.lang.Object" anywhere + if (this.classId == StandardClassIds.Any) return false + + // We don't have Enum among enums supertype in sources neither we do for decompiled class-files and light-classes + if (isEnum && this.classId == StandardClassIds.Enum) return false + + val isInterfaceType = + (this.classSymbol as? KtClassOrObjectSymbol)?.classKind == KtClassKind.INTERFACE + + return forExtendsList == !isInterfaceType } + + //TODO Add support for kotlin.collections. + superTypes + .filterIsInstance() + .filter { it.needToAddTypeIntoList() } + .mapNotNull { it.mapSupertype(this, kotlinCollectionAsIs = true) } + .forEach { listBuilder.addReference(it) } + + return listBuilder +} + +internal fun KtSymbolWithDeclarations.createInnerClasses(manager: PsiManager): List { + val result = ArrayList() + + // workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927 + // inner classes with null names can't be searched for and can't be used from java anyway + // we can't prohibit creating light classes with null names either since they can contain members + + analyzeWithSymbolAsContext(this) { + getDeclaredMemberScope().getAllSymbols().filterIsInstance().mapTo(result) { + FirLightClassForSymbol(it, manager) + } + } + + //TODO + //if (classOrObject.hasInterfaceDefaultImpls) { + // result.add(KtLightClassForInterfaceDefaultImpls(classOrObject)) + //} + return result } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt index 8768cfcec55..bfd07121be4 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightField.kt @@ -80,4 +80,18 @@ internal abstract class FirLightField protected constructor( visitor.visitElement(this) } } + + internal class FieldNameGenerator { + private val usedNames: MutableSet = mutableSetOf() + + fun generateUniqueFieldName(base: String): String { + if (usedNames.add(base)) return base + var i = 1 + while (true) { + val suggestion = "$base$$i" + if (usedNames.add(suggestion)) return suggestion + i++ + } + } + } } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt index f62b988b103..b78a4ea4f63 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt @@ -18,13 +18,13 @@ import org.jetbrains.kotlin.psi.KtDeclaration internal class FirLightFieldForObjectSymbol( private val objectSymbol: KtClassOrObjectSymbol, containingClass: KtLightClass, + private val name: String, lightMemberOrigin: LightMemberOrigin?, ) : FirLightField(containingClass, lightMemberOrigin) { override val kotlinOrigin: KtDeclaration? = objectSymbol.psi as? KtDeclaration - private val _name = if (objectSymbol.classKind == KtClassKind.COMPANION_OBJECT) objectSymbol.name.asString() else "INSTANCE" - override fun getName(): String = _name + override fun getName(): String = name private val _modifierList: PsiModifierList by lazyPub { val modifiers = setOf(objectSymbol.computeVisibility(isTopLevel = false), PsiModifier.STATIC, PsiModifier.FINAL) @@ -58,8 +58,8 @@ internal class FirLightFieldForObjectSymbol( override fun equals(other: Any?): Boolean = this === other || (other is FirLightFieldForObjectSymbol && - kotlinOrigin == other.kotlinOrigin && - objectSymbol == other.objectSymbol) + kotlinOrigin == other.kotlinOrigin && + objectSymbol == other.objectSymbol) override fun hashCode(): Int = kotlinOrigin.hashCode() } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt index 7ff8c9546b7..d8f46e2827c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt @@ -12,18 +12,20 @@ import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue import org.jetbrains.kotlin.psi.KtDeclaration internal class FirLightFieldForPropertySymbol( private val propertySymbol: KtPropertySymbol, - usedNames: MutableSet, + nameGenerator: FieldNameGenerator, containingClass: FirLightClassBase, lightMemberOrigin: LightMemberOrigin?, isTopLevel: Boolean, - forceStatic: Boolean = false + forceStatic: Boolean, + takePropertyVisibility: Boolean ) : FirLightField(containingClass, lightMemberOrigin) { - private val _name: String = generateUniqueFieldName(usedNames, propertySymbol.name.asString()) + private val _name: String = nameGenerator.generateUniqueFieldName(propertySymbol.name.asString()) override val kotlinOrigin: KtDeclaration? = propertySymbol.psi as? KtDeclaration @@ -53,7 +55,6 @@ internal class FirLightFieldForPropertySymbol( private val _modifierList: PsiModifierList by lazyPub { - val isJvmField = propertySymbol.hasJvmFieldAnnotation() val suppressFinal = !propertySymbol.isVal val modifiersFromSymbol = propertySymbol.computeModalityForMethod( @@ -67,7 +68,7 @@ internal class FirLightFieldForPropertySymbol( ) val visibility = - if (isJvmField) propertySymbol.computeVisibility(isTopLevel = false) else PsiModifier.PRIVATE + if (takePropertyVisibility) propertySymbol.computeVisibility(isTopLevel = false) else PsiModifier.PRIVATE val modifiersWithVisibility = basicModifiers + visibility @@ -95,10 +96,13 @@ internal class FirLightFieldForPropertySymbol( FirLightClassModifierList(this, modifiers, annotations) } - override fun getModifierList(): PsiModifierList? = _modifierList + override fun getModifierList(): PsiModifierList = _modifierList + private val _initializer by lazyPub { + (propertySymbol.initializer as? KtSimpleConstantValue<*>)?.createPsiLiteral(this) + } - override fun getInitializer(): PsiExpression? = null //TODO + override fun getInitializer(): PsiExpression? = _initializer override fun equals(other: Any?): Boolean = this === other || @@ -107,16 +111,4 @@ internal class FirLightFieldForPropertySymbol( propertySymbol == other.propertySymbol) override fun hashCode(): Int = kotlinOrigin.hashCode() - - companion object { - private fun generateUniqueFieldName(usedNames: MutableSet, base: String): String { - if (usedNames.add(base)) return base - var i = 1 - while (true) { - val suggestion = "$base$$i" - if (usedNames.add(suggestion)) return suggestion - i++ - } - } - } } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt index f5288743966..c340d92bee8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt @@ -10,24 +10,24 @@ import com.intellij.psi.impl.cache.TypeInfo import com.intellij.psi.impl.compiled.ClsTypeElementImpl import com.intellij.psi.impl.compiled.SignatureParsing import com.intellij.psi.impl.compiled.StubBuildingVisitor -import org.jetbrains.annotations.NotNull +import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.asJava.elements.KtLightMember import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.isPrimitiveNumberOrUnsignedNumberType import org.jetbrains.kotlin.fir.isPrimitiveType +import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.symbols.StandardClassIds -import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState +import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirClassType @@ -37,10 +37,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.* import org.jetbrains.kotlin.idea.frontend.api.types.* import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.SpecialNames -import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.model.SimpleTypeMarker -import org.jetbrains.kotlin.types.model.typeConstructor -import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import java.text.StringCharacterIterator internal fun L.invalidAccess(): Nothing = @@ -60,9 +57,8 @@ internal fun KtType.asPsiType( ): PsiType { require(this is KtFirType) require(context is KtFirSymbol<*>) - val session = context.firRef.withFir(phase) { it.session } - return coneType.asPsiType(session, TypeMappingMode.DEFAULT, parent) + return coneType.asPsiType(session, context.firRef.resolveState, TypeMappingMode.DEFAULT, parent) } internal fun KtClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElement): PsiType { @@ -74,33 +70,53 @@ internal fun KtClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElement): P isNullable = false ) } - return type.asPsiType(session, TypeMappingMode.DEFAULT, psiElement) + return type.asPsiType(session, this.firRef.resolveState, TypeMappingMode.DEFAULT, psiElement) } +private class AnonymousTypesSubstitutor(private val session: FirSession, private val state: FirModuleResolveState) : + AbstractConeSubstitutor() { + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { + + if (type !is ConeClassLikeType) return null + + val isAnonymous = type.classId.let { it?.shortClassName?.asString() == SpecialNames.ANONYMOUS } + if (!isAnonymous) return null + + val firstSuperType = (type.lookupTag.toSymbol(session) as? FirClassSymbol)?.fir + ?.withFirDeclaration(state, FirResolvePhase.SUPER_TYPES) { + (it as? FirClass)?.superConeTypes?.firstOrNull() + } + + if (firstSuperType != null) return firstSuperType + + return if (type.nullability.isNullable) session.builtinTypes.nullableAnyType.type + else session.builtinTypes.anyType.type + } +} + + private fun ConeKotlinType.asPsiType( session: FirSession, + state: FirModuleResolveState, mode: TypeMappingMode, psiContext: PsiElement, ): PsiType { if (this is ConeClassErrorType || this !is SimpleTypeMarker) return psiContext.nonExistentType() if (this.typeArguments.any { it is ConeClassErrorType }) return psiContext.nonExistentType() - if (this is ConeClassLikeType) { - val classId = classId - //TODO make anonymous type deriving - if (classId != null && classId.shortClassName.asString() == SpecialNames.ANONYMOUS) return PsiType.NULL - } + + val correctedType = AnonymousTypesSubstitutor(session, state).substituteOrSelf(this) val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) //TODO Check thread safety - session.jvmTypeMapper.mapType(this, mode, signatureWriter) + session.jvmTypeMapper.mapType(correctedType, mode, signatureWriter) val canonicalSignature = signatureWriter.toString() if (canonicalSignature.contains("L")) return psiContext.nonExistentType() - //TODO Fix it in typemapper - val patchedCanonicalSignature = canonicalSignature.replace(SpecialNames.ANONYMOUS, "java.lang.Object") - val signature = StringCharacterIterator(patchedCanonicalSignature) + require(!canonicalSignature.contains(SpecialNames.ANONYMOUS)) + + val signature = StringCharacterIterator(canonicalSignature) val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER) val typeInfo = TypeInfo.fromString(javaType, false) val typeText = TypeInfo.createTypeText(typeInfo) ?: return psiContext.nonExistentType() @@ -109,9 +125,16 @@ private fun ConeKotlinType.asPsiType( return typeElement.type } -private fun mapSupertype(psiContext: PsiElement, session: FirSession, supertype: ConeKotlinType, kotlinCollectionAsIs: Boolean = false) = +private fun mapSupertype( + psiContext: PsiElement, + session: FirSession, + firResolvePhase: FirModuleResolveState, + supertype: ConeKotlinType, + kotlinCollectionAsIs: Boolean = false +) = supertype.asPsiType( session, + firResolvePhase, if (kotlinCollectionAsIs) TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS else TypeMappingMode.SUPER_TYPE, psiContext ) as? PsiClassType @@ -129,6 +152,7 @@ internal fun KtClassType.mapSupertype( return mapSupertype( psiContext, session, + contextSymbol.firRef.resolveState, this.coneType, kotlinCollectionAsIs, ) @@ -280,6 +304,39 @@ internal fun KtType.getTypeNullability(context: KtSymbol, phase: FirResolvePhase return if (isNotPrimitiveType) NullabilityType.NotNull else NullabilityType.Unknown } + +private fun escapeString(str: String): String = buildString { + str.forEach { char -> + val escaped = when (char) { + '\n' -> "\\n" + '\r' -> "\\r" + '\t' -> "\\t" + '\"' -> "\\\"" + '\\' -> "\\\\" + else -> "$char" + } + append(escaped) + } +} + +private fun KtSimpleConstantValue<*>.asStringForPsiLiteral(): String = + when (val value = this.constant) { + is String -> "\"${escapeString(value)}\"" + is Long -> "${value}L" + is Float -> "${value}f" + else -> value?.toString() ?: "null" + } + +internal fun KtSimpleConstantValue<*>.createPsiLiteral(parent: PsiElement): PsiExpression? { + val asString = asStringForPsiLiteral() + val instance = PsiElementFactory.getInstance(parent.project) + return try { + instance.createExpressionFromText(asString, parent) + } catch (_: IncorrectOperationException) { + null + } +} + internal fun Set.add(what: T, `if`: Boolean): Set = applyIf(`if`) { this + what } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt index 6fbe6fdbb4a..4c04d4ff8d5 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt @@ -87,6 +87,7 @@ internal class KtSymbolByFirBuilder private constructor( is FirField -> buildFieldSymbol(fir) is FirAnonymousFunction -> buildAnonymousFunctionSymbol(fir) is FirPropertyAccessor -> buildPropertyAccessorSymbol(fir) + is FirAnonymousObject -> buildAnonymousObjectSymbol(fir) else -> TODO(fir::class.toString()) } @@ -111,6 +112,9 @@ internal class KtSymbolByFirBuilder private constructor( fun buildClassSymbol(fir: FirRegularClass) = symbolsCache.cache(fir) { KtFirClassOrObjectSymbol(fir, resolveState, token, this) } + fun buildAnonymousObjectSymbol(fir: FirAnonymousObject) = + symbolsCache.cache(fir) { KtFirAnonymousObjectSymbol(fir, resolveState, token, this) } + // TODO it can be a constructor parameter, which may be split into parameter & property // we should handle them both fun buildParameterSymbol(fir: FirValueParameter) = @@ -127,7 +131,8 @@ internal class KtSymbolByFirBuilder private constructor( } fun buildConstructorSymbol(fir: FirConstructor) = symbolsCache.cache(fir) { KtFirConstructorSymbol(fir, resolveState, token, this) } - fun buildTypeParameterSymbol(fir: FirTypeParameter) = symbolsCache.cache(fir) { KtFirTypeParameterSymbol(fir, resolveState, token, this) } + fun buildTypeParameterSymbol(fir: FirTypeParameter) = + symbolsCache.cache(fir) { KtFirTypeParameterSymbol(fir, resolveState, token, this) } fun buildTypeAliasSymbol(fir: FirTypeAlias) = symbolsCache.cache(fir) { KtFirTypeAliasSymbol(fir, resolveState, token) } fun buildEnumEntrySymbol(fir: FirEnumEntry) = symbolsCache.cache(fir) { KtFirEnumEntrySymbol(fir, resolveState, token, this) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt index abbc9132299..6024798f860 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.frontend.api.components.KtScopeProvider import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder import org.jetbrains.kotlin.idea.frontend.api.fir.scopes.* +import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirAnonymousObjectSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirEnumEntrySymbol import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType @@ -59,6 +60,7 @@ internal class KtFirScopeProvider( private inline fun KtSymbolWithDeclarations.withFirForScope(crossinline body: (FirClass<*>) -> T): T? = when (this) { is KtFirClassOrObjectSymbol -> firRef.withFir(FirResolvePhase.SUPER_TYPES, body) + is KtFirAnonymousObjectSymbol -> firRef.withFir(FirResolvePhase.SUPER_TYPES, body) is KtFirEnumEntrySymbol -> firRef.withFir(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { val initializer = it.initializer check(initializer is FirAnonymousObject) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnonymousObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnonymousObjectSymbol.kt new file mode 100644 index 00000000000..f4de67d9eb3 --- /dev/null +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirAnonymousObjectSymbol.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.frontend.api.fir.symbols + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.superConeTypes +import org.jetbrains.kotlin.idea.fir.findPsi +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState +import org.jetbrains.kotlin.idea.frontend.api.ValidityToken +import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.convertAnnotation +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.firRef +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtAnonymousObjectSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind +import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException +import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtPsiBasedSymbolPointer +import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtSymbolPointer +import org.jetbrains.kotlin.idea.frontend.api.types.KtType + +internal class KtFirAnonymousObjectSymbol( + fir: FirAnonymousObject, + resolveState: FirModuleResolveState, + override val token: ValidityToken, + private val builder: KtSymbolByFirBuilder +) : KtAnonymousObjectSymbol(), KtFirSymbol { + + override val firRef = firRef(fir, resolveState) + override val symbolKind: KtSymbolKind = KtSymbolKind.LOCAL + override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.session) } + + override val annotations: List by firRef.withFirAndCache(FirResolvePhase.TYPES) { + convertAnnotation(it) + } + + override val superTypes: List by firRef.withFirAndCache(FirResolvePhase.SUPER_TYPES) { fir -> + fir.superConeTypes.map { + builder.buildKtType(it) + } + } + + override fun createPointer(): KtSymbolPointer = + KtPsiBasedSymbolPointer.createForSymbolFromSource(this) + ?: throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException("Cannot create pointer for KtFirAnonymousObjectSymbol") +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirPropertySymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirPropertySymbol.kt index 5e10089371b..ac2df6b9a41 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirPropertySymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirPropertySymbol.kt @@ -15,14 +15,12 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.pointers.KtFirMemberPropertySymbolPointer import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.pointers.createSignature import org.jetbrains.kotlin.idea.frontend.api.fir.utils.convertAnnotation +import org.jetbrains.kotlin.idea.frontend.api.fir.utils.convertConstantExpression import org.jetbrains.kotlin.idea.frontend.api.fir.utils.firRef import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertyGetterSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySetterSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol -import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotationCall -import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtCommonSymbolModality -import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind -import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.* import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtSymbolPointer @@ -48,7 +46,7 @@ internal class KtFirPropertySymbol( override val type: KtType by firRef.withFirAndCache(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { fir -> builder.buildKtType(fir.returnTypeRef) } override val receiverType: KtType? by firRef.withFirAndCache(FirResolvePhase.TYPES) { fir -> fir.receiverTypeRef?.let(builder::buildKtType) } override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null } - + override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir -> fir.initializer?.convertConstantExpression() } override val symbolKind: KtSymbolKind get() = firRef.withFir { fir -> when (fir.containingClass()?.classId) { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt index e368febdaf2..027dbc18cd9 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt @@ -87,7 +87,14 @@ internal class KtFirSymbolProvider( } } + override fun getAnonymousObjectSymbol(psi: KtObjectLiteralExpression): KtAnonymousObjectSymbol = withValidityAssertion { + psi.objectDeclaration.withFirDeclarationOfType(resolveState) { + firSymbolBuilder.buildAnonymousObjectSymbol(it) + } + } + override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol = withValidityAssertion { + check(psi !is KtObjectDeclaration || psi.parent !is KtObjectLiteralExpression) psi.withFirDeclarationOfType(resolveState) { firSymbolBuilder.buildClassSymbol(it) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt index b939bb0e58b..b8c7c98cdf6 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/firUtils.kt @@ -51,7 +51,7 @@ internal fun mapAnnotationParameters(annotationCall: FirAnnotationCall, session: return resultSet } -private fun FirExpression.convertConstantExpression(): KtConstantValue = +internal fun FirExpression.convertConstantExpression(): KtConstantValue = when (this) { is FirConstExpression<*> -> KtSimpleConstantValue(value) else -> KtUnsupportedConstantValue diff --git a/idea/idea-frontend-fir/testData/symbolsByPsi/anonymousObject.kt b/idea/idea-frontend-fir/testData/symbolsByPsi/anonymousObject.kt new file mode 100644 index 00000000000..41f140b6433 --- /dev/null +++ b/idea/idea-frontend-fir/testData/symbolsByPsi/anonymousObject.kt @@ -0,0 +1,91 @@ +class AnonymousContainer { + val anonymousObject = object : Runnable { + override fun run() { + + } + val data = 123 + } +} + +// SYMBOLS: +/* +KtFirFunctionSymbol: + annotations: [] + callableIdIfNonLocal: .run + isExtension: false + isExternal: false + isInline: false + isOperator: false + isOverride: true + isSuspend: false + modality: FINAL + name: run + origin: SOURCE + receiverType: null + symbolKind: MEMBER + type: kotlin/Unit + typeParameters: [] + valueParameters: [] + visibility: PUBLIC + +KtFirPropertySymbol: + annotations: [] + callableIdIfNonLocal: .data + getter: KtFirPropertyGetterSymbol() + hasBackingField: true + initializer: 123 + isConst: false + isExtension: false + isLateInit: false + isOverride: false + isVal: true + modality: FINAL + name: data + origin: SOURCE + receiverType: null + setter: null + symbolKind: MEMBER + type: kotlin/Int + visibility: PUBLIC + +KtFirAnonymousObjectSymbol: + annotations: [] + origin: SOURCE + superTypes: [java/lang/Runnable] + symbolKind: LOCAL + +KtFirPropertySymbol: + annotations: [] + callableIdIfNonLocal: AnonymousContainer.anonymousObject + getter: KtFirPropertyGetterSymbol() + hasBackingField: true + initializer: KtUnsupportedConstantValue + isConst: false + isExtension: false + isLateInit: false + isOverride: false + isVal: true + modality: FINAL + name: anonymousObject + origin: SOURCE + receiverType: null + setter: null + symbolKind: MEMBER + type: java/lang/Runnable + visibility: PUBLIC + +KtFirClassOrObjectSymbol: + annotations: [] + classIdIfNonLocal: AnonymousContainer + classKind: CLASS + companionObject: null + isInner: false + modality: FINAL + name: AnonymousContainer + origin: SOURCE + primaryConstructor: KtFirConstructorSymbol() + superTypes: [kotlin/Any] + symbolKind: TOP_LEVEL + typeParameters: [] + visibility: PUBLIC +*/ diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolsByPsiBuildingTestGenerated.java b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolsByPsiBuildingTestGenerated.java index fa7930de2e2..a3e8eee3c46 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolsByPsiBuildingTestGenerated.java +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/frontend/api/symbols/SymbolsByPsiBuildingTestGenerated.java @@ -33,6 +33,11 @@ public class SymbolsByPsiBuildingTestGenerated extends AbstractSymbolsByPsiBuild runTest("idea/idea-frontend-fir/testData/symbolsByPsi/annotations.kt"); } + @TestMetadata("anonymousObject.kt") + public void testAnonymousObject() throws Exception { + runTest("idea/idea-frontend-fir/testData/symbolsByPsi/anonymousObject.kt"); + } + @TestMetadata("class.kt") public void testClass() throws Exception { runTest("idea/idea-frontend-fir/testData/symbolsByPsi/class.kt");