KTIJ-27139 [AA] Shorten qualified expressions only when the callee/type reference is in selection

If you want to shorten call like `foo.bar()` into `bar()`, then you
need your range to intersect with `bar` callee reference. Having only
`foo` in the range is not enough

Same goes for the type references - to shorten `foo.Bar` into `Bar`, you
need at least some intersection of your range with `Bar` reference

^KTIJ-27139 Fixed
^KTIJ-27015 Fixed
This commit is contained in:
Roman Golyshev
2023-09-22 18:54:25 +02:00
committed by teamcity
parent ecbf69504a
commit d2fcd71d23
19 changed files with 244 additions and 6 deletions
@@ -468,9 +468,11 @@ private class ElementsToShortenCollector(
private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val typeElement = resolvedTypeRef.correspondingTypePsi ?: return
if (typeElement.referenceExpression?.textRange?.intersects(selection) != true) return
if (typeElement.qualifier == null) return
val typeReferenceTextRange = typeElement.referenceExpression?.textRange
if (typeReferenceTextRange?.intersects(selection) != true) return
val classifierId = resolvedTypeRef.type.lowerBoundIfFlexible().candidateClassId ?: return
findTypeQualifierToShorten(classifierId, typeElement)?.let(::addElementToShorten)
@@ -535,13 +537,16 @@ private class ElementsToShortenCollector(
val wholeClassQualifier = resolvedQualifier.classId ?: return
val qualifierPsi = resolvedQualifier.psi ?: return
if (!qualifierPsi.textRange.intersects(selection)) return
val wholeQualifierElement = when (qualifierPsi) {
is KtDotQualifiedExpression -> qualifierPsi
is KtNameReferenceExpression -> qualifierPsi.getDotQualifiedExpressionForSelector() ?: return
else -> return
}
val typeReferenceTextRange = wholeQualifierElement.selectorExpression?.textRange
if (typeReferenceTextRange?.intersects(selection) != true) return
findTypeQualifierToShorten(wholeClassQualifier, wholeQualifierElement)?.let(::addElementToShorten)
}
@@ -1028,9 +1033,11 @@ private class ElementsToShortenCollector(
if (!canBePossibleToDropReceiver(firPropertyAccess)) return
val propertyReferenceExpression = firPropertyAccess.correspondingNameReference ?: return
if (!propertyReferenceExpression.textRange.intersects(selection)) return
val qualifiedProperty = propertyReferenceExpression.getQualifiedElement() as? KtDotQualifiedExpression ?: return
val propertyReferenceTextRange = propertyReferenceExpression.textRange
if (!propertyReferenceTextRange.intersects(selection)) return
val propertySymbol = firPropertyAccess.referencedSymbol ?: return
val option = callableShortenOption(propertySymbol)
@@ -1075,8 +1082,7 @@ private class ElementsToShortenCollector(
val callExpression = qualifiedCallExpression.selectorExpression as? KtCallExpression ?: return
val calleeTextRange = callExpression.calleeExpression?.textRange
val qualifierTextRange = qualifiedCallExpression.receiverExpression.textRange
if (calleeTextRange?.intersects(selection) != true && !qualifierTextRange.intersects(selection)) return
if (calleeTextRange?.intersects(selection) != true) return
val calleeReference = functionCall.calleeReference
val calledSymbol = findUnambiguousReferencedCallableId(calleeReference) ?: return
@@ -340,6 +340,54 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall1.kt")
public void testPartiallySelectedQualifiedCall1() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall1.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall2.kt")
public void testPartiallySelectedQualifiedCall2() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall2.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall3.kt")
public void testPartiallySelectedQualifiedCall3() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall3.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall4.kt")
public void testPartiallySelectedQualifiedCall4() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall4.kt");
}
@Test
@TestMetadata("partiallySelectedType1.kt")
public void testPartiallySelectedType1() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedType1.kt");
}
@Test
@TestMetadata("partiallySelectedType2.kt")
public void testPartiallySelectedType2() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedType2.kt");
}
@Test
@TestMetadata("partiallySelectedTypeQualifier1.kt")
public void testPartiallySelectedTypeQualifier1() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedTypeQualifier1.kt");
}
@Test
@TestMetadata("partiallySelectedTypeQualifier2.kt")
public void testPartiallySelectedTypeQualifier2() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedTypeQualifier2.kt");
}
@Test
@TestMetadata("qualifierOfUnresolvedReference.kt")
public void testQualifierOfUnresolvedReference() throws Exception {
@@ -340,6 +340,54 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall1.kt")
public void testPartiallySelectedQualifiedCall1() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall1.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall2.kt")
public void testPartiallySelectedQualifiedCall2() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall2.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall3.kt")
public void testPartiallySelectedQualifiedCall3() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall3.kt");
}
@Test
@TestMetadata("partiallySelectedQualifiedCall4.kt")
public void testPartiallySelectedQualifiedCall4() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedQualifiedCall4.kt");
}
@Test
@TestMetadata("partiallySelectedType1.kt")
public void testPartiallySelectedType1() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedType1.kt");
}
@Test
@TestMetadata("partiallySelectedType2.kt")
public void testPartiallySelectedType2() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedType2.kt");
}
@Test
@TestMetadata("partiallySelectedTypeQualifier1.kt")
public void testPartiallySelectedTypeQualifier1() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedTypeQualifier1.kt");
}
@Test
@TestMetadata("partiallySelectedTypeQualifier2.kt")
public void testPartiallySelectedTypeQualifier2() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/partiallySelectedTypeQualifier2.kt");
}
@Test
@TestMetadata("qualifierOfUnresolvedReference.kt")
public void testQualifierOfUnresolvedReference() throws Exception {
@@ -0,0 +1,11 @@
// FILE: main.kt
package test
fun usage() {
<expr>dependency</expr>.foo()
}
// FILE: dependency.kt
package dependency
fun foo() {}
@@ -0,0 +1,5 @@
Before shortening: dependency
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
with SHORTEN_AND_STAR_IMPORT:
@@ -0,0 +1,11 @@
// FILE: main.kt
package test
fun usage() {
dependency.<expr>foo()</expr>
}
// FILE: dependency.kt
package dependency
fun foo() {}
@@ -0,0 +1,7 @@
Before shortening: foo()
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
[qualifier] dependency.foo()
with SHORTEN_AND_STAR_IMPORT:
[qualifier] dependency.foo()
@@ -0,0 +1,11 @@
// FILE: main.kt
package test
fun usage() {
<expr>dependency</expr>.foo()
}
// FILE: dependency.kt
package dependency
val foo: Int = 10
@@ -0,0 +1,5 @@
Before shortening: dependency
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
with SHORTEN_AND_STAR_IMPORT:
@@ -0,0 +1,11 @@
// FILE: main.kt
package test
fun usage() {
dependency.<expr>foo</expr>
}
// FILE: dependency.kt
package dependency
val foo: Int = 10
@@ -0,0 +1,7 @@
Before shortening: foo
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
[qualifier] dependency.foo
with SHORTEN_AND_STAR_IMPORT:
[qualifier] dependency.foo
@@ -0,0 +1,9 @@
// FILE: main.kt
package test
fun usage(foo: <expr>dependency</expr>.Foo) {}
// FILE: dependency.kt
package dependency
class Foo
@@ -0,0 +1,5 @@
Before shortening: dependency
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
with SHORTEN_AND_STAR_IMPORT:
@@ -0,0 +1,9 @@
// FILE: main.kt
package test
fun usage(foo: dependency.<expr>Foo</expr>) {}
// FILE: dependency.kt
package dependency
class Foo
@@ -0,0 +1,7 @@
Before shortening: Foo
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
[type] dependency.Foo
with SHORTEN_AND_STAR_IMPORT:
[type] dependency.Foo
@@ -0,0 +1,13 @@
// FILE: main.kt
package test
fun usage() {
<expr>dependency</expr>.Foo.bar()
}
// FILE: dependency.kt
package dependency
object Foo {
fun bar() {}
}
@@ -0,0 +1,5 @@
Before shortening: dependency
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
with SHORTEN_AND_STAR_IMPORT:
@@ -0,0 +1,13 @@
// FILE: main.kt
package test
fun usage() {
dependency.<expr>Foo</expr>.bar()
}
// FILE: dependency.kt
package dependency
object Foo {
fun bar() {}
}
@@ -0,0 +1,7 @@
Before shortening: Foo
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
[qualifier] dependency.Foo
with SHORTEN_AND_STAR_IMPORT:
[qualifier] dependency.Foo