diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/shortenRefs/FirShortenRefsTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/shortenRefs/FirShortenRefsTestGenerated.java
index e0c9819ff0a..f7579af856f 100644
--- a/idea/idea-fir/tests/org/jetbrains/kotlin/shortenRefs/FirShortenRefsTestGenerated.java
+++ b/idea/idea-fir/tests/org/jetbrains/kotlin/shortenRefs/FirShortenRefsTestGenerated.java
@@ -126,11 +126,6 @@ public class FirShortenRefsTestGenerated extends AbstractFirShortenRefsTest {
runTest("idea/testData/shortenRefsFir/calls/rootPackage.kt");
}
- @TestMetadata("rootPackageShortenFakeRootPackage.kt")
- public void testRootPackageShortenFakeRootPackage() throws Exception {
- runTest("idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt");
- }
-
@TestMetadata("selfReferencingFunction.kt")
public void testSelfReferencingFunction() throws Exception {
runTest("idea/testData/shortenRefsFir/calls/selfReferencingFunction.kt");
@@ -142,6 +137,24 @@ public class FirShortenRefsTestGenerated extends AbstractFirShortenRefsTest {
}
}
+ @TestMetadata("idea/testData/shortenRefsFir/fakeRootPackage")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class FakeRootPackage extends AbstractFirShortenRefsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTestWithMuting, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInFakeRootPackage() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/shortenRefsFir/fakeRootPackage"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
+ }
+
+ @TestMetadata("rootPackageShortenFakeRootPackage.kt")
+ public void testRootPackageShortenFakeRootPackage() throws Exception {
+ runTest("idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt");
+ }
+ }
+
@TestMetadata("idea/testData/shortenRefsFir/quailfiers")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirReferenceShortener.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirReferenceShortener.kt
index 23ab798fed2..40013c40c35 100644
--- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirReferenceShortener.kt
+++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirReferenceShortener.kt
@@ -11,6 +11,7 @@ import com.intellij.psi.SmartPsiElementPointer
import com.intellij.util.containers.addIfNotNull
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirElement
+import org.jetbrains.kotlin.fir.ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
@@ -209,6 +210,17 @@ internal class KtFirReferenceShortener(
if (availableClassifier == null || availableClassifier.isFromStarOrPackageImport) {
addTypeToImportAndShorten(mostTopLevelClassId.asSingleFqName(), mostTopLevelTypeElement)
+ } else {
+ addFakePackagePrefixToShortenIfPresent(mostTopLevelTypeElement)
+ }
+ }
+
+ private fun addFakePackagePrefixToShortenIfPresent(typeElement: KtUserType) {
+ val deepestTypeWithQualifier = typeElement.qualifiersWithSelf.last().parent as? KtUserType
+ ?: error("Type element should have at least one qualifier, instead it was ${typeElement.text}")
+
+ if (deepestTypeWithQualifier.hasFakeRootPrefix()) {
+ addTypeToShorten(deepestTypeWithQualifier)
}
}
@@ -260,11 +272,17 @@ internal class KtFirReferenceShortener(
val scopes = findScopesAtPosition(callExpression, namesToImport) ?: return
val availableCallables = findFunctionsInScopes(scopes, callableId.callableName)
- if (availableCallables.isEmpty()) {
- val additionalImport = callableId.asImportableFqName() ?: return
- addElementToImportAndShorten(additionalImport, qualifiedCallExpression)
- } else if (availableCallables.all { it.callableId == callableId }) {
- addElementToShorten(qualifiedCallExpression)
+ when {
+ availableCallables.isEmpty() -> {
+ val additionalImport = callableId.asImportableFqName() ?: return
+ addElementToImportAndShorten(additionalImport, qualifiedCallExpression)
+ }
+ availableCallables.all { it.callableId == callableId } -> {
+ addElementToShorten(qualifiedCallExpression)
+ }
+ else -> {
+ addFakePackagePrefixToShortenIfPresent(qualifiedCallExpression)
+ }
}
}
@@ -346,6 +364,15 @@ internal class KtFirReferenceShortener(
if (availableClassifier == null || availableClassifier.isFromStarOrPackageImport) {
addElementToImportAndShorten(mostTopLevelClassId.asSingleFqName(), mostTopLevelQualifier)
+ } else {
+ addFakePackagePrefixToShortenIfPresent(mostTopLevelQualifier)
+ }
+ }
+
+ private fun addFakePackagePrefixToShortenIfPresent(wholeQualifiedExpression: KtDotQualifiedExpression) {
+ val deepestQualifier = wholeQualifiedExpression.qualifiersWithSelf.last()
+ if (deepestQualifier.hasFakeRootPrefix()) {
+ addElementToShorten(deepestQualifier)
}
}
@@ -395,6 +422,12 @@ private class ShortenCommandImpl(
}
}
+private fun KtUserType.hasFakeRootPrefix(): Boolean =
+ qualifier?.referencedName == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
+
+private fun KtDotQualifiedExpression.hasFakeRootPrefix(): Boolean =
+ (receiverExpression as? KtNameReferenceExpression)?.getReferencedName() == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
+
private fun CallableId.asImportableFqName(): FqName? = if (classId == null) packageName.child(callableName) else null
private fun KtElement.getDotQualifiedExpressionForSelector(): KtDotQualifiedExpression? =
diff --git a/idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt b/idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt
deleted file mode 100644
index d890c3ea23a..00000000000
--- a/idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-// FIR_IGNORE
-package test
-
-fun test() {}
-
-fun usage() {
- fun test() {}
-
- _root_ide_package_.test.test()
-}
\ No newline at end of file
diff --git a/idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt b/idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt
new file mode 100644
index 00000000000..58fa8373070
--- /dev/null
+++ b/idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt
@@ -0,0 +1,18 @@
+// FIR_COMPARISON
+package test
+
+class Test
+
+fun test() {}
+
+fun usage() {
+ class Test
+
+ fun test() {}
+
+
+ _root_ide_package_.test.test()
+ _root_ide_package_.test.Test
+ val t: _root_ide_package_.test.Test
+
+}
\ No newline at end of file
diff --git a/idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt.after b/idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt.after
similarity index 59%
rename from idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt.after
rename to idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt.after
index ea300498b7a..6a5a5f26126 100644
--- a/idea/testData/shortenRefsFir/calls/rootPackageShortenFakeRootPackage.kt.after
+++ b/idea/testData/shortenRefsFir/fakeRootPackage/rootPackageShortenFakeRootPackage.kt.after
@@ -1,10 +1,18 @@
// FIR_COMPARISON
package test
+class Test
+
fun test() {}
fun usage() {
+ class Test
+
fun test() {}
+
test.test()
+ test.Test
+ val t: test.Test
+
}
\ No newline at end of file