[FIR IDE] Add unwrapping substitution overrides which doesn't affect function's signature

Also, do not use PSI to restore SUBSTITUTION_OVERRIDE function/property
symbols
This commit is contained in:
Roman Golyshev
2021-10-28 13:16:33 +03:00
committed by teamcityserver
parent 2766dc938b
commit fa8bb47bdf
51 changed files with 1291 additions and 33 deletions
@@ -23,20 +23,22 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirFieldImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.resolve.getContainingClass
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.originalConstructorIfTypeAlias
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirClassInitializerSymbol
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
@@ -206,6 +208,10 @@ internal class KtSymbolByFirBuilder private constructor(
}
fun buildFunctionSymbol(fir: FirSimpleFunction): KtFirFunctionSymbol {
fir.unwrapSubstitutionOverrideIfNeeded()?.let {
return buildFunctionSymbol(it)
}
check(fir.origin != FirDeclarationOrigin.SamConstructor)
return symbolsCache.cache(fir) { KtFirFunctionSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
@@ -258,9 +264,14 @@ internal class KtSymbolByFirBuilder private constructor(
}
}
fun buildPropertySymbol(fir: FirProperty): KtKotlinPropertySymbol {
fun buildPropertySymbol(fir: FirProperty): KtVariableSymbol {
checkRequirementForBuildingSymbol<KtKotlinPropertySymbol>(fir, !fir.isLocal)
checkRequirementForBuildingSymbol<KtKotlinPropertySymbol>(fir, fir !is FirSyntheticProperty)
fir.unwrapSubstitutionOverrideIfNeeded()?.let {
return buildVariableSymbol(it)
}
return symbolsCache.cache(fir) {
KtFirKotlinPropertySymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
}
@@ -406,6 +417,44 @@ internal class KtSymbolByFirBuilder private constructor(
}
}
/**
* We want to unwrap a SUBSTITUTION_OVERRIDE wrapper if it doesn't affect the declaration's signature in any way. If the signature
* is somehow changed, then we want to keep the wrapper.
*
* If the declaration references only its own type parameters, or parameters from the outer declarations, then
* we consider that it's signature will not be changed by the SUBSTITUTION_OVERRIDE, so the wrapper can be unwrapped.
*
* This have a few caveats when it comes to the inner classes. TODO Provide a reference to some more in-detail description of that.
*
* N.B. This functions lifts only a single layer of SUBSTITUTION_OVERRIDE at a time.
*
* @receiver A declaration that needs to be unwrapped.
* @return An unsubstituted declaration ([originalForSubstitutionOverride]]) if it exists and if it does not have any change
* in signature; `null` otherwise.
*/
private inline fun <reified T : FirCallableDeclaration> T.unwrapSubstitutionOverrideIfNeeded(): T? {
val containingClass = getContainingClass(rootSession) ?: return null
val originalDeclaration = originalForSubstitutionOverride ?: return null
val allowedTypeParameters = buildSet {
// declaration's own parameters
originalDeclaration.typeParameters.mapTo(this) { it.symbol.toLookupTag() }
// captured outer parameters
containingClass.typeParameters.mapNotNullTo(this) {
(it as? FirOuterClassTypeParameterRef)?.symbol?.toLookupTag()
}
}
val usedTypeParameters = collectReferencedTypeParameters(originalDeclaration)
return if (allowedTypeParameters.containsAll(usedTypeParameters)) {
originalDeclaration
} else {
null
}
}
companion object {
private fun throwUnexpectedElementError(element: Any): Nothing {
error("Unexpected ${element::class.simpleName}")
@@ -427,7 +476,7 @@ internal class KtSymbolByFirBuilder private constructor(
}
private class BuilderCache<From, To: Any> private constructor(
private class BuilderCache<From, To : Any> private constructor(
private val cache: ConcurrentMap<From, To>,
private val isReadOnly: Boolean
) {
@@ -452,3 +501,46 @@ internal fun FirElement.buildSymbol(builder: KtSymbolByFirBuilder) =
internal fun FirDeclaration.buildSymbol(builder: KtSymbolByFirBuilder) =
builder.buildSymbol(this)
private fun collectReferencedTypeParameters(declaration: FirCallableDeclaration): Set<ConeTypeParameterLookupTag> {
val allUsedTypeParameters = mutableSetOf<ConeTypeParameterLookupTag>()
declaration.accept(object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
simpleFunction.typeParameters.forEach { it.accept(this) }
simpleFunction.receiverTypeRef?.accept(this)
simpleFunction.valueParameters.forEach { it.returnTypeRef.accept(this) }
simpleFunction.returnTypeRef.accept(this)
}
override fun visitProperty(property: FirProperty) {
property.typeParameters.forEach { it.accept(this) }
property.receiverTypeRef?.accept(this)
property.returnTypeRef.accept(this)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
super.visitResolvedTypeRef(resolvedTypeRef)
handleTypeRef(resolvedTypeRef)
}
private fun handleTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val resolvedType = resolvedTypeRef.type
resolvedType.forEachType {
if (it is ConeTypeParameterType) {
allUsedTypeParameters.add(it.lookupTag)
}
}
}
})
return allUsedTypeParameters
}
@@ -31,7 +31,7 @@ internal class KtFirBackingFieldSymbol(
}
override val owningProperty: KtKotlinPropertySymbol by propertyFirRef.withFirAndCache { fir ->
builder.variableLikeBuilder.buildPropertySymbol(fir)
builder.buildSymbol(fir) as KtKotlinPropertySymbol
}
override fun createPointer(): KtSymbolPointer<KtBackingFieldSymbol> {
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.*
@@ -92,7 +93,10 @@ internal class KtFirFunctionSymbol(
override val visibility: Visibility get() = getVisibility()
override fun createPointer(): KtSymbolPointer<KtFunctionSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
if (firRef.withFir { it.origin != FirDeclarationOrigin.SubstitutionOverride }) {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
}
return when (symbolKind) {
KtSymbolKind.TOP_LEVEL -> firRef.withFir { fir ->
KtFirTopLevelFunctionSymbolPointer(fir.symbol.callableId, fir.createSignature())
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
@@ -115,7 +116,10 @@ internal class KtFirKotlinPropertySymbol(
override val hasSetter: Boolean get() = firRef.withFir { it.setter != null }
override fun createPointer(): KtSymbolPointer<KtKotlinPropertySymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
if (firRef.withFir { it.origin != FirDeclarationOrigin.SubstitutionOverride }) {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
}
return when (symbolKind) {
KtSymbolKind.TOP_LEVEL -> TODO("Creating symbol for top level properties is not supported yet")
KtSymbolKind.CLASS_MEMBER -> firRef.withFir { fir ->
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2021 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.fir.scopes
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.scopes.AbstractSubstitutionOverridesUnwrappingTest
abstract class AbstractFirSubstitutionOverridesUnwrappingTest : AbstractSubstitutionOverridesUnwrappingTest(FirFrontendApiTestConfiguratorService)
@@ -47,10 +47,4 @@ public class FirMemberScopeByFqNameTestGenerated extends AbstractFirMemberScopeB
public void testMutableList() throws Exception {
runTest("analysis/analysis-api/testData/scopes/memberScopeByFqName/MutableList.kt");
}
@Test
@TestMetadata("overridenFunctionWithGenericBound.kt")
public void testOverridenFunctionWithGenericBound() throws Exception {
runTest("analysis/analysis-api/testData/scopes/memberScopeByFqName/overridenFunctionWithGenericBound.kt");
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2010-2021 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.fir.scopes;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping")
@TestDataPath("$PROJECT_ROOT")
public class FirSubstitutionOverridesUnwrappingTestGenerated extends AbstractFirSubstitutionOverridesUnwrappingTest {
@Test
public void testAllFilesPresentInSubstitutionOverridesUnwrapping() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("ClassWithGenericBase1.kt")
public void testClassWithGenericBase1() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/ClassWithGenericBase1.kt");
}
@Test
@TestMetadata("ClassWithGenericBase2.kt")
public void testClassWithGenericBase2() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/ClassWithGenericBase2.kt");
}
@Test
@TestMetadata("ClassWithGenericBase3.kt")
public void testClassWithGenericBase3() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/ClassWithGenericBase3.kt");
}
@Test
@TestMetadata("ClassWithGenericBase4.kt")
public void testClassWithGenericBase4() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/ClassWithGenericBase4.kt");
}
@Test
@TestMetadata("GenericFromFunctionInLocalClass1.kt")
public void testGenericFromFunctionInLocalClass1() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromFunctionInLocalClass1.kt");
}
@Test
@TestMetadata("GenericFromFunctionInLocalClass2.kt")
public void testGenericFromFunctionInLocalClass2() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromFunctionInLocalClass2.kt");
}
@Test
@TestMetadata("GenericFromOuterClassInInnerClass1.kt")
public void testGenericFromOuterClassInInnerClass1() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromOuterClassInInnerClass1.kt");
}
@Test
@TestMetadata("GenericFromOuterClassInInnerClass2.kt")
public void testGenericFromOuterClassInInnerClass2() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromOuterClassInInnerClass2.kt");
}
@Test
@TestMetadata("GenericFromOuterClassInInnerClassInInheritor1.kt")
public void testGenericFromOuterClassInInnerClassInInheritor1() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromOuterClassInInnerClassInInheritor1.kt");
}
@Test
@TestMetadata("GenericFromOuterClassInInnerClassInInheritor2.kt")
public void testGenericFromOuterClassInInnerClassInInheritor2() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromOuterClassInInnerClassInInheritor2.kt");
}
@Test
@TestMetadata("GenericFromOuterClassInInnerClassInInheritor3.kt")
public void testGenericFromOuterClassInInnerClassInInheritor3() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/GenericFromOuterClassInInnerClassInInheritor3.kt");
}
@Test
@TestMetadata("Implement_java_util_Collection.kt")
public void testImplement_java_util_Collection() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/Implement_java_util_Collection.kt");
}
@Test
@TestMetadata("MemberFunctionWithOuterTypeParameterBound.kt")
public void testMemberFunctionWithOuterTypeParameterBound() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/MemberFunctionWithOuterTypeParameterBound.kt");
}
@Test
@TestMetadata("MemberPropertyWithOuterTypeParameterBound.kt")
public void testMemberPropertyWithOuterTypeParameterBound() throws Exception {
runTest("analysis/analysis-api/testData/scopes/substitutionOverridesUnwrapping/MemberPropertyWithOuterTypeParameterBound.kt");
}
}
@@ -36,6 +36,18 @@ public class FirSymbolByReferenceTestGenerated extends AbstractFirSymbolByRefere
runTest("analysis/analysis-api/testData/symbols/symbolByReference/constructorViaTypeAlias.kt");
}
@Test
@TestMetadata("genericFromFunctionInLocalClass.kt")
public void testGenericFromFunctionInLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/symbols/symbolByReference/genericFromFunctionInLocalClass.kt");
}
@Test
@TestMetadata("genericFromOuterClassInInnerClass.kt")
public void testGenericFromOuterClassInInnerClass() throws Exception {
runTest("analysis/analysis-api/testData/symbols/symbolByReference/genericFromOuterClassInInnerClass.kt");
}
@Test
@TestMetadata("samConstructor.kt")
public void testSamConstructor() throws Exception {