KTIJ-27050 [Analysis API] Correctly handle type parameters in KtFirReferenceShortener

Make `FirShorteningContext` correctly return symbols for type
parameters, so they are not ignored when scopes are inspected

Add additional type of `PartialOrderOfScope` - `TypeParameter`, because
otherwise it would have been classified as `Unclassified`, and that
breaks scopes comparison

Add missing type parameters to the scope of class header in
`ContextCollector`, add testdata for that

There is a bug in the compiler with type parameters leaking to nested
classes headers (KT-61959). After it's fixed, the testData with
incorrect expected shortenings/scopes should be adjusted and fixed too

^KTIJ-27050 Fixed
This commit is contained in:
Roman Golyshev
2023-09-14 17:06:15 +02:00
committed by teamcity
parent e2019ceb95
commit a78d631b16
29 changed files with 560 additions and 12 deletions
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.util.PrivateForInline
import org.jetbrains.kotlin.utils.yieldIfNotNull
object ContextCollector {
@@ -358,10 +359,13 @@ private class ContextCollectorVisitor(
* Processing those parts before adding the implicit receiver of the class
* to the [context] allows to not collect incorrect contexts for them later on.
*/
@OptIn(PrivateForInline::class)
private fun Processor.processClassHeader(regularClass: FirRegularClass) {
processList(regularClass.contextReceivers)
processList(regularClass.typeParameters)
processList(regularClass.superTypeRefs)
context.withTypeParametersOf(regularClass) {
processList(regularClass.contextReceivers)
processList(regularClass.typeParameters)
processList(regularClass.superTypeRefs)
}
}
override fun visitConstructor(constructor: FirConstructor) = withProcessor {
@@ -0,0 +1,4 @@
package test
context(<expr>MyParam</expr>)
class Outer<MyParam>
@@ -0,0 +1,28 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol MyParam
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromContextReceiver.kt
context(R|MyParam|)
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam>(): R|test/Outer<MyParam>| {
super<R|kotlin/Any|>()
}
}
@@ -0,0 +1,5 @@
package test
class Outer<MyParam> {
inner class Inner<T : <expr>MyParam</expr>>
}
@@ -0,0 +1,46 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol MyParam
Element 8
Scope: FirNestedClassifierScopeImpl
Classifiers:
FirRegularClassSymbol public final inner class Inner<T : R|MyParam|, Outer(MyParam)> : R|kotlin/Any|
Element 9
Implicit receiver:
FirRegularClassSymbol public final class Outer<MyParam> : R|kotlin/Any|
Type: test/Outer<MyParam>
Element 10
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol T : R|MyParam|
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromInner_typeBound.kt
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam>(): R|test/Outer<MyParam>| {
super<R|kotlin/Any|>()
}
public final inner [ResolvedTo(STATUS)] class Inner<[ResolvedTo(STATUS)] T : R|MyParam|, [ResolvedTo(STATUS)] Outer(MyParam)> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] test/Outer<MyParam>.constructor<[ResolvedTo(STATUS)] T : R|MyParam|>(): R|test/Outer.Inner<T, MyParam>| {
super<R|kotlin/Any|>()
}
}
}
@@ -0,0 +1,7 @@
package test
class Outer<MyParam> {
inner class Inner {
fun member(p: <expr>MyParam</expr>) {}
}
}
@@ -0,0 +1,55 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol MyParam
Element 8
Scope: FirNestedClassifierScopeImpl
Classifiers:
FirRegularClassSymbol public final inner class Inner<Outer(MyParam)> : R|kotlin/Any|
Element 9
Implicit receiver:
FirRegularClassSymbol public final class Outer<MyParam> : R|kotlin/Any|
Type: test/Outer<MyParam>
Element 10
Scope: FirMemberTypeParameterScope
Element 11
Implicit receiver:
FirRegularClassSymbol public final inner class Inner<Outer(MyParam)> : R|kotlin/Any|
Type: test/Outer.Inner<MyParam>
Element 12
Scope: FirLocalScope
Properties:
FirValueParameterSymbol p: R|MyParam|
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromInner_typeRefInMember.kt
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam>(): R|test/Outer<MyParam>| {
super<R|kotlin/Any|>()
}
public final inner [ResolvedTo(STATUS)] class Inner<[ResolvedTo(STATUS)] Outer(MyParam)> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] test/Outer<MyParam>.constructor(): R|test/Outer.Inner<MyParam>| {
super<R|kotlin/Any|>()
}
public final [ResolvedTo(BODY_RESOLVE)] fun member([ResolvedTo(BODY_RESOLVE)] p: R|MyParam|): R|kotlin/Unit| {
}
}
}
@@ -0,0 +1,6 @@
package test
class Outer<MyParam> {
// TODO this test has an error, MyParam should not be resolved here. See KT-61959
class Nested<T : <expr>MyParam</expr>>
}
@@ -0,0 +1,46 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol MyParam
Element 8
Scope: FirNestedClassifierScopeImpl
Classifiers:
FirRegularClassSymbol public final class Nested<T : R|MyParam|> : R|kotlin/Any|
Element 9
Implicit receiver:
FirRegularClassSymbol public final class Outer<MyParam> : R|kotlin/Any|
Type: test/Outer<MyParam>
Element 10
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol T : R|MyParam|
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromNested_typeBound.kt
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam>(): R|test/Outer<MyParam>| {
super<R|kotlin/Any|>()
}
public final [ResolvedTo(STATUS)] class Nested<[ResolvedTo(STATUS)] T : R|MyParam|> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] T : R|MyParam|>(): R|test/Outer.Nested<T>| {
super<R|kotlin/Any|>()
}
}
}
@@ -0,0 +1,7 @@
package test
class Outer<MyParam> {
class Nested {
fun member(p: <expr>MyParam</expr>) {}
}
}
@@ -0,0 +1,45 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirNestedClassifierScopeImpl
Classifiers:
FirRegularClassSymbol public final class Nested : R|kotlin/Any|
Element 8
Implicit receiver:
FirRegularClassSymbol public final class Nested : R|kotlin/Any|
Type: test/Outer.Nested
Element 9
Scope: FirLocalScope
Properties:
FirValueParameterSymbol p: <ERROR TYPE REF: Symbol not found for MyParam>
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromNested_typeRefInMember.kt
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam>(): R|test/Outer<MyParam>| {
super<R|kotlin/Any|>()
}
public final [ResolvedTo(STATUS)] class Nested : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor(): R|test/Outer.Nested| {
super<R|kotlin/Any|>()
}
public final [ResolvedTo(BODY_RESOLVE)] fun member([ResolvedTo(BODY_RESOLVE)] p: <ERROR TYPE REF: Symbol not found for MyParam>): R|kotlin/Unit| {
}
}
}
@@ -0,0 +1,5 @@
package test
open class Base<T>
class Outer<MyParam> : Base<<expr>MyParam</expr>>()
@@ -0,0 +1,33 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol MyParam
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromSuperType.kt
public open [ResolvedTo(STATUS)] class Base<[ResolvedTo(STATUS)] T> : R|kotlin/Any| {
public [ResolvedTo(STATUS)] constructor<[ResolvedTo(STATUS)] T>(): R|test/Base<T>| {
LAZY_super<R|kotlin/Any|>
}
}
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam> : R|test/Base<MyParam>| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam>(): R|test/Outer<MyParam>| {
super<R|test/Base<MyParam>|>()
}
}
@@ -0,0 +1,3 @@
package test
class Outer<MyParam, Other : <expr>MyParam</expr>>
@@ -0,0 +1,28 @@
Tower Data Context:
Element 0
Scope: FirDefaultStarImportingScope
Element 1
Scope: FirDefaultSimpleImportingScope
Element 2
Scope: FirExplicitStarImportingScope
Element 3
Scope: FirDefaultSimpleImportingScope
Element 4
Scope: FirDefaultSimpleImportingScope
Element 5
Scope: FirPackageMemberScope
Element 6
Scope: FirExplicitSimpleImportingScope
Element 7
Scope: FirMemberTypeParameterScope
Classifiers:
FirTypeParameterSymbol MyParam
FirTypeParameterSymbol Other : R|MyParam|
FILE: [ResolvedTo(IMPORTS)] declaredInClass_fromTypeBound.kt
public final [ResolvedTo(STATUS)] class Outer<[ResolvedTo(STATUS)] MyParam, [ResolvedTo(STATUS)] Other : R|MyParam|> : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] constructor<[ResolvedTo(STATUS)] MyParam, [ResolvedTo(STATUS)] Other : R|MyParam|>(): R|test/Outer<MyParam, Other>| {
super<R|kotlin/Any|>()
}
}
@@ -71,4 +71,14 @@ public class ContextCollectorScriptTestGenerated extends AbstractContextCollecto
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testdata/contextCollector/smartCasts"), Pattern.compile("^(.+)\\.(kts)$"), null, true);
}
}
@Nested
@TestMetadata("analysis/low-level-api-fir/testdata/contextCollector/typeParameters")
@TestDataPath("$PROJECT_ROOT")
public class TypeParameters {
@Test
public void testAllFilesPresentInTypeParameters() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testdata/contextCollector/typeParameters"), Pattern.compile("^(.+)\\.(kts)$"), null, true);
}
}
}
@@ -293,4 +293,56 @@ public class ContextCollectorSourceTestGenerated extends AbstractContextCollecto
runTest("analysis/low-level-api-fir/testdata/contextCollector/smartCasts/when.kt");
}
}
@Nested
@TestMetadata("analysis/low-level-api-fir/testdata/contextCollector/typeParameters")
@TestDataPath("$PROJECT_ROOT")
public class TypeParameters {
@Test
public void testAllFilesPresentInTypeParameters() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testdata/contextCollector/typeParameters"), Pattern.compile("^(.+)\\.(kt)$"), null, true);
}
@Test
@TestMetadata("declaredInClass_fromContextReceiver.kt")
public void testDeclaredInClass_fromContextReceiver() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromContextReceiver.kt");
}
@Test
@TestMetadata("declaredInClass_fromInner_typeBound.kt")
public void testDeclaredInClass_fromInner_typeBound() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromInner_typeBound.kt");
}
@Test
@TestMetadata("declaredInClass_fromInner_typeRefInMember.kt")
public void testDeclaredInClass_fromInner_typeRefInMember() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromInner_typeRefInMember.kt");
}
@Test
@TestMetadata("declaredInClass_fromNested_typeBound.kt")
public void testDeclaredInClass_fromNested_typeBound() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromNested_typeBound.kt");
}
@Test
@TestMetadata("declaredInClass_fromNested_typeRefInMember.kt")
public void testDeclaredInClass_fromNested_typeRefInMember() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromNested_typeRefInMember.kt");
}
@Test
@TestMetadata("declaredInClass_fromSuperType.kt")
public void testDeclaredInClass_fromSuperType() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromSuperType.kt");
}
@Test
@TestMetadata("declaredInClass_fromTypeBound.kt")
public void testDeclaredInClass_fromTypeBound() throws Exception {
runTest("analysis/low-level-api-fir/testdata/contextCollector/typeParameters/declaredInClass_fromTypeBound.kt");
}
}
}