[FIR IDE] LC Add anonymous objects support

+minor fixes
This commit is contained in:
Igor Yakovlev
2020-11-25 12:47:48 +03:00
parent 5630667320
commit a1603716ed
27 changed files with 657 additions and 208 deletions
@@ -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)
@@ -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<KtType>
abstract override fun createPointer(): KtSymbolPointer<KtAnonymousObjectSymbol>
}
@@ -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
@@ -59,6 +59,8 @@ abstract class KtPropertySymbol : KtVariableSymbol(),
abstract val isOverride: Boolean
abstract val initializer: KtConstantValue?
abstract override fun createPointer(): KtSymbolPointer<KtPropertySymbol>
}
@@ -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<FirDeclaration>(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()}")
@@ -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
}
}
}
@@ -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) {
@@ -31,16 +31,15 @@ internal class FirLightAnnotationClassSymbol(
override fun isAnnotationType(): Boolean = true
private val _ownFields: List<KtLightField> by lazyPub {
//TODO
mutableListOf<KtLightField>().also {
it.addCompanionObjectFieldIfNeeded()
addCompanionObjectFieldIfNeeded(it)
}
}
override fun getOwnFields(): List<KtLightField> = _ownFields
private val _ownMethods: List<KtLightMethod> by lazyPub {
//TODO
val result = mutableListOf<KtLightMethod>()
analyzeWithSymbolAsContext(classOrObjectSymbol) {
@@ -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<KotlinClassOrObjectStub<out KtClassOrObject>>, 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<KtLightField> = _ownFields
override fun getOwnMethods(): List<PsiMethod> = _ownMethods
private val _ownMethods: List<KtLightMethod> by lazyPub {
val result = mutableListOf<KtLightMethod>()
analyzeWithSymbolAsContext(anonymousObjectSymbol) {
val callableSymbols = anonymousObjectSymbol.getDeclaredMemberScope().getCallableSymbols()
createMethods(callableSymbols, isTopLevel = false, result)
}
result
}
private val _ownFields: List<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
val nameGenerator = FirLightField.FieldNameGenerator()
analyzeWithSymbolAsContext(anonymousObjectSymbol) {
anonymousObjectSymbol.getDeclaredMemberScope().getCallableSymbols()
.filterIsInstance<KtPropertySymbol>()
.forEach { propertySymbol ->
createField(
propertySymbol,
nameGenerator,
isTopLevel = false,
forceStatic = false,
takePropertyVisibility = propertySymbol.hasJvmFieldAnnotation(),
result
)
}
}
result
}
private val _ownInnerClasses: List<FirLightClassForSymbol> by lazyPub {
anonymousObjectSymbol.createInnerClasses(manager)
}
override fun getOwnInnerClasses(): List<PsiClass> = _ownInnerClasses
override fun getScope(): PsiElement? = parent
override fun getInterfaces(): Array<PsiClass> = PsiClassImplUtil.getInterfaces(this)
override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this)
override fun getSupers(): Array<PsiClass> = PsiClassImplUtil.getSupers(this)
override fun getSuperTypes(): Array<PsiClassType> = 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> = 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<out StubElement<*>, *>? = kotlinOrigin?.elementType
override fun getStub(): KotlinClassOrObjectStub<out KtClassOrObject>? = 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()}"
}
@@ -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<KtClassType>()
.filter { it.needToAddTypeIntoList() }
.mapNotNull { it.mapSupertype(this, kotlinCollectionAsIs = true) }
.forEach { listBuilder.addReference(it) }
return listBuilder
}
protected fun MutableList<KtLightField>.addCompanionObjectFieldIfNeeded() {
protected fun addCompanionObjectFieldIfNeeded(result: MutableList<KtLightField>) {
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
@@ -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<String>,
nameGenerator: FirLightField.FieldNameGenerator,
result: MutableList<KtLightField>
) {
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<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
val usedFieldNames = mutableSetOf<String>()
val nameGenerator = FirLightField.FieldNameGenerator()
for (file in files) {
loadFieldsFromFile(file, usedFieldNames, result)
loadFieldsFromFile(file, nameGenerator, result)
}
result
}
@@ -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<PsiClass> {
val result = ArrayList<PsiClass>()
// 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<KtClassOrObjectSymbol>().mapTo(result) {
FirLightClassForSymbol(it, manager)
}
}
//TODO
//if (classOrObject.hasInterfaceDefaultImpls) {
// result.add(KtLightClassForInterfaceDefaultImpls(classOrObject))
//}
return result
private val _ownInnerClasses: List<FirLightClassForSymbol> 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<PsiClass> = _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<KtLightMethod> 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<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
result.addCompanionObjectFieldIfNeeded()
val usedNames = mutableSetOf<String>()
private fun addFieldsFromCompanionIfNeeded(result: MutableList<KtLightField>, 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<KtLightField>, nameGenerator: FirLightField.FieldNameGenerator) {
analyzeWithSymbolAsContext(classOrObjectSymbol) {
classOrObjectSymbol.getDeclaredMemberScope().getAllSymbols()
.filterIsInstance<KtClassOrObjectSymbol>()
.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<KtLightField>) {
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<KtLightField>, nameGenerator: FirLightField.FieldNameGenerator) {
analyzeWithSymbolAsContext(classOrObjectSymbol) {
val propertySymbols = classOrObjectSymbol.getDeclaredMemberScope().getCallableSymbols()
.filterIsInstance<KtPropertySymbol>()
.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<KtEnumEntrySymbol>()
.mapTo(result) { FirLightFieldForEnumEntry(it, this@FirLightClassForSymbol, null) }
}
}
}
private val _ownFields: List<KtLightField> by lazyPub {
val result = mutableListOf<KtLightField>()
addCompanionObjectFieldIfNeeded(result)
addInstanceFieldIfNeeded(result)
val nameGenerator = FirLightField.FieldNameGenerator()
addObjectFields(result, nameGenerator)
addFieldsFromCompanionIfNeeded(result, nameGenerator)
addPropertyBackingFields(result, nameGenerator)
result
}
@@ -29,7 +29,7 @@ internal class FirLightInterfaceClassSymbol(
private val _ownFields: List<KtLightField> by lazyPub {
mutableListOf<KtLightField>().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
@@ -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 {
@@ -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<KtCallableSymbol>,
usedNames: MutableSet<String>,
internal fun FirLightClassBase.createField(
declaration: KtPropertySymbol,
nameGenerator: FirLightField.FieldNameGenerator,
isTopLevel: Boolean,
forceStatic: Boolean,
takePropertyVisibility: Boolean,
result: MutableList<KtLightField>
) {
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<KtType>): 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<KtClassType>()
.filter { it.needToAddTypeIntoList() }
.mapNotNull { it.mapSupertype(this, kotlinCollectionAsIs = true) }
.forEach { listBuilder.addReference(it) }
return listBuilder
}
internal fun KtSymbolWithDeclarations.createInnerClasses(manager: PsiManager): List<FirLightClassForSymbol> {
val result = ArrayList<FirLightClassForSymbol>()
// 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<KtClassOrObjectSymbol>().mapTo(result) {
FirLightClassForSymbol(it, manager)
}
}
//TODO
//if (classOrObject.hasInterfaceDefaultImpls) {
// result.add(KtLightClassForInterfaceDefaultImpls(classOrObject))
//}
return result
}
@@ -80,4 +80,18 @@ internal abstract class FirLightField protected constructor(
visitor.visitElement(this)
}
}
internal class FieldNameGenerator {
private val usedNames: MutableSet<String> = 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++
}
}
}
}
@@ -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()
}
@@ -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<String>,
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<String>, 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++
}
}
}
}
@@ -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 : Any> 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<error>")) 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 <T> Set<T>.add(what: T, `if`: Boolean): Set<T> =
applyIf(`if`) { this + what }
@@ -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) }
@@ -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 <T> 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)
@@ -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<FirAnonymousObject> {
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<KtAnnotationCall> by firRef.withFirAndCache(FirResolvePhase.TYPES) {
convertAnnotation(it)
}
override val superTypes: List<KtType> by firRef.withFirAndCache(FirResolvePhase.SUPER_TYPES) { fir ->
fir.superConeTypes.map {
builder.buildKtType(it)
}
}
override fun createPointer(): KtSymbolPointer<KtAnonymousObjectSymbol> =
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)
?: throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException("Cannot create pointer for KtFirAnonymousObjectSymbol")
}
@@ -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) {
@@ -87,7 +87,14 @@ internal class KtFirSymbolProvider(
}
}
override fun getAnonymousObjectSymbol(psi: KtObjectLiteralExpression): KtAnonymousObjectSymbol = withValidityAssertion {
psi.objectDeclaration.withFirDeclarationOfType<FirAnonymousObject, KtAnonymousObjectSymbol>(resolveState) {
firSymbolBuilder.buildAnonymousObjectSymbol(it)
}
}
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol = withValidityAssertion {
check(psi !is KtObjectDeclaration || psi.parent !is KtObjectLiteralExpression)
psi.withFirDeclarationOfType<FirRegularClass, KtClassOrObjectSymbol>(resolveState) {
firSymbolBuilder.buildClassSymbol(it)
}
@@ -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
@@ -0,0 +1,91 @@
class AnonymousContainer {
val anonymousObject = object : Runnable {
override fun run() {
}
val data = 123
}
}
// SYMBOLS:
/*
KtFirFunctionSymbol:
annotations: []
callableIdIfNonLocal: <anonymous>.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: <anonymous>.data
getter: KtFirPropertyGetterSymbol(<getter>)
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(<getter>)
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(<constructor>)
superTypes: [kotlin/Any]
symbolKind: TOP_LEVEL
typeParameters: []
visibility: PUBLIC
*/
@@ -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");