FIR IDE: Implement shortening and import for type qualifiers
This commit is contained in:
+38
@@ -87,6 +87,44 @@ public class FirShortenRefsTestGenerated extends AbstractFirShortenRefsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/shortenRefsFir/quailfiers")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Quailfiers extends AbstractFirShortenRefsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTestWithMuting, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInQuailfiers() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/shortenRefsFir/quailfiers"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("AlreadyImportedNestedType.kt")
|
||||
public void testAlreadyImportedNestedType() throws Exception {
|
||||
runTest("idea/testData/shortenRefsFir/quailfiers/AlreadyImportedNestedType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("NestedTypeInSameFile.kt")
|
||||
public void testNestedTypeInSameFile() throws Exception {
|
||||
runTest("idea/testData/shortenRefsFir/quailfiers/NestedTypeInSameFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("NotImportedNestedType.kt")
|
||||
public void testNotImportedNestedType() throws Exception {
|
||||
runTest("idea/testData/shortenRefsFir/quailfiers/NotImportedNestedType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("NotImportedTopLevelType.kt")
|
||||
public void testNotImportedTopLevelType() throws Exception {
|
||||
runTest("idea/testData/shortenRefsFir/quailfiers/NotImportedTopLevelType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("TopLevelTypeInSameFile.kt")
|
||||
public void testTopLevelTypeInSameFile() throws Exception {
|
||||
runTest("idea/testData/shortenRefsFir/quailfiers/TopLevelTypeInSameFile.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/shortenRefsFir/types")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+57
-3
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
@@ -179,8 +180,8 @@ internal class KtFirReferenceShortener(
|
||||
}
|
||||
|
||||
private fun collectTypeIfNeedsToBeShortened(wholeClassifierId: ClassId, wholeTypeElement: KtUserType) {
|
||||
val allClassIds = generateSequence(wholeClassifierId) { it.outerClassId }
|
||||
val allTypeElements = generateSequence(wholeTypeElement) { it.qualifier }
|
||||
val allClassIds = wholeClassifierId.outerClassesWithSelf
|
||||
val allTypeElements = wholeTypeElement.qualifiersWithSelf
|
||||
|
||||
val positionScopes = findScopesAtPosition(wholeTypeElement, namesToImport) ?: return
|
||||
|
||||
@@ -218,7 +219,7 @@ internal class KtFirReferenceShortener(
|
||||
}
|
||||
|
||||
private inner class CallsCollectingVisitor(
|
||||
private val namesToImport: List<FqName>,
|
||||
private val namesToImport: MutableList<FqName>,
|
||||
private val callsToShorten: MutableList<KtDotQualifiedExpression>
|
||||
) : FirVisitorVoid() {
|
||||
override fun visitElement(element: FirElement) {
|
||||
@@ -258,10 +259,63 @@ internal class KtFirReferenceShortener(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
|
||||
super.visitResolvedQualifier(resolvedQualifier)
|
||||
|
||||
val wholeClassQualifier = resolvedQualifier.classId ?: return
|
||||
val wholeQualifierElement = when (val qualifierPsi = resolvedQualifier.psi) {
|
||||
is KtDotQualifiedExpression -> qualifierPsi
|
||||
is KtNameReferenceExpression -> qualifierPsi.parent as? KtDotQualifiedExpression ?: return
|
||||
else -> return
|
||||
}
|
||||
|
||||
collectQualifierIfNeedsToBeShortened(wholeClassQualifier, wholeQualifierElement)
|
||||
}
|
||||
|
||||
private fun collectQualifierIfNeedsToBeShortened(wholeClassQualifier: ClassId, wholeQualifierElement: KtDotQualifiedExpression) {
|
||||
val positionScopes = findScopesAtPosition(wholeQualifierElement, namesToImport) ?: return
|
||||
|
||||
val allClassIds = wholeClassQualifier.outerClassesWithSelf
|
||||
val allQualifiers = wholeQualifierElement.qualifiersWithSelf
|
||||
|
||||
for ((classId, qualifier) in allClassIds.zip(allQualifiers)) {
|
||||
val firstFoundClass = findFirstClassifierInScopesByName(positionScopes, classId.shortClassName)?.classId
|
||||
|
||||
if (firstFoundClass == classId) {
|
||||
addElementToShorten(qualifier)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val (mostTopLevelClassId, mostTopLevelQualifier) = allClassIds.zip(allQualifiers).last()
|
||||
val availableClassifier = findFirstClassifierInScopesByName(positionScopes, mostTopLevelClassId.shortClassName)
|
||||
|
||||
check(availableClassifier?.classId != mostTopLevelClassId) { "This should not be true" }
|
||||
|
||||
if (availableClassifier == null || availableClassifier.isFromStarOrPackageImport) {
|
||||
addElementToImportAndShorten(mostTopLevelClassId.asSingleFqName(), mostTopLevelQualifier)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addElementToShorten(element: KtDotQualifiedExpression) {
|
||||
callsToShorten.add(element)
|
||||
}
|
||||
|
||||
private fun addElementToImportAndShorten(nameToImport: FqName, element: KtDotQualifiedExpression) {
|
||||
namesToImport.add(nameToImport)
|
||||
callsToShorten.add(element)
|
||||
}
|
||||
}
|
||||
|
||||
private val ClassId.outerClassesWithSelf: Sequence<ClassId>
|
||||
get() = generateSequence(this) { it.outerClassId }
|
||||
|
||||
private val KtUserType.qualifiersWithSelf: Sequence<KtUserType>
|
||||
get() = generateSequence(this) { it.qualifier }
|
||||
|
||||
private val KtDotQualifiedExpression.qualifiersWithSelf: Sequence<KtDotQualifiedExpression>
|
||||
get() = generateSequence(this) { it.receiverExpression as? KtDotQualifiedExpression }
|
||||
}
|
||||
|
||||
private class ShortenCommandImpl(
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package dependency
|
||||
|
||||
class T {
|
||||
class TT
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
import dependency.T
|
||||
import dependency.T.TT
|
||||
|
||||
fun usage() {
|
||||
<selection>
|
||||
dependency.T.TT
|
||||
T.TT
|
||||
</selection>
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
import dependency.T
|
||||
import dependency.T.TT
|
||||
|
||||
fun usage() {
|
||||
|
||||
TT
|
||||
TT
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
class A {
|
||||
class AA
|
||||
}
|
||||
|
||||
fun usage() {
|
||||
<selection>test.A.AA</selection>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
class A {
|
||||
class AA
|
||||
}
|
||||
|
||||
fun usage() {
|
||||
A.AA
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package dependency
|
||||
|
||||
class T {
|
||||
class TT
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
fun usage() {
|
||||
<selection>dependency.T.TT</selection>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
import dependency.T
|
||||
|
||||
fun usage() {
|
||||
T.TT
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
class T
|
||||
@@ -0,0 +1,6 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
fun usage() {
|
||||
<selection>dependency.T</selection>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
import dependency.T
|
||||
|
||||
fun usage() {
|
||||
T
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
class A
|
||||
|
||||
fun usage() {
|
||||
<selection>test.A</selection>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// FIR_COMPARISON
|
||||
package test
|
||||
|
||||
class A
|
||||
|
||||
fun usage() {
|
||||
A
|
||||
}
|
||||
Reference in New Issue
Block a user