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 88e1e3e07d5..2124080cc7f 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 @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir 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.fir.* import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol import org.jetbrains.kotlin.fir.declarations.* @@ -156,22 +157,15 @@ internal class KtFirReferenceShortener( private fun buildSymbol(firSymbol: FirBasedSymbol<*>): KtSymbol = analysisSession.firSymbolBuilder.buildSymbol(firSymbol) } -private fun FqName.dropFakeRootPrefixIfPresent(): FqName { - val pathSegments = pathSegments() - return if (pathSegments.firstOrNull()?.asString() == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE) { - FqName.fromSegments(pathSegments.drop(1).map { it.asString() }) - } else this -} +private fun FqName.dropFakeRootPrefixIfPresent(): FqName = + tail(FqName(ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE)) private data class AdditionalImports(val simpleImports: Set, val starImports: Set) -private inline fun KtFile.findSmallestElementOfTypeContainingSelection(selection: TextRange): T? { - val parents = findElementAt(selection.startOffset) - ?.parentsWithSelf - ?.toList() - - return parents?.filterIsInstance()?.firstOrNull { selection in it.textRange } -} +private inline fun KtFile.findSmallestElementOfTypeContainingSelection(selection: TextRange): T? = + findElementAt(selection.startOffset) + ?.parentsOfType(withSelf = true) + ?.firstOrNull { selection in it.textRange } /** * How a symbol is imported. The order of the enum entry represents the priority of imports. If a symbol is available from multiple kinds of @@ -437,7 +431,7 @@ private class ElementsToShortenCollector( val classifierId = resolvedTypeRef.type.lowerBoundIfFlexible().candidateClassId ?: return - findTypeToShorten(classifierId, typeElement)?.let(::addElementToShorten) + findTypeQualifierToShorten(classifierId, typeElement)?.let(::addElementToShorten) } /** @@ -488,20 +482,6 @@ private class ElementsToShortenCollector( yieldAll(qualifiersToShorten) }.filter { starImport == it.importAllInParent }.mapNotNull { it.nameToImport }.distinct() - private fun findTypeToShorten(wholeClassifierId: ClassId, wholeTypeElement: KtUserType): ElementToShorten? { - val positionScopes = - shorteningContext.findScopesAtPosition(wholeTypeElement, getNamesToImport(), towerContextProvider) ?: return null - val allClassIds = wholeClassifierId.outerClassesWithSelf - val allQualifiedTypeElements = wholeTypeElement.qualifiedTypesWithSelf - return findClassifierElementsToShorten( - positionScopes, - allClassIds, - allQualifiedTypeElements, - ::ShortenType, - this::findFakePackageToShorten - ) - } - private fun findFakePackageToShorten(typeElement: KtUserType): ShortenType? { val deepestTypeWithQualifier = typeElement.qualifiedTypesWithSelf.last() @@ -525,18 +505,16 @@ private class ElementsToShortenCollector( private fun findTypeQualifierToShorten( wholeClassQualifier: ClassId, - wholeQualifierElement: KtDotQualifiedExpression + wholeQualifierElement: KtElement, ): ElementToShorten? { val positionScopes: List = shorteningContext.findScopesAtPosition(wholeQualifierElement, getNamesToImport(), towerContextProvider) ?: return null - val allClassIds: Sequence = wholeClassQualifier.outerClassesWithSelf - val allQualifiers: Sequence = wholeQualifierElement.qualifiedExpressionsWithSelf + val allClassIds = wholeClassQualifier.outerClassesWithSelf + val allQualifiers = wholeQualifierElement.qualifiedElementsWithSelf return findClassifierElementsToShorten( positionScopes, allClassIds, allQualifiers, - ::ShortenQualifier, - this::findFakePackageToShorten ) } @@ -743,12 +721,10 @@ private class ElementsToShortenCollector( return !element.containingFile.hasImportDirectiveForDifferentSymbolWithSameName(classId) } - private inline fun findClassifierElementsToShorten( + private fun findClassifierElementsToShorten( positionScopes: List, allClassIds: Sequence, - allQualifiedElements: Sequence, - createElementToShorten: (E, nameToImport: FqName?, importAllInParent: Boolean) -> ElementToShorten, - findFakePackageToShortenFn: (E) -> ElementToShorten?, + allQualifiedElements: Sequence, ): ElementToShorten? { for ((classId, element) in allClassIds.zip(allQualifiedElements)) { val classSymbol = shorteningContext.toClassSymbol(classId) ?: return null @@ -792,7 +768,23 @@ private class ElementsToShortenCollector( } } } - return findFakePackageToShortenFn(allQualifiedElements.last()) + return findFakePackageToShorten(allQualifiedElements.last()) + } + + private fun createElementToShorten(element: KtElement, nameToImport: FqName?, importAllInParent: Boolean): ElementToShorten { + return when (element) { + is KtUserType -> ShortenType(element, nameToImport, importAllInParent) + is KtDotQualifiedExpression -> ShortenQualifier(element, nameToImport, importAllInParent) + else -> error("Unexpected ${element::class}") + } + } + + private fun findFakePackageToShorten(element: KtElement): ElementToShorten? { + return when (element) { + is KtUserType -> findFakePackageToShorten(element) + is KtDotQualifiedExpression -> findFakePackageToShorten(element) + else -> error("Unexpected ${element::class}") + } } private fun importedClassifierOverwritesAvailableClassifier( @@ -1200,6 +1192,13 @@ private class ElementsToShortenCollector( private val ClassId.outerClassesWithSelf: Sequence get() = generateSequence(this) { it.outerClassId } + private val KtElement.qualifiedElementsWithSelf: Sequence + get() = when (this) { + is KtUserType -> qualifiedTypesWithSelf + is KtDotQualifiedExpression -> qualifiedExpressionsWithSelf + else -> error("Unexpected ${this::class}") + } + /** * Note: The resulting sequence does not contain non-qualified types! * 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 1d924bcc60f..ba994b6ae24 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 @@ -292,6 +292,12 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected.kt"); } + @Test + @TestMetadata("kdocQualifierSelected_rootIdePrefix.kt") + public void testKdocQualifierSelected_rootIdePrefix() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.kt"); + } + @Test @TestMetadata("kdocUnresolved.kt") public void testKdocUnresolved() 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 ec69a56374f..b34812eaba6 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 @@ -292,6 +292,12 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected.kt"); } + @Test + @TestMetadata("kdocQualifierSelected_rootIdePrefix.kt") + public void testKdocQualifierSelected_rootIdePrefix() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.kt"); + } + @Test @TestMetadata("kdocUnresolved.kt") public void testKdocUnresolved() throws Exception { diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.kt new file mode 100644 index 00000000000..f4974b373ca --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.kt @@ -0,0 +1,14 @@ +// FILE: main.kt +import dependency.Foo + +/** + * [_root_ide_package_.dependency.Foo.foo] + */ +fun test() {} + +// FILE: dependency.kt +package dependency + +object Foo { + fun foo() {} +} diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.txt new file mode 100644 index 00000000000..91f2d2d55da --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdocQualifierSelected_rootIdePrefix.txt @@ -0,0 +1,9 @@ +Before shortening: _root_ide_package_.dependency.Foo +with DO_NOT_SHORTEN: +[kdoc] _root_ide_package_.dependency +with SHORTEN_IF_ALREADY_IMPORTED: +[kdoc] _root_ide_package_.dependency.Foo +with SHORTEN_AND_IMPORT: +[kdoc] _root_ide_package_.dependency.Foo +with SHORTEN_AND_STAR_IMPORT: +[kdoc] _root_ide_package_.dependency.Foo