KT-63627 [AA] Properly handle object declarations when traversing scopes in KtFirReferenceShortener

`KtClass` denotes only classes, interfaces and enums.
To handle object declarations, we now use
`KtClassOrObject` PSI type

^KT-63627 Fixed
This commit is contained in:
Roman Golyshev
2023-11-21 15:16:37 +01:00
committed by teamcity
parent 5096fd266e
commit 7d7256536c
15 changed files with 256 additions and 5 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
@@ -66,6 +67,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import java.util.Arrays
internal class KtFirReferenceShortener(
override val analysisSession: KtFirAnalysisSession,
@@ -652,7 +654,7 @@ private class ElementsToShortenCollector(
*
* This function determines the distance based on [ClassId].
*/
private fun FirScope.isScopeForClassCloserThanAnotherScopeForClass(another: FirScope, from: KtClass): Boolean {
private fun FirScope.isScopeForClassCloserThanAnotherScopeForClass(another: FirScope, from: KtClassOrObject): Boolean {
// Make sure both are scopes for classes
if (!isScopeForClass() || !another.isScopeForClass()) return false
@@ -673,12 +675,12 @@ private class ElementsToShortenCollector(
* Travels all containing classes of [innerClass] and finds the one matching ClassId with one of [candidates]. Returns the matching
* ClassId. If it does not have a matching ClassId, it returns null.
*/
private fun findMostInnerClassMatchingId(innerClass: KtClass, candidates: Set<ClassId>): ClassId? {
var classInNestedClass: KtClass? = innerClass
private fun findMostInnerClassMatchingId(innerClass: KtClassOrObject, candidates: Set<ClassId>): ClassId? {
var classInNestedClass: KtClassOrObject? = innerClass
while (classInNestedClass != null) {
val containingClassId = classInNestedClass.getClassId()
if (containingClassId in candidates) return containingClassId
classInNestedClass = classInNestedClass.containingClass()
classInNestedClass = classInNestedClass.findClassOrObjectParent()
}
return null
}
@@ -745,7 +747,7 @@ private class ElementsToShortenCollector(
*/
private fun List<FirScope>.hasScopeCloserThan(base: FirScope, from: KtElement) = any { scope ->
if (scope.isScopeForClass() && base.isScopeForClass()) {
val classContainingFrom = from.containingClass() ?: return@any false
val classContainingFrom = from.findClassOrObjectParent() ?: return@any false
return@any scope.isScopeForClassCloserThanAnotherScopeForClass(base, classContainingFrom)
}
base.isWiderThan(scope)
@@ -1494,3 +1496,12 @@ private fun KtElement.getQualifier(): KtElement? = when (this) {
is KtThisExpression -> labelQualifier
else -> error("Unexpected ${this::class}")
}
/**
* N.B. We don't use [containingClassOrObject] because it works only for [KtDeclaration]s,
* and also check only the immediate (direct) parent.
*
* For this function, we want to find the parent [KtClassOrObject] declaration no matter
* how far it is from the element.
*/
private fun KtElement.findClassOrObjectParent(): KtClassOrObject? = parentOfType()
@@ -625,6 +625,42 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_inside.kt")
public void testClassAndObjectHaveConflictingNestedClasses_inside() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_inside.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_inside_companion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_inside_companion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_inside_companion.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_inside_namedCompanion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_inside_namedCompanion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_inside_namedCompanion.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_outside.kt")
public void testClassAndObjectHaveConflictingNestedClasses_outside() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_outside.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_outside_companion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_outside_companion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_outside_companion.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_outside_namedCompanion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_outside_namedCompanion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_outside_namedCompanion.kt");
}
@Test
@TestMetadata("nestedClassFromSupertypes1.kt")
public void testNestedClassFromSupertypes1() throws Exception {
@@ -625,6 +625,42 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_inside.kt")
public void testClassAndObjectHaveConflictingNestedClasses_inside() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_inside.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_inside_companion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_inside_companion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_inside_companion.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_inside_namedCompanion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_inside_namedCompanion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_inside_namedCompanion.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_outside.kt")
public void testClassAndObjectHaveConflictingNestedClasses_outside() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_outside.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_outside_companion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_outside_companion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_outside_companion.kt");
}
@Test
@TestMetadata("classAndObjectHaveConflictingNestedClasses_outside_namedCompanion.kt")
public void testClassAndObjectHaveConflictingNestedClasses_outside_namedCompanion() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classAndObjectHaveConflictingNestedClasses_outside_namedCompanion.kt");
}
@Test
@TestMetadata("nestedClassFromSupertypes1.kt")
public void testNestedClassFromSupertypes1() throws Exception {
@@ -0,0 +1,14 @@
package test
class OuterClass {
class Nested
object NestedObject {
class Nested
<expr>fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NestedObject.Nested,
) {}</expr>
}
}
@@ -0,0 +1,14 @@
Before shortening: fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NestedObject.Nested,
) {}
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
[type] test.OuterClass
[type] test.OuterClass.NestedObject.Nested
with SHORTEN_AND_IMPORT:
[type] test.OuterClass
[type] test.OuterClass.NestedObject.Nested
with SHORTEN_AND_STAR_IMPORT:
[type] test.OuterClass
[type] test.OuterClass.NestedObject.Nested
@@ -0,0 +1,14 @@
package test
class OuterClass {
class Nested
companion object {
class Nested
<expr>fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.Companion.Nested,
) {}</expr>
}
}
@@ -0,0 +1,14 @@
Before shortening: fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.Companion.Nested,
) {}
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
[type] test.OuterClass
[type] test.OuterClass.Companion.Nested
with SHORTEN_AND_IMPORT:
[type] test.OuterClass
[type] test.OuterClass.Companion.Nested
with SHORTEN_AND_STAR_IMPORT:
[type] test.OuterClass
[type] test.OuterClass.Companion.Nested
@@ -0,0 +1,14 @@
package test
class OuterClass {
class Nested
companion object NamedCompanion {
class Nested
<expr>fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NamedCompanion.Nested,
) {}</expr>
}
}
@@ -0,0 +1,14 @@
Before shortening: fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NamedCompanion.Nested,
) {}
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
[type] test.OuterClass
[type] test.OuterClass.NamedCompanion.Nested
with SHORTEN_AND_IMPORT:
[type] test.OuterClass
[type] test.OuterClass.NamedCompanion.Nested
with SHORTEN_AND_STAR_IMPORT:
[type] test.OuterClass
[type] test.OuterClass.NamedCompanion.Nested
@@ -0,0 +1,14 @@
package test
class OuterClass {
class Nested
object NestedObject {
class Nested
}
<expr>fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NestedObject.Nested,
) {}</expr>
}
@@ -0,0 +1,14 @@
Before shortening: fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NestedObject.Nested,
) {}
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
[type] test.OuterClass.Nested
[type] test.OuterClass.NestedObject
with SHORTEN_AND_IMPORT:
[type] test.OuterClass.Nested
[type] test.OuterClass.NestedObject
with SHORTEN_AND_STAR_IMPORT:
[type] test.OuterClass.Nested
[type] test.OuterClass.NestedObject
@@ -0,0 +1,14 @@
package test
class OuterClass {
class Nested
companion object {
class Nested
}
<expr>fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.Companion.Nested,
) {}</expr>
}
@@ -0,0 +1,14 @@
Before shortening: fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.Companion.Nested,
) {}
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
[type] test.OuterClass.Nested
[type] test.OuterClass.Companion
with SHORTEN_AND_IMPORT:
[type] test.OuterClass.Nested
[type] test.OuterClass.Companion
with SHORTEN_AND_STAR_IMPORT:
[type] test.OuterClass.Nested
[type] test.OuterClass.Companion
@@ -0,0 +1,14 @@
package test
class OuterClass {
class Nested
companion object NamedCompanion {
class Nested
}
<expr>fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NamedCompanion.Nested,
) {}</expr>
}
@@ -0,0 +1,14 @@
Before shortening: fun usage(
first: test.OuterClass.Nested,
second: test.OuterClass.NamedCompanion.Nested,
) {}
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
[type] test.OuterClass.Nested
[type] test.OuterClass.NamedCompanion
with SHORTEN_AND_IMPORT:
[type] test.OuterClass.Nested
[type] test.OuterClass.NamedCompanion
with SHORTEN_AND_STAR_IMPORT:
[type] test.OuterClass.Nested
[type] test.OuterClass.NamedCompanion