[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:
committed by
teamcityserver
parent
2766dc938b
commit
fa8bb47bdf
+96
-4
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -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> {
|
||||
|
||||
+5
-1
@@ -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())
|
||||
|
||||
+5
-1
@@ -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 ->
|
||||
|
||||
+11
@@ -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)
|
||||
-6
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
+110
@@ -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");
|
||||
}
|
||||
}
|
||||
+12
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user