KT-60957 [Analysis API] Visit FirPropertyAccessExpressions instead of FirResolvedNamedReferences

It's much easier to analyze complex cases like invoke operator calls
using dedicated `FirPropertyAccessExpression`
This commit is contained in:
Roman Golyshev
2023-08-07 23:14:11 +02:00
committed by teamcity
parent b0b2e76e13
commit 7633e6e6f1
@@ -404,18 +404,18 @@ private class ElementsToShortenCollector(
processTypeQualifier(errorResolvedQualifier) processTypeQualifier(errorResolvedQualifier)
} }
override fun visitResolvedNamedReference(resolvedNamedReference: FirResolvedNamedReference) {
super.visitResolvedNamedReference(resolvedNamedReference)
processPropertyReference(resolvedNamedReference)
}
override fun visitFunctionCall(functionCall: FirFunctionCall) { override fun visitFunctionCall(functionCall: FirFunctionCall) {
super.visitFunctionCall(functionCall) super.visitFunctionCall(functionCall)
processFunctionCall(functionCall) processFunctionCall(functionCall)
} }
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
super.visitPropertyAccessExpression(propertyAccessExpression)
processPropertyAccess(propertyAccessExpression)
}
private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) { private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val typeElement = resolvedTypeRef.correspondingTypePsi ?: return val typeElement = resolvedTypeRef.correspondingTypePsi ?: return
if (typeElement.referenceExpression?.textRange?.intersects(selection) != true) return if (typeElement.referenceExpression?.textRange?.intersects(selection) != true) return
@@ -984,46 +984,38 @@ private class ElementsToShortenCollector(
return false return false
} }
private fun processPropertyReference(resolvedNamedReference: FirResolvedNamedReference) { private fun processPropertyAccess(firPropertyAccess: FirPropertyAccessExpression) {
val referenceExpression = resolvedNamedReference.psi as? KtNameReferenceExpression ?: return val propertyReferenceExpression = (firPropertyAccess.psi as? KtDotQualifiedExpression)?.selectorExpression as? KtNameReferenceExpression ?: return
if (!referenceExpression.textRange.intersects(selection)) return if (!propertyReferenceExpression.textRange.intersects(selection)) return
val qualifiedProperty = referenceExpression.getDotQualifiedExpressionForSelector() ?: return
val callableSymbol = resolvedNamedReference.resolvedSymbol as? FirCallableSymbol<*> ?: return val qualifiedProperty = propertyReferenceExpression.getQualifiedElement() as? KtDotQualifiedExpression ?: return
val propertySymbol = firPropertyAccess.referencedSymbol ?: return
val option = callableShortenOption(callableSymbol) val option = callableShortenOption(propertySymbol)
if (option == ShortenOption.DO_NOT_SHORTEN) return if (option == ShortenOption.DO_NOT_SHORTEN) return
val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, getNamesToImport(), towerContextProvider) ?: return val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, getNamesToImport(), towerContextProvider) ?: return
val availableCallables = shorteningContext.findPropertiesInScopes(scopes, callableSymbol.name) val availableCallables = shorteningContext.findPropertiesInScopes(scopes, propertySymbol.name)
val firPropertyAccess = qualifiedProperty.getCorrespondingPropertyAccessExpression() ?: return
// if explicit receiver is a property access or a function call, we cannot shorten it // if explicit receiver is a property access or a function call, we cannot shorten it
if (firPropertyAccess.explicitReceiver !is FirResolvedQualifier) return if (firPropertyAccess.explicitReceiver !is FirResolvedQualifier) return
if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(firPropertyAccess, callableSymbol, referenceExpression)) { if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(firPropertyAccess, propertySymbol, qualifiedProperty)) {
addElementToShorten(ShortenQualifier(qualifiedProperty)) addElementToShorten(ShortenQualifier(qualifiedProperty))
return return
} }
if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) return if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) return
processCallableQualifiedAccess( processCallableQualifiedAccess(
callableSymbol, propertySymbol,
option, option,
qualifiedProperty, qualifiedProperty,
availableCallables, availableCallables,
) )
} }
private fun KtDotQualifiedExpression.getCorrespondingPropertyAccessExpression(): FirPropertyAccessExpression? { private val FirPropertyAccessExpression.referencedSymbol: FirVariableSymbol<*>?
val accessExpression = when (val fir = getOrBuildFir(firResolveSession)) { get() = (calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirVariableSymbol<*>
is FirVariableAssignment -> fir.unwrapLValue()
else -> fir
}
return accessExpression as? FirPropertyAccessExpression
}
private fun processFunctionCall(functionCall: FirFunctionCall) { private fun processFunctionCall(functionCall: FirFunctionCall) {
if (!canBePossibleToDropReceiver(functionCall)) return if (!canBePossibleToDropReceiver(functionCall)) return