FIR IDE: Add import in case when conflicting class comes from * import

This commit is contained in:
Roman Golyshev
2020-12-24 20:08:23 +03:00
committed by Space
parent 0b48416a1e
commit f03ca5ea57
7 changed files with 41 additions and 8 deletions
@@ -66,6 +66,11 @@ public class FirShortenRefsTestGenerated extends AbstractFirShortenRefsTest {
runTest("idea/testData/shortenRefsFir/types/ParameterTypeGenericTypes.kt"); runTest("idea/testData/shortenRefsFir/types/ParameterTypeGenericTypes.kt");
} }
@TestMetadata("ParameterTypeImplicitImportBeatsStarImport.kt")
public void testParameterTypeImplicitImportBeatsStarImport() throws Exception {
runTest("idea/testData/shortenRefsFir/types/ParameterTypeImplicitImportBeatsStarImport.kt");
}
@TestMetadata("ParameterTypeImportedNestedClass.kt") @TestMetadata("ParameterTypeImportedNestedClass.kt")
public void testParameterTypeImportedNestedClass() throws Exception { public void testParameterTypeImportedNestedClass() throws Exception {
runTest("idea/testData/shortenRefsFir/types/ParameterTypeImportedNestedClass.kt"); runTest("idea/testData/shortenRefsFir/types/ParameterTypeImportedNestedClass.kt");
@@ -15,12 +15,15 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.classId import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir
@@ -60,12 +63,17 @@ internal class KtFirReferenceShortener(
) )
} }
private fun findFirstClassifierInScopesByName(positionScopes: List<FirScope>, targetClassName: Name): ClassId? { private data class AvailableClassifier(val classId: ClassId, val isFromStarOrPackageImport: Boolean)
private fun findFirstClassifierInScopesByName(positionScopes: List<FirScope>, targetClassName: Name): AvailableClassifier? {
for (scope in positionScopes) { for (scope in positionScopes) {
val classifierSymbol = scope.findFirstClassifierByName(targetClassName) ?: continue val classifierSymbol = scope.findFirstClassifierByName(targetClassName) ?: continue
val classifierLookupTag = classifierSymbol.toLookupTag() as? ConeClassLikeLookupTag ?: continue val classifierLookupTag = classifierSymbol.toLookupTag() as? ConeClassLikeLookupTag ?: continue
return classifierLookupTag.classId return AvailableClassifier(
classifierLookupTag.classId,
isFromStarOrPackageImport = scope is FirAbstractStarImportingScope || scope is FirPackageMemberScope
)
} }
return null return null
@@ -137,7 +145,7 @@ internal class KtFirReferenceShortener(
private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) { private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val wholeTypeReference = resolvedTypeRef.psi as? KtTypeReference ?: return val wholeTypeReference = resolvedTypeRef.psi as? KtTypeReference ?: return
val wholeClassifierId = resolvedTypeRef.type.classId ?: return val wholeClassifierId = resolvedTypeRef.type.lowerBoundIfFlexible().classId ?: return
val wholeTypeElement = wholeTypeReference.typeElement.unwrapNullable() as? KtUserType ?: return val wholeTypeElement = wholeTypeReference.typeElement.unwrapNullable() as? KtUserType ?: return
if (wholeTypeElement.qualifier == null) return if (wholeTypeElement.qualifier == null) return
@@ -152,7 +160,7 @@ internal class KtFirReferenceShortener(
val positionScopes = findScopesAtPosition(wholeTypeElement, typesToImport) ?: return val positionScopes = findScopesAtPosition(wholeTypeElement, typesToImport) ?: return
for ((classId, typeElement) in allClassIds.zip(allTypeElements)) { for ((classId, typeElement) in allClassIds.zip(allTypeElements)) {
val firstFoundClass = findFirstClassifierInScopesByName(positionScopes, classId.shortClassName) val firstFoundClass = findFirstClassifierInScopesByName(positionScopes, classId.shortClassName)?.classId
if (firstFoundClass == classId) { if (firstFoundClass == classId) {
addTypeToShorten(typeElement) addTypeToShorten(typeElement)
@@ -162,11 +170,11 @@ internal class KtFirReferenceShortener(
// none class matched // none class matched
val (mostTopLevelClassId, mostTopLevelTypeElement) = allClassIds.zip(allTypeElements).last() val (mostTopLevelClassId, mostTopLevelTypeElement) = allClassIds.zip(allTypeElements).last()
val firstFoundClass = findFirstClassifierInScopesByName(positionScopes, mostTopLevelClassId.shortClassName) val availableClassifier = findFirstClassifierInScopesByName(positionScopes, mostTopLevelClassId.shortClassName)
check(firstFoundClass != mostTopLevelClassId) { "This should not be true" } check(availableClassifier?.classId != mostTopLevelClassId) { "This should not be true" }
if (firstFoundClass == null) { if (availableClassifier == null || availableClassifier.isFromStarOrPackageImport) {
addTypeToImportAndShorten(mostTopLevelClassId.asSingleFqName(), mostTopLevelTypeElement) addTypeToImportAndShorten(mostTopLevelClassId.asSingleFqName(), mostTopLevelTypeElement)
} }
} }
@@ -0,0 +1,3 @@
package dependency1
class T
@@ -0,0 +1,3 @@
package dependency2
class T
@@ -0,0 +1,6 @@
// FIR_COMPARISON
package test
import dependency1.*
<selection>fun foo(t: dependency2.T) {}</selection>
@@ -0,0 +1,7 @@
// FIR_COMPARISON
package test
import dependency1.*
import dependency2.T
fun foo(t: T) {}
@@ -2,7 +2,8 @@
package test package test
import dependency.* import dependency.*
import dependency.T
class T class T
fun foo(t: dependency.T) {} fun foo(t: T) {}