diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt index e461d6ab0ee..1cc22967872 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.api.fir.components import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.SmartPsiElementPointer import org.jetbrains.kotlin.analysis.api.components.KtReferenceShortener @@ -146,8 +147,6 @@ private enum class ImportKind { infix fun hasHigherPriorityThan(that: ImportKind): Boolean = this < that - val canBeOverwrittenByExplicitImport: Boolean get() = DEFAULT_EXPLICIT hasHigherPriorityThan this - companion object { fun fromScope(scope: FirScope): ImportKind { return when (scope) { @@ -662,6 +661,9 @@ private class ElementsToShortenCollector( } if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) continue + val importAllInParent = option == ShortenOption.SHORTEN_AND_STAR_IMPORT + if (importAffectsUsagesOfClassesWithSameName(classId, element.containingKtFile, importAllInParent)) continue + // Find class with the same name that's already available in this file. val availableClassifier = shorteningContext.findFirstClassifierInScopesByName(positionScopes, classId.shortClassName) @@ -672,33 +674,70 @@ private class ElementsToShortenCollector( return createElementToShorten( element, classId.asSingleFqName(), - option == ShortenOption.SHORTEN_AND_STAR_IMPORT + importAllInParent ) } // The class with name `classId.shortClassName` happens to be the same class referenced by this qualified access. availableClassifier.symbol == classId -> { // Respect caller's request to use star import, if it's not already star-imported. return when { - availableClassifier.importKind == ImportKind.EXPLICIT && option == ShortenOption.SHORTEN_AND_STAR_IMPORT -> { - createElementToShorten(element, classId.asSingleFqName(), true) + availableClassifier.importKind == ImportKind.EXPLICIT && importAllInParent -> { + createElementToShorten(element, classId.asSingleFqName(), importAllInParent) } // Otherwise, just shorten it and don't alter import statements else -> createElementToShorten(element, null, false) } } - // Allow using star import to overwrite members implicitly imported by default. - availableClassifier.importKind == ImportKind.DEFAULT_STAR && option == ShortenOption.SHORTEN_AND_STAR_IMPORT -> { - return createElementToShorten(element, classId.asSingleFqName(), true) - } - // Allow using explicit import to overwrite members star-imported or in package - availableClassifier.importKind.canBeOverwrittenByExplicitImport && option == ShortenOption.SHORTEN_AND_IMPORT -> { - return createElementToShorten(element, classId.asSingleFqName(), false) + importedClassifierOverwritesAvailableClassifier(availableClassifier, importAllInParent) -> { + return createElementToShorten(element, classId.asSingleFqName(), importAllInParent) } } } return findFakePackageToShortenFn(allQualifiedElements.last()) } + private fun importedClassifierOverwritesAvailableClassifier( + availableClassifier: AvailableSymbol, + importAllInParent: Boolean + ): Boolean { + val importKindFromOption = if (importAllInParent) ImportKind.STAR else ImportKind.EXPLICIT + return importKindFromOption.hasHigherPriorityThan(availableClassifier.importKind) + } + + private fun importAffectsUsagesOfClassesWithSameName(classToImport: ClassId, file: KtFile, importAllInParent: Boolean): Boolean { + var importAffectsUsages = false + + file.accept(object : KtVisitorVoid() { + override fun visitElement(element: PsiElement) { + element.acceptChildren(this) + } + + override fun visitImportList(importList: KtImportList) {} + + override fun visitPackageDirective(directive: KtPackageDirective) {} + + override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { + if (importAffectsUsages) return + if (KtPsiUtil.isSelectorInQualified(expression)) return + + val shortClassName = classToImport.shortClassName + if (expression.getReferencedNameAsName() != shortClassName) return + + val contextProvider = LowLevelFirApiFacadeForResolveOnAir.getOnAirGetTowerContextProvider(firResolveSession, expression) + val positionScopes = shorteningContext.findScopesAtPosition(expression, getNamesToImport(), contextProvider) ?: return + val availableClassifier = shorteningContext.findFirstClassifierInScopesByName(positionScopes, shortClassName) ?: return + when { + availableClassifier.symbol == classToImport -> return + importedClassifierOverwritesAvailableClassifier(availableClassifier, importAllInParent) -> { + importAffectsUsages = true + } + } + } + }) + + return importAffectsUsages + } + private fun resolveUnqualifiedAccess( fullyQualifiedAccess: FirQualifiedAccessExpression, name: Name, diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java index 6533580fbe4..73226637934 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java @@ -94,6 +94,18 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt"); } + @Test + @TestMetadata("classesWithSameName10.kt") + public void testClassesWithSameName10() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.kt"); + } + + @Test + @TestMetadata("classesWithSameName11.kt") + public void testClassesWithSameName11() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.kt"); + } + @Test @TestMetadata("classesWithSameName2.kt") public void testClassesWithSameName2() throws Exception { diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java index eb2c9c47ffa..b4f0d1e5d1b 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java @@ -94,6 +94,18 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt"); } + @Test + @TestMetadata("classesWithSameName10.kt") + public void testClassesWithSameName10() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.kt"); + } + + @Test + @TestMetadata("classesWithSameName11.kt") + public void testClassesWithSameName11() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.kt"); + } + @Test @TestMetadata("classesWithSameName2.kt") public void testClassesWithSameName2() throws Exception { diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.kt new file mode 100644 index 00000000000..f779d47efbf --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.kt @@ -0,0 +1,8 @@ +// FILE: main.kt +class SortedSet + +fun test() { + val a = java.util.SortedSet +} + +fun foo(set: SortedSet) \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.txt new file mode 100644 index 00000000000..997e8afae87 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName10.txt @@ -0,0 +1,5 @@ +Before shortening: java.util.SortedSet +with DO_NOT_SHORTEN: +with SHORTEN_IF_ALREADY_IMPORTED: +with SHORTEN_AND_IMPORT: +with SHORTEN_AND_STAR_IMPORT: diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.kt new file mode 100644 index 00000000000..fb517fe298b --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.kt @@ -0,0 +1,6 @@ +// FILE: main.kt +class SortedSet + +fun test() { + val a = java.util.SortedSet +} diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.txt new file mode 100644 index 00000000000..ac4a9fd74ed --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName11.txt @@ -0,0 +1,6 @@ +Before shortening: java.util.SortedSet +with DO_NOT_SHORTEN: +with SHORTEN_IF_ALREADY_IMPORTED: +with SHORTEN_AND_IMPORT: +[qualifier] java.util.SortedSet +with SHORTEN_AND_STAR_IMPORT: