From 982e7fdd86bd647973f44473ef8f8dd3e127e33b Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 26 Aug 2019 16:47:28 +0300 Subject: [PATCH] New J2K: do not shorten class references for some Java primitive class wrappers classes It may cause unresolved call errors #KT-33500 fixed --- .../kotlin/idea/core/ShortenReferences.kt | 56 ++++++++++--------- .../postProcessing/processings/processings.kt | 15 ++++- .../kotlin/nj2k/ConversionsRunner.kt | 2 +- .../jetbrains/kotlin/nj2k/ImportStorage.kt | 10 ++++ .../conversions/FilterImportsConversion.kt | 9 +-- .../conflictJavaMethodCall.java | 10 ++++ .../conflictJavaMethodCall.kt | 10 ++++ ...lictJavaMethodCallWithExplicitImports.java | 13 +++++ ...nflictJavaMethodCallWithExplicitImports.kt | 8 +++ ...otlinConverterSingleFileTestGenerated.java | 10 ++++ 10 files changed, 108 insertions(+), 35 deletions(-) create mode 100644 nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.java create mode 100644 nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.kt create mode 100644 nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.java create mode 100644 nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.kt diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt index 993c646ae04..c2067764194 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt @@ -96,7 +96,8 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT return process(listOf(element), elementFilter).single() } - fun process(file: KtFile, startOffset: Int, endOffset: Int) { + @JvmOverloads + fun process(file: KtFile, startOffset: Int, endOffset: Int, additionalFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }) { val documentManager = PsiDocumentManager.getInstance(file.project) val document = file.viewProvider.document!! if (!documentManager.isCommitted(document)) { @@ -106,33 +107,36 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT val rangeMarker = document.createRangeMarker(startOffset, endOffset) rangeMarker.isGreedyToLeft = true rangeMarker.isGreedyToRight = true + + val rangeFilter = { element: PsiElement -> + if (rangeMarker.isValid) { + val range = TextRange(rangeMarker.startOffset, rangeMarker.endOffset) + + val elementRange = element.textRange!! + when { + range.contains(elementRange) -> FilterResult.PROCESS + + range.intersects(elementRange) -> { + // for qualified call expression allow to shorten only the part without parenthesis + val calleeExpression = ((element as? KtDotQualifiedExpression) + ?.selectorExpression as? KtCallExpression) + ?.calleeExpression + if (calleeExpression != null) { + val rangeWithoutParenthesis = TextRange(elementRange.startOffset, calleeExpression.textRange!!.endOffset) + if (range.contains(rangeWithoutParenthesis)) FilterResult.PROCESS else FilterResult.GO_INSIDE + } else { + FilterResult.GO_INSIDE + } + } + else -> FilterResult.SKIP + } + } else { + FilterResult.SKIP + } + } try { process(listOf(file)) { element -> - if (rangeMarker.isValid) { - val range = TextRange(rangeMarker.startOffset, rangeMarker.endOffset) - - val elementRange = element.textRange!! - when { - range.contains(elementRange) -> FilterResult.PROCESS - - range.intersects(elementRange) -> { - // for qualified call expression allow to shorten only the part without parenthesis - val calleeExpression = ((element as? KtDotQualifiedExpression) - ?.selectorExpression as? KtCallExpression) - ?.calleeExpression - if (calleeExpression != null) { - val rangeWithoutParenthesis = TextRange(elementRange.startOffset, calleeExpression.textRange!!.endOffset) - if (range.contains(rangeWithoutParenthesis)) FilterResult.PROCESS else FilterResult.GO_INSIDE - } else { - FilterResult.GO_INSIDE - } - } - - else -> FilterResult.SKIP - } - } else { - FilterResult.SKIP - } + minOf(rangeFilter(element), additionalFilter(element)) } } finally { rangeMarker.dispose() diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt index d3b894d5278..9ae06316980 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt @@ -14,6 +14,9 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument +import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.nj2k.ImportStorage import org.jetbrains.kotlin.nj2k.asLabel import org.jetbrains.kotlin.nj2k.inference.common.BoundTypeCalculatorImpl import org.jetbrains.kotlin.nj2k.inference.common.ByInfoSuperFunctionsProvider @@ -29,6 +32,7 @@ import org.jetbrains.kotlin.nj2k.inference.nullability.NullabilityStateUpdater import org.jetbrains.kotlin.nj2k.postProcessing.postProcessing import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.elementsInRange +import org.jetbrains.kotlin.utils.addToStdlib.safeAs val formatCodeProcessing = postProcessing { file, rangeMarker, _ -> @@ -90,12 +94,19 @@ private fun KtFile.clearUndefinedLabels() { val shortenReferencesProcessing = postProcessing { file, rangeMarker, _ -> + val filter = filter@{ element: PsiElement -> + if (element !is KtQualifiedExpression) return@filter ShortenReferences.FilterResult.PROCESS + val fqName = element.selectorExpression?.mainReference?.resolve()?.getKotlinFqName() + ?: return@filter ShortenReferences.FilterResult.PROCESS + if (ImportStorage.isImportNeeded(fqName)) ShortenReferences.FilterResult.PROCESS + else ShortenReferences.FilterResult.SKIP + } if (rangeMarker != null) { if (rangeMarker.isValid) { - ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset) + ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter) } } else { - ShortenReferences.DEFAULT.process(file) + ShortenReferences.DEFAULT.process(file, filter) } } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt index 6de564ce411..f5801f9bf0f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt @@ -73,7 +73,6 @@ object ConversionsRunner { //Kotlin --> Kotlin conversions +InnerClassConversion() - +FilterImportsConversion() +StaticsToCompanionExtractConversion() +InterfaceWithFieldConversion() +ClassToObjectPromotionConversion(context) @@ -84,6 +83,7 @@ object ConversionsRunner { +LiteralConversion() +CollectImportsConversion(context) + +FilterImportsConversion() +MoveInitBlocksToTheEndConversion() +AddElementsInfoConversion(context) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/ImportStorage.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/ImportStorage.kt index 0f7d03dbd25..85bbdbe1a83 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/ImportStorage.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/ImportStorage.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.nj2k +import com.intellij.psi.CommonClassNames import org.jetbrains.kotlin.load.java.NULLABILITY_ANNOTATIONS import org.jetbrains.kotlin.name.FqName @@ -22,9 +23,18 @@ class ImportStorage { companion object { fun isImportNeeded(fqName: FqName): Boolean { if (fqName in NULLABILITY_ANNOTATIONS) return false + if (fqName in JAVA_TYPE_WRAPPERS_WHICH_HAVE_CONFLICTS_WITH_KOTLIN_ONES) return false return true } + private val JAVA_TYPE_WRAPPERS_WHICH_HAVE_CONFLICTS_WITH_KOTLIN_ONES = setOf( + FqName(CommonClassNames.JAVA_LANG_BYTE), + FqName(CommonClassNames.JAVA_LANG_SHORT), + FqName(CommonClassNames.JAVA_LANG_LONG), + FqName(CommonClassNames.JAVA_LANG_FLOAT), + FqName(CommonClassNames.JAVA_LANG_DOUBLE) + ) + fun isImportNeeded(fqName: String): Boolean = isImportNeeded(FqName(fqName)) } } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/FilterImportsConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/FilterImportsConversion.kt index 7f5282910d4..ac204cf45b3 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/FilterImportsConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/FilterImportsConversion.kt @@ -12,12 +12,9 @@ import org.jetbrains.kotlin.nj2k.tree.JKTreeElement class FilterImportsConversion : RecursiveApplicableConversionBase() { override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element is JKImportList) { - for (import in element.imports) { - if (!ImportStorage.isImportNeeded(import.name.value)) { - element.imports -= import - } - } + if (element !is JKImportList) return recurse(element) + element.imports = element.imports.filter { import -> + ImportStorage.isImportNeeded(import.name.value) } return recurse(element) } diff --git a/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.java b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.java new file mode 100644 index 00000000000..6819a7b67ae --- /dev/null +++ b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.java @@ -0,0 +1,10 @@ +// RUNTIME_WITH_FULL_JDK + +public class Test { + void m() { + Double.isFinite(2.0); + Double.isNaN(2.0); + Float.isNaN(2.0f); + Float.isInfinite(2.0f); + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.kt b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.kt new file mode 100644 index 00000000000..f57a1b86ad2 --- /dev/null +++ b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.kt @@ -0,0 +1,10 @@ +// RUNTIME_WITH_FULL_JDK + +class Test { + internal fun m() { + java.lang.Double.isFinite(2.0) + java.lang.Double.isNaN(2.0) + java.lang.Float.isNaN(2.0f) + java.lang.Float.isInfinite(2.0f) + } +} diff --git a/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.java b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.java new file mode 100644 index 00000000000..d7d8bf38045 --- /dev/null +++ b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.java @@ -0,0 +1,13 @@ +// RUNTIME_WITH_FULL_JDK + +import java.lang.Double +import java.lang.Float + +public class Test { + void m() { + Double.isFinite(2.0); + Double.isNaN(2.0); + Float.isNaN(2.0f); + Float.isInfinite(2.0f); + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.kt b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.kt new file mode 100644 index 00000000000..75d80761ef7 --- /dev/null +++ b/nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.kt @@ -0,0 +1,8 @@ +class Test { + internal fun m() { + java.lang.Double.isFinite(2.0) + java.lang.Double.isNaN(2.0) + java.lang.Float.isNaN(2.0f) + java.lang.Float.isInfinite(2.0f) + } +} diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java index 59506c8d6c5..1e197f4fcdc 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java @@ -3472,6 +3472,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew runTest("nj2k/testData/newJ2k/methodCallExpression/collectionsMethods2.java"); } + @TestMetadata("conflictJavaMethodCall.java") + public void testConflictJavaMethodCall() throws Exception { + runTest("nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCall.java"); + } + + @TestMetadata("conflictJavaMethodCallWithExplicitImports.java") + public void testConflictJavaMethodCallWithExplicitImports() throws Exception { + runTest("nj2k/testData/newJ2k/methodCallExpression/conflictJavaMethodCallWithExplicitImports.java"); + } + @TestMetadata("emptyCall.java") public void testEmptyCall() throws Exception { runTest("nj2k/testData/newJ2k/methodCallExpression/emptyCall.java");