[AA] improve symbol pointers for property accessors

Fe10:
* supported default setter
* support default getter
* support parameter from default setter

Fir:
* support java synthetic properties
* support parameter from default setter

^KT-54051
This commit is contained in:
Dmitrii Gridin
2022-11-17 17:09:31 +01:00
committed by Space Team
parent ca12cfb90d
commit edd60cd204
11 changed files with 129 additions and 50 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade
@@ -24,11 +25,10 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.ktSym
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.ktVisibility
import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached
import org.jetbrains.kotlin.analysis.api.impl.base.annotations.KtEmptyAnnotationsList
import org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers.KtPropertyAccessorSymbolPointer
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyGetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtReceiverParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.*
@@ -97,8 +97,12 @@ internal class KtFe10PsiDefaultPropertyGetterSymbol(
descriptor?.let { KtFe10AnnotationsList.create(it.annotations, token) } ?: KtEmptyAnnotationsList(token)
}
@OptIn(KtAnalysisApiInternals::class)
override fun createPointer(): KtSymbolPointer<KtPropertyGetterSymbol> = withValidityAssertion {
return KtFe10NeverRestoringSymbolPointer()
KtPsiBasedSymbolPointer.createForSymbolFromPsi<KtPropertySymbol>(propertyPsi)?.let {
@Suppress("UNCHECKED_CAST")
KtPropertyAccessorSymbolPointer(it, isGetter = true) as KtSymbolPointer<KtPropertyGetterSymbol>
} ?: KtFe10NeverRestoringSymbolPointer()
}
override fun equals(other: Any?): Boolean = isEqualTo(other)
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade
@@ -24,11 +25,11 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.ktSym
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.ktVisibility
import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached
import org.jetbrains.kotlin.analysis.api.impl.base.annotations.KtEmptyAnnotationsList
import org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers.KtPropertyAccessorSymbolPointer
import org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers.KtValueParameterFromDefaultSetterSymbolPointer
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtReceiverParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.*
@@ -104,11 +105,14 @@ internal class KtFe10PsiDefaultPropertySetterSymbol(
descriptor?.let { KtFe10AnnotationsList.create(it.annotations, token) } ?: KtEmptyAnnotationsList(token)
}
@OptIn(KtAnalysisApiInternals::class)
override fun createPointer(): KtSymbolPointer<KtPropertySetterSymbol> = withValidityAssertion {
return KtFe10NeverRestoringSymbolPointer()
KtPsiBasedSymbolPointer.createForSymbolFromPsi<KtPropertySymbol>(propertyPsi)?.let {
@Suppress("UNCHECKED_CAST")
KtPropertyAccessorSymbolPointer(it, isGetter = false) as KtSymbolPointer<KtPropertySetterSymbol>
} ?: KtFe10NeverRestoringSymbolPointer()
}
override fun equals(other: Any?): Boolean = isEqualTo(other)
override fun hashCode(): Int = calculateHashCode()
@@ -149,8 +153,11 @@ internal class KtFe10PsiDefaultPropertySetterSymbol(
descriptor?.let { KtFe10AnnotationsList.create(it.annotations, token) } ?: KtEmptyAnnotationsList(token)
}
@OptIn(KtAnalysisApiInternals::class)
override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol> = withValidityAssertion {
return KtFe10NeverRestoringSymbolPointer()
KtPsiBasedSymbolPointer.createForSymbolFromPsi<KtPropertySymbol>(propertyPsi)?.let {
KtValueParameterFromDefaultSetterSymbolPointer(it)
} ?: KtFe10NeverRestoringSymbolPointer()
}
override fun equals(other: Any?): Boolean = isEqualTo(other)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2022 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.
*/
@@ -18,9 +18,12 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.creat
import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached
import org.jetbrains.kotlin.analysis.api.impl.base.annotations.KtEmptyAnnotationsList
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.symbolPointerDelegator
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.name.Name
@@ -67,10 +70,11 @@ internal class KtFe10PsiDefaultSetterParameterSymbol(
get() = withValidityAssertion { KtEmptyAnnotationsList(token) }
override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol> = withValidityAssertion {
return KtFe10NeverRestoringSymbolPointer()
KtPsiBasedSymbolPointer.createForSymbolFromPsi<KtPropertySetterSymbol>(accessorPsi)?.let { symbolPointer ->
symbolPointerDelegator(symbolPointer) { it.parameter }
} ?: KtFe10NeverRestoringSymbolPointer()
}
override fun equals(other: Any?): Boolean = isEqualTo(other)
override fun hashCode(): Int = calculateHashCode()
}
@@ -88,7 +88,7 @@ internal class KtFirSymbolContainingDeclarationProvider(
KtFakeSourceElementKind.ImplicitConstructor -> return source.psi as KtDeclaration
KtFakeSourceElementKind.PropertyFromParameter -> return source.psi?.parentOfType<KtPrimaryConstructor>()!!
KtFakeSourceElementKind.DefaultAccessor -> return source.psi as KtProperty
KtFakeSourceElementKind.DefaultAccessor -> return source.psi as KtDeclaration
KtFakeSourceElementKind.ItLambdaParameter -> return source.psi as KtFunctionLiteral
KtFakeSourceElementKind.EnumInitializer -> return source.psi as KtEnumEntry
KtRealSourceElementKind -> source.psi!!
@@ -6,12 +6,13 @@
package org.jetbrains.kotlin.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirPropertyAccessorSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.requireOwnerPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers.KtPropertyAccessorSymbolPointer
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyGetterSymbol
@@ -57,8 +58,14 @@ internal class KtFirPropertyGetterSymbol(
override val returnType: KtType get() = withValidityAssertion { firSymbol.returnType(builder) }
override val receiverParameter: KtReceiverParameterSymbol? get() = withValidityAssertion { firSymbol.fir.propertySymbol.receiver(builder) }
override val annotationsList by cached { KtFirAnnotationListForDeclaration.create(firSymbol, firResolveSession.useSiteFirSession, token) }
override val annotationsList by cached {
KtFirAnnotationListForDeclaration.create(
firSymbol,
firResolveSession.useSiteFirSession,
token,
)
}
/**
* Returns [CallableId] of the delegated Java method if the corresponding property of this setter is a synthetic Java property.
@@ -76,11 +83,12 @@ internal class KtFirPropertyGetterSymbol(
override val hasStableParameterNames: Boolean
get() = withValidityAssertion { true }
@OptIn(KtAnalysisApiInternals::class)
override fun createPointer(): KtSymbolPointer<KtPropertyGetterSymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtPropertyGetterSymbol>(this)?.let { return it }
@Suppress("UNCHECKED_CAST")
KtFirPropertyAccessorSymbolPointer(requireOwnerPointer(), isGetter = true) as KtSymbolPointer<KtPropertyGetterSymbol>
KtPropertyAccessorSymbolPointer(requireOwnerPointer(), isGetter = true) as KtSymbolPointer<KtPropertyGetterSymbol>
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
@@ -6,12 +6,13 @@
package org.jetbrains.kotlin.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirPropertyAccessorSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.requireOwnerPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers.KtPropertyAccessorSymbolPointer
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySetterSymbol
@@ -99,11 +100,12 @@ internal class KtFirPropertySetterSymbol(
override val hasStableParameterNames: Boolean
get() = withValidityAssertion { true }
@OptIn(KtAnalysisApiInternals::class)
override fun createPointer(): KtSymbolPointer<KtPropertySetterSymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtPropertySetterSymbol>(this)?.let { return it }
@Suppress("UNCHECKED_CAST")
KtFirPropertyAccessorSymbolPointer(requireOwnerPointer(), isGetter = false) as KtSymbolPointer<KtPropertySetterSymbol>
KtPropertyAccessorSymbolPointer(requireOwnerPointer(), isGetter = false) as KtSymbolPointer<KtPropertySetterSymbol>
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
@@ -46,9 +46,9 @@ internal class KtFirValueParameterSymbol(
firSymbol.source?.kind == KtFakeSourceElementKind.ItLambdaParameter
}
override val isCrossinline: Boolean get() = withValidityAssertion { firSymbol.isCrossinline}
override val isCrossinline: Boolean get() = withValidityAssertion { firSymbol.isCrossinline }
override val isNoinline: Boolean get() = withValidityAssertion { firSymbol.isNoinline}
override val isNoinline: Boolean get() = withValidityAssertion { firSymbol.isNoinline }
override val returnType by cached {
val returnType = firSymbol.resolvedReturnType
@@ -64,7 +64,13 @@ internal class KtFirValueParameterSymbol(
override val hasDefaultValue: Boolean get() = withValidityAssertion { firSymbol.hasDefaultValue }
override val annotationsList by cached { KtFirAnnotationListForDeclaration.create(firSymbol, firResolveSession.useSiteFirSession, token) }
override val annotationsList by cached {
KtFirAnnotationListForDeclaration.create(
firSymbol,
firResolveSession.useSiteFirSession,
token,
)
}
override val generatedPrimaryConstructorProperty: KtKotlinPropertySymbol? by cached {
val propertySymbol = firSymbol.fir.correspondingProperty?.symbol ?: return@cached null
@@ -72,6 +78,7 @@ internal class KtFirValueParameterSymbol(
check(ktPropertySymbol is KtKotlinPropertySymbol) {
"Unexpected symbol for primary constructor property ${ktPropertySymbol.javaClass} for fir: ${firSymbol.fir.renderWithType()}"
}
ktPropertySymbol
}
@@ -79,14 +86,16 @@ internal class KtFirValueParameterSymbol(
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtValueParameterSymbol>(this)?.let { return it }
analyze(firResolveSession.useSiteKtModule) {
val owner = getContainingSymbol() as KtFunctionLikeSymbol
val firFunction = owner.firSymbol.fir as FirFunction
when (val owner = getContainingSymbol()) {
is KtFunctionLikeSymbol ->
KtFirValueParameterSymbolPointer(
owner.createPointer(),
name,
(owner.firSymbol.fir as FirFunction).valueParameters.indexOf(firSymbol.fir),
)
KtFirValueParameterSymbolPointer(
owner.createPointer(),
name,
firFunction.valueParameters.indexOf(firSymbol.fir),
)
else -> error("${requireNotNull(owner)::class}")
}
}
}
@@ -3,27 +3,25 @@
* 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.analysis.api.fir.symbols.pointers
package org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirKotlinPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyAccessorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
internal class KtFirPropertyAccessorSymbolPointer(
private val propertySymbolPointer: KtSymbolPointer<KtKotlinPropertySymbol>,
@KtAnalysisApiInternals
class KtPropertyAccessorSymbolPointer(
private val propertySymbolPointer: KtSymbolPointer<KtPropertySymbol>,
private val isGetter: Boolean,
) : KtSymbolPointer<KtPropertyAccessorSymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtPropertyAccessorSymbol? {
require(analysisSession is KtFirAnalysisSession)
val propertySymbol = with(analysisSession) {
propertySymbolPointer.restoreSymbol()
} ?: return null
check(propertySymbol is KtFirKotlinPropertySymbol)
return if (isGetter) propertySymbol.getter else propertySymbol.setter
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2022 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.analysis.api.impl.base.symbols.pointers
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
@KtAnalysisApiInternals
class KtValueParameterFromDefaultSetterSymbolPointer(
private val ownerPointer: KtSymbolPointer<KtPropertySymbol>,
) : KtSymbolPointer<KtValueParameterSymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtValueParameterSymbol? {
val ownerSymbol = with(analysisSession) {
ownerPointer.restoreSymbol()
}
return ownerSymbol?.setter?.parameter
}
}
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.base.test.SymbolByFqName
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolsData
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.services.TestServices
@@ -85,11 +85,19 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
analyseForTest(ktFile) {
val (symbols, symbolForPrettyRendering) = collectSymbols(ktFile, testServices)
val pointerWithRenderedSymbol = symbols.map { symbol ->
PointerWithRenderedSymbol(
symbol.safePointer(),
renderSymbolForComparison(symbol),
)
val pointerWithRenderedSymbol = symbols.flatMap { symbol ->
listOf(
PointerWithRenderedSymbol(
symbol.safePointer(),
renderSymbolForComparison(symbol),
)
) + symbol.withImplicitSymbols().map { implicitSymbol ->
PointerWithRenderedSymbol(
implicitSymbol.safePointer(),
renderSymbolForComparison(implicitSymbol),
shouldBeRendered = false,
)
}
}
val pointerWithPrettyRenderedSymbol = symbolForPrettyRendering.map { symbol ->
@@ -105,7 +113,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
is KtReceiverParameterSymbol -> DebugSymbolRenderer().render(symbol)
else -> error(symbol::class.toString())
}
},
)
}
@@ -168,7 +176,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
}
private fun List<PointerWithRenderedSymbol>.renderDeclarations(): String =
map { it.rendered }.renderAsDeclarations()
mapNotNull { it.rendered.takeIf { _ -> it.shouldBeRendered } }.renderAsDeclarations()
private fun List<String>.renderAsDeclarations(): String =
if (isEmpty()) "NO_SYMBOLS"
@@ -184,10 +192,16 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() {
var failed = false
try {
val restored = analyseForTest(ktFile) {
pointersWithRendered.map { (pointerWrapper, expectedRender) ->
pointersWithRendered.mapNotNull { (pointerWrapper, expectedRender, shouldBeRendered) ->
val pointer = pointerWrapper?.let(pointerAccessor) ?: error("Symbol pointer for $expectedRender was not created")
val restored = pointer.restoreSymbol() ?: error("Symbol $expectedRender was not restored")
renderSymbolForComparison(restored)
val actualRender = renderSymbolForComparison(restored)
if (shouldBeRendered) {
actualRender
} else {
testServices.assertions.assertEquals(expectedRender, actualRender) { "${restored::class}" }
null
}
}
}
@@ -259,9 +273,18 @@ private data class SymbolPointersData(
private data class PointerWithRenderedSymbol(
val pointer: PointerWrapper?,
val rendered: String,
val shouldBeRendered: Boolean = true,
)
private data class PointerWrapper(
val regularPointer: KtSymbolPointer<*>,
val pointerWithoutPsiAnchor: KtSymbolPointer<*>?,
)
private fun KtSymbol?.withImplicitSymbols(): List<KtSymbol> = when (this) {
null -> emptyList()
is KtPropertySymbol -> listOf(this) + setter.withImplicitSymbols() + getter.withImplicitSymbols()
is KtPropertySetterSymbol -> listOf(this) + parameter
is KtValueParameterSymbol -> listOf(this) + generatedPrimaryConstructorProperty.withImplicitSymbols()
else -> listOf(this)
}