FIR IDE: Add more accurate shortening for properties

This commit is contained in:
Roman Golyshev
2021-03-01 17:44:49 +03:00
parent 03a1c6fcca
commit 8392b36964
7 changed files with 42 additions and 9 deletions
@@ -101,6 +101,11 @@ public class FirShortenRefsTestGenerated extends AbstractFirShortenRefsTest {
runTest("idea/testData/shortenRefsFir/calls/notImportedTopLevelFunctionNoArgs.kt");
}
@TestMetadata("notImportedTopLevelProperty.kt")
public void testNotImportedTopLevelProperty() throws Exception {
runTest("idea/testData/shortenRefsFir/calls/notImportedTopLevelProperty.kt");
}
@TestMetadata("notImportedTopLevelTypeConstructorNoArgs.kt")
public void testNotImportedTopLevelTypeConstructorNoArgs() throws Exception {
runTest("idea/testData/shortenRefsFir/calls/notImportedTopLevelTypeConstructorNoArgs.kt");
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.getFunctions
import org.jetbrains.kotlin.fir.scopes.getProperties
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
@@ -120,8 +121,8 @@ private class FirShorteningContext(val firResolveState: FirModuleResolveState) {
return scopes.flatMap { it.getFunctions(name) }
}
fun findSinglePropertyInScopesByName(scopes: List<FirScope>, name: Name): FirVariableSymbol<*>? {
return scopes.asSequence().mapNotNull { it.getSinglePropertyByName(name) }.singleOrNull()
fun findPropertiesInScopes(scopes: List<FirScope>, name: Name): List<FirVariableSymbol<*>> {
return scopes.flatMap { it.getProperties(name) }
}
private fun FirScope.findFirstClassifierByName(name: Name): FirClassifierSymbol<*>? {
@@ -136,10 +137,6 @@ private class FirShorteningContext(val firResolveState: FirModuleResolveState) {
return element
}
@OptIn(ExperimentalStdlibApi::class)
private fun FirScope.getSinglePropertyByName(name: Name): FirVariableSymbol<*>? =
buildList { processPropertiesByName(name, this::add) }.singleOrNull()
@OptIn(ExperimentalStdlibApi::class)
fun findScopesAtPosition(position: KtElement, newImports: List<FqName>): List<FirScope>? {
val towerDataContext = firResolveState.getTowerDataContextForElement(position) ?: return null
@@ -316,11 +313,15 @@ private class ElementsToShortenCollector(private val shorteningContext: FirShort
val propertyId = (resolvedNamedReference.resolvedSymbol as? FirCallableSymbol<*>)?.callableId ?: return
val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, namesToImport) ?: return
val singleAvailableProperty = shorteningContext.findSinglePropertyInScopesByName(scopes, propertyId.callableName)
val singleAvailableProperty = shorteningContext.findPropertiesInScopes(scopes, propertyId.callableName)
if (singleAvailableProperty?.callableId == propertyId) {
addElementToShorten(ShortenQualifier(qualifiedProperty))
val propertyToShorten = when {
singleAvailableProperty.isEmpty() -> ShortenQualifier(qualifiedProperty, propertyId.asImportableFqName())
singleAvailableProperty.all { it.callableId == propertyId } -> ShortenQualifier(qualifiedProperty)
else -> findFakePackageToShorten(qualifiedProperty)
}
propertyToShorten?.let(::addElementToShorten)
}
private fun processFunctionCall(functionCall: FirFunctionCall) {
@@ -0,0 +1,3 @@
package dependency
val topLevelProperty = 10
@@ -0,0 +1,6 @@
// FIR_COMPARISON
package test
fun usage() {
<selection>dependency.topLevelProperty</selection>
}
@@ -0,0 +1,8 @@
// FIR_COMPARISON
package test
import dependency.topLevelProperty
fun usage() {
topLevelProperty
}
@@ -3,14 +3,19 @@ package test
class Test
val property: Int = 10
fun test() {}
fun usage() {
class Test
val property: String = ""
fun test() {}
<selection>
_root_ide_package_.test.property
_root_ide_package_.test.test()
_root_ide_package_.test.Test
val t: _root_ide_package_.test.Test
@@ -3,14 +3,19 @@ package test
class Test
val property: Int = 10
fun test() {}
fun usage() {
class Test
val property: String = ""
fun test() {}
test.property
test.test()
test.Test
val t: test.Test