KTIJ-26627 [AA] Correctly handle object receivers of property accesses

Also remove redundant code from `canBePossibleToDropReceiver`

^KTIJ-26627 Fixed
This commit is contained in:
Roman Golyshev
2023-08-13 20:21:44 +02:00
parent 2db8f31966
commit b52d3c114f
7 changed files with 63 additions and 11 deletions
@@ -30,7 +30,6 @@ 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.utils.printer.parentsOfType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.declarations.*
@@ -985,6 +984,9 @@ private class ElementsToShortenCollector(
}
private fun processPropertyAccess(firPropertyAccess: FirPropertyAccessExpression) {
// if explicit receiver is a property access or a function call, we cannot shorten it
if (!canBePossibleToDropReceiver(firPropertyAccess)) return
val propertyReferenceExpression = firPropertyAccess.correspondingNameReference ?: return
if (!propertyReferenceExpression.textRange.intersects(selection)) return
@@ -996,10 +998,6 @@ private class ElementsToShortenCollector(
val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, getNamesToImport(), towerContextProvider) ?: return
val availableCallables = shorteningContext.findPropertiesInScopes(scopes, propertySymbol.name)
// if explicit receiver is a property access or a function call, we cannot shorten it
if (firPropertyAccess.explicitReceiver !is FirResolvedQualifier) return
if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(firPropertyAccess, propertySymbol, qualifiedProperty)) {
addElementToShorten(ShortenQualifier(qualifiedProperty))
return
@@ -1100,15 +1098,12 @@ private class ElementsToShortenCollector(
callToShorten?.let(::addElementToShorten)
}
private fun canBePossibleToDropReceiver(functionCall: FirFunctionCall): Boolean {
private fun canBePossibleToDropReceiver(qualifiedAccess: FirQualifiedAccessExpression): Boolean {
// we can remove receiver only if it is a qualifier
val explicitReceiver = functionCall.explicitReceiver as? FirResolvedQualifier ?: return false
if (qualifiedAccess.explicitReceiver !is FirResolvedQualifier) return false
// if there is no extension receiver necessary, then it can be removed
if (functionCall.extensionReceiver is FirNoReceiverExpression) return true
val receiverType = shorteningContext.getRegularClass(explicitReceiver.typeRef) ?: return true
return receiverType.classKind != ClassKind.OBJECT
return qualifiedAccess.extensionReceiver is FirNoReceiverExpression
}
private fun findUnambiguousReferencedCallableId(namedReference: FirNamedReference): FirCallableSymbol<*>? {
@@ -244,6 +244,18 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt");
}
@Test
@TestMetadata("extensionFunction_objectReceiverWithOtherThisInScope.kt")
public void testExtensionFunction_objectReceiverWithOtherThisInScope() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFunction_objectReceiverWithOtherThisInScope.kt");
}
@Test
@TestMetadata("extensionProperty_objectReceiverWithOtherThisInScope.kt")
public void testExtensionProperty_objectReceiverWithOtherThisInScope() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionProperty_objectReceiverWithOtherThisInScope.kt");
}
@Test
@TestMetadata("kdoc.kt")
public void testKdoc() throws Exception {
@@ -244,6 +244,18 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt");
}
@Test
@TestMetadata("extensionFunction_objectReceiverWithOtherThisInScope.kt")
public void testExtensionFunction_objectReceiverWithOtherThisInScope() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFunction_objectReceiverWithOtherThisInScope.kt");
}
@Test
@TestMetadata("extensionProperty_objectReceiverWithOtherThisInScope.kt")
public void testExtensionProperty_objectReceiverWithOtherThisInScope() throws Exception {
runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionProperty_objectReceiverWithOtherThisInScope.kt");
}
@Test
@TestMetadata("kdoc.kt")
public void testKdoc() throws Exception {
@@ -0,0 +1,11 @@
package test
fun <T> T.extFun(): T = this
object Bar
class Other
fun Other.usage() {
<expr>Bar.extFun()</expr>
}
@@ -0,0 +1,5 @@
Before shortening: Bar.extFun()
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
with SHORTEN_AND_STAR_IMPORT:
@@ -0,0 +1,12 @@
package test
val <T> T.extProperty: T
get() = this
object Bar
class Other
fun Other.usage() {
<expr>Bar.extProperty</expr>
}
@@ -0,0 +1,5 @@
Before shortening: Bar.extProperty
with DO_NOT_SHORTEN:
with SHORTEN_IF_ALREADY_IMPORTED:
with SHORTEN_AND_IMPORT:
with SHORTEN_AND_STAR_IMPORT: