diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt
index d8266e72870..ef3931c8933 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
import org.jetbrains.kotlin.fir.expressions.builder.buildPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
-import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
@@ -601,8 +600,15 @@ private class ElementsToShortenCollector(
// If its parent has a type parameter, we cannot shorten it because it will lose its type parameter.
if (classSymbol.hasTypeParameterFromParent()) return false
+ /**
+ * Class use-site member scopes may contain classifiers which are not actually available without explicit import.
+ *
+ * See KTIJ-24684 and KTIJ-24662 for examples.
+ */
+ val scopes = positionScopes.filterNot { it is FirClassUseSiteMemberScope }
+
val name = classId.shortClassName
- val availableClassifiers = shorteningContext.findClassifiersInScopesByName(positionScopes, name)
+ val availableClassifiers = shorteningContext.findClassifiersInScopesByName(scopes, name)
val matchingAvailableSymbol = availableClassifiers.firstOrNull { it.availableSymbol.symbol == classId }
val scopeForClass = matchingAvailableSymbol?.scope ?: return false
@@ -618,7 +624,7 @@ private class ElementsToShortenCollector(
* my.component.foo::class.java // If we drop `my.component`, it will reference `B` instead of `A`
* }
*/
- if (shorteningContext.findPropertiesInScopes(positionScopes, name).isNotEmpty()) {
+ if (shorteningContext.findPropertiesInScopes(scopes, name).isNotEmpty()) {
val firForElement = element.getOrBuildFir(firResolveSession) as? FirQualifiedAccessExpression
val typeArguments = firForElement?.typeArguments ?: emptyList()
val qualifiedAccessCandidates = findCandidatesForPropertyAccess(classSymbol.annotations, typeArguments, name, element)
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
index 770525932d9..780b1df440c 100644
--- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
@@ -196,6 +196,42 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt");
}
+ @Test
+ @TestMetadata("nestedClassFromSupertypes.kt")
+ public void testNestedClassFromSupertypes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes2.kt")
+ public void testNestedClassFromSupertypes2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes3.kt")
+ public void testNestedClassFromSupertypes3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes4.kt")
+ public void testNestedClassFromSupertypes4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes5.kt")
+ public void testNestedClassFromSupertypes5() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes6.kt")
+ public void testNestedClassFromSupertypes6() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.kt");
+ }
+
@Test
@TestMetadata("parameterTypeTopLevelTypeLoses.kt")
public void testParameterTypeTopLevelTypeLoses() throws Exception {
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
index a74cddec90e..21c5f6d45e0 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
@@ -196,6 +196,42 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt");
}
+ @Test
+ @TestMetadata("nestedClassFromSupertypes.kt")
+ public void testNestedClassFromSupertypes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes2.kt")
+ public void testNestedClassFromSupertypes2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes3.kt")
+ public void testNestedClassFromSupertypes3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes4.kt")
+ public void testNestedClassFromSupertypes4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes5.kt")
+ public void testNestedClassFromSupertypes5() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClassFromSupertypes6.kt")
+ public void testNestedClassFromSupertypes6() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.kt");
+ }
+
@Test
@TestMetadata("parameterTypeTopLevelTypeLoses.kt")
public void testParameterTypeTopLevelTypeLoses() throws Exception {
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.kt
new file mode 100644
index 00000000000..487561528ae
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.kt
@@ -0,0 +1,9 @@
+// FILE: main.kt
+
+interface MyInterface {
+ class Nested
+}
+
+class Foo : MyInterface {
+ val prop: MyInterface.Nested = MyInterface.Nested()
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.txt
new file mode 100644
index 00000000000..75e85c4b526
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes.txt
@@ -0,0 +1,9 @@
+Before shortening: val prop: MyInterface.Nested = MyInterface.Nested()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
+with SHORTEN_AND_STAR_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.kt
new file mode 100644
index 00000000000..f0cd04008bd
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.kt
@@ -0,0 +1,10 @@
+// FILE: main.kt
+import MyInterface.Nested
+
+interface MyInterface {
+ class Nested
+}
+
+class Foo : MyInterface {
+ val prop: MyInterface.Nested = MyInterface.Nested()
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.txt
new file mode 100644
index 00000000000..d852fea443e
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes2.txt
@@ -0,0 +1,11 @@
+Before shortening: val prop: MyInterface.Nested = MyInterface.Nested()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
+with SHORTEN_AND_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
+with SHORTEN_AND_STAR_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.kt
new file mode 100644
index 00000000000..293e78dfa83
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.kt
@@ -0,0 +1,8 @@
+// FILE: main.kt
+open class MyBaseClass {
+ class Nested
+}
+
+class Foo : MyBaseClass() {
+ val prop: MyBaseClass.Nested = MyBaseClass.Nested()
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.txt
new file mode 100644
index 00000000000..6c1430ef188
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes3.txt
@@ -0,0 +1,11 @@
+Before shortening: val prop: MyBaseClass.Nested = MyBaseClass.Nested()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[type] MyBaseClass.Nested
+[qualifier] MyBaseClass.Nested()
+with SHORTEN_AND_IMPORT:
+[type] MyBaseClass.Nested
+[qualifier] MyBaseClass.Nested()
+with SHORTEN_AND_STAR_IMPORT:
+[type] MyBaseClass.Nested
+[qualifier] MyBaseClass.Nested()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.kt
new file mode 100644
index 00000000000..6a88bb4f63a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.kt
@@ -0,0 +1,6 @@
+// FILE: main.kt
+interface MyInterface {
+ class Nested
+
+ val prop: MyInterface.Nested get() = MyInterface.Nested()
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.txt
new file mode 100644
index 00000000000..3d4f1bf538c
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes4.txt
@@ -0,0 +1,11 @@
+Before shortening: val prop: MyInterface.Nested get() = MyInterface.Nested()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
+with SHORTEN_AND_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
+with SHORTEN_AND_STAR_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.kt
new file mode 100644
index 00000000000..716f60b9ba2
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.kt
@@ -0,0 +1,8 @@
+// FILE: main.kt
+interface MyInterface {
+ class Nested
+}
+
+fun MyInterface.foo() {
+ val prop: MyInterface.Nested = MyInterface.Nested()
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.txt
new file mode 100644
index 00000000000..75e85c4b526
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes5.txt
@@ -0,0 +1,9 @@
+Before shortening: val prop: MyInterface.Nested = MyInterface.Nested()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
+with SHORTEN_AND_STAR_IMPORT:
+[type] MyInterface.Nested
+[qualifier] MyInterface.Nested()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.kt
new file mode 100644
index 00000000000..cf92cd81506
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.kt
@@ -0,0 +1,8 @@
+// FILE: main.kt
+open class MyBaseClass {
+ class Nested
+}
+
+fun MyBaseClass.foo() {
+ val prop: MyBaseClass.Nested = MyBaseClass.Nested()
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.txt
new file mode 100644
index 00000000000..6e35eb2a1f4
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClassFromSupertypes6.txt
@@ -0,0 +1,9 @@
+Before shortening: val prop: MyBaseClass.Nested = MyBaseClass.Nested()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[type] MyBaseClass.Nested
+[qualifier] MyBaseClass.Nested()
+with SHORTEN_AND_STAR_IMPORT:
+[type] MyBaseClass.Nested
+[qualifier] MyBaseClass.Nested()