From c5ded1ba48f5ddeea8a6cc7b2697f0fd2f6c2f38 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Mon, 3 Jul 2023 15:57:49 +0200 Subject: [PATCH] KTIJ-26103 [Analysis API] Ignore implicit dispatch receivers in Reference Shortener Calls to extension functions imported from objects have implicit dispatch receivers, but those receivers are not present in the code and should not be analyzed by the shortener ^KTIJ-26103 Fixed --- .../kotlin/analysis/api/fir/FirUtils.kt | 20 +++++++++++++++++++ .../fir/components/KtFirImportOptimizer.kt | 4 ++-- .../fir/components/KtFirReferenceShortener.kt | 3 +++ ...ModuleReferenceShortenerTestGenerated.java | 6 ++++++ ...ModuleReferenceShortenerTestGenerated.java | 6 ++++++ .../referenceShortener/extensionFromObject.kt | 15 ++++++++++++++ .../extensionFromObject.txt | 5 +++++ 7 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.txt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/FirUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/FirUtils.kt index d2ae6dd1890..747e2d33835 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/FirUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/FirUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.api.fir +import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationInfo import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue @@ -17,6 +18,7 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.arguments import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.references.FirErrorNamedReference @@ -94,3 +96,21 @@ internal fun FirAnnotation.toKtAnnotationInfo( isCallWithArguments = this is FirAnnotationCall && arguments.isNotEmpty(), index = index, ) + +/** + * Implicit dispatch receiver is present when an extension function declared in object + * is imported somewhere else and used without directly referencing the object instance + * itself: + * + * ```kt + * import Foo.bar + * + * object Foo { fun String.bar() {} } + * + * fun usage() { + * "hello".bar() // this call has implicit 'Foo' dispatch receiver + * } + * ``` + */ +internal val FirResolvedQualifier.isImplicitDispatchReceiver: Boolean + get() = source?.kind == KtFakeSourceElementKind.ImplicitReceiver diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt index f89aa67dddd..09bc84ccd63 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt @@ -5,11 +5,11 @@ package org.jetbrains.kotlin.analysis.api.fir.components -import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtRealSourceElementKind import org.jetbrains.kotlin.analysis.api.components.KtImportOptimizer import org.jetbrains.kotlin.analysis.api.components.KtImportOptimizerResult import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols +import org.jetbrains.kotlin.analysis.api.fir.isImplicitDispatchReceiver import org.jetbrains.kotlin.analysis.api.fir.utils.FirBodyReanalyzingVisitorVoid import org.jetbrains.kotlin.analysis.api.fir.utils.computeImportableName import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken @@ -274,7 +274,7 @@ internal class KtFirImportOptimizer( val dispatchReceiver = dispatchReceiver if ( dispatchReceiver !is FirResolvedQualifier || - dispatchReceiver.source?.kind != KtFakeSourceElementKind.ImplicitReceiver + !dispatchReceiver.isImplicitDispatchReceiver ) { return null } 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 56be6e1e2c4..99900cc507c 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 @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.components.ShortenCommand import org.jetbrains.kotlin.analysis.api.components.ShortenOption import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.components.ElementsToShortenCollector.PartialOrderOfScope.Companion.toPartialOrder +import org.jetbrains.kotlin.analysis.api.fir.isImplicitDispatchReceiver import org.jetbrains.kotlin.analysis.api.fir.utils.FirBodyReanalyzingVisitorVoid import org.jetbrains.kotlin.analysis.api.fir.utils.computeImportableName import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken @@ -427,6 +428,8 @@ private class ElementsToShortenCollector( } private fun processTypeQualifier(resolvedQualifier: FirResolvedQualifier) { + if (resolvedQualifier.isImplicitDispatchReceiver) return + val wholeClassQualifier = resolvedQualifier.classId ?: return val qualifierPsi = resolvedQualifier.psi ?: return if (!qualifierPsi.textRange.intersects(selection)) return 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 053b21f1262..d6f2c82d7b8 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 @@ -232,6 +232,12 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt"); } + @Test + @TestMetadata("extensionFromObject.kt") + public void testExtensionFromObject() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt"); + } + @Test @TestMetadata("multipleImport.kt") public void testMultipleImport() 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 2b280e28590..e804b67317f 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 @@ -232,6 +232,12 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt"); } + @Test + @TestMetadata("extensionFromObject.kt") + public void testExtensionFromObject() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt"); + } + @Test @TestMetadata("multipleImport.kt") public void testMultipleImport() throws Exception { diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt new file mode 100644 index 00000000000..47202a4ef39 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.kt @@ -0,0 +1,15 @@ +// FILE: main.kt +package test + +import dependency.Bar.extFun + +fun usage(str: String) { + str.extFun() +} + +// FILE: dependency.kt +package dependency + +object Bar { + fun String.extFun() {} +} diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.txt new file mode 100644 index 00000000000..e8f84e7fc38 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/extensionFromObject.txt @@ -0,0 +1,5 @@ +Before shortening: str.extFun() +with DO_NOT_SHORTEN: +with SHORTEN_IF_ALREADY_IMPORTED: +with SHORTEN_AND_IMPORT: +with SHORTEN_AND_STAR_IMPORT: