From b3505152372329acdfad481f249bdbb5492f5244 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Fri, 11 Oct 2019 00:33:10 +0300 Subject: [PATCH] New J2K: make post-processing aware of other files which are being converted Before post-processing was able to handle only one converting file at once So, some conversions (like (field, getter, setter) to Kotlin property) was not able to work when converting class hierarchy was split into multiple files. Also, inferring nullability for a set of files was broken #KT-19569 fixed #KT-34266 fixed #KT-32518 fixed --- .../kotlin/idea/j2k/J2kPostProcessor.kt | 15 ++- .../kotlin/idea/actions/JavaToKotlinAction.kt | 1 - .../kotlin/j2k/AfterConversionPass.kt | 24 ++-- .../kotlin/j2k/JavaToKotlinConverter.kt | 35 +++++- .../nj2k/postProcessing/J2kPostProcessor.kt | 10 +- .../postProcessing/JKInMemoryFilesSearcher.kt | 42 +++++++ .../diagnosticBasedPostProcessing.kt | 13 +- .../inspectionLikePostProcessings.kt | 7 +- .../nj2k/postProcessing/postProcessings.kt | 32 +++-- ...rtGettersAndSettersToPropertyProcessing.kt | 115 ++++++++++-------- .../processings/InferenceProcessing.kt | 24 ++-- .../processings/ShortenReferenceProcessing.kt | 5 +- .../postProcessing/processings/processings.kt | 35 +++--- .../kotlin/nj2k/NewJavaToKotlinConverter.kt | 55 ++++----- .../src/org/jetbrains/kotlin/nj2k/psiUtils.kt | 16 +++ .../DetectPropertiesMultipleFiles/B.java | 31 +++++ .../DetectPropertiesMultipleFiles/B.kt | 20 +++ .../DetectPropertiesMultipleFiles/C.java | 57 +++++++++ .../DetectPropertiesMultipleFiles/C.kt | 34 ++++++ .../DetectPropertiesMultipleFiles/I.java | 21 ++++ .../DetectPropertiesMultipleFiles/I.kt | 13 ++ .../DetectPropertiesMultipleFiles/I1.java | 7 ++ .../DetectPropertiesMultipleFiles/I1.kt | 6 + .../InterfaceWithGetterInOtherFile/IUser.java | 5 + .../InterfaceWithGetterInOtherFile/IUser.kt | 5 + .../UserImpl.java | 14 +++ .../UserImpl.kt | 3 + ...ctNewJavaToKotlinConverterMultiFileTest.kt | 8 +- ...KotlinConverterMultiFileTestGenerated.java | 10 ++ 29 files changed, 498 insertions(+), 165 deletions(-) create mode 100644 nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/JKInMemoryFilesSearcher.kt create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.java create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.kt create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.java create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.kt create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.java create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.kt create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.java create mode 100644 nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.kt create mode 100644 nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.java create mode 100644 nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.kt create mode 100644 nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.java create mode 100644 nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.kt diff --git a/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessor.kt b/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessor.kt index b77f5bf669a..71b192596b6 100644 --- a/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessor.kt +++ b/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessor.kt @@ -32,8 +32,7 @@ import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.j2k.ConverterContext -import org.jetbrains.kotlin.j2k.PostProcessor +import org.jetbrains.kotlin.j2k.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -61,11 +60,15 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor { } override fun doAdditionalProcessing( - file: KtFile, + target: JKPostProcessingTarget, converterContext: ConverterContext?, - rangeMarker: RangeMarker?, onPhaseChanged: ((Int, String) -> Unit)? - ) = + ) { + val (file, rangeMarker) = when (target) { + is JKPieceOfCodePostProcessingTarget -> target.file to target.rangeMarker + is JKMultipleFilesPostProcessingTarget -> target.files.single() to null + } + runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { do { var modificationStamp: Long? = file.modificationStamp @@ -109,7 +112,7 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor { } } } - + } private data class ActionData(val element: KtElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean) diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt index 850dce16207..9d8f389a1e7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt @@ -57,7 +57,6 @@ import org.jetbrains.kotlin.idea.util.isRunningInCidrIde import org.jetbrains.kotlin.j2k.* import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.UserDataProperty -import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.io.File import java.io.IOException import java.util.* diff --git a/j2k/src/org/jetbrains/kotlin/j2k/AfterConversionPass.kt b/j2k/src/org/jetbrains/kotlin/j2k/AfterConversionPass.kt index a4e0ad8ad7d..656b467e65f 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/AfterConversionPass.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/AfterConversionPass.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.j2k +import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.idea.util.application.runReadAction @@ -29,14 +30,19 @@ class AfterConversionPass(val project: Project, val postProcessor: PostProcessor range: TextRange?, onPhaseChanged: ((Int, String) -> Unit)? = null ) { - val rangeMarker = if (range != null) { - val document = kotlinFile.viewProvider.document!! - val marker = runReadAction { document.createRangeMarker(range.startOffset, range.endOffset) } - marker.isGreedyToLeft = true - marker.isGreedyToRight = true - marker - } else null - - postProcessor.doAdditionalProcessing(kotlinFile, converterContext, rangeMarker, onPhaseChanged) + postProcessor.doAdditionalProcessing( + when { + range != null -> JKPieceOfCodePostProcessingTarget(kotlinFile, range.toRangeMarker(kotlinFile)) + else -> JKMultipleFilesPostProcessingTarget(listOf(kotlinFile)) + }, + converterContext, + onPhaseChanged + ) } } + +fun TextRange.toRangeMarker(file: KtFile): RangeMarker = + runReadAction { file.viewProvider.document!!.createRangeMarker(startOffset, endOffset) }.apply { + isGreedyToLeft = true + isGreedyToRight = true + } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt index 1d1f9ab9596..d13e80bb64b 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt @@ -26,12 +26,15 @@ import com.intellij.openapi.util.Computable import com.intellij.psi.* import com.intellij.psi.impl.source.DummyHolder import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.idea.core.util.range +import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.j2k.ast.Element import org.jetbrains.kotlin.j2k.usageProcessing.ExternalCodeProcessor import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import java.util.* @@ -43,13 +46,37 @@ interface PostProcessor { val phasesCount: Int fun doAdditionalProcessing( - file: KtFile, + target: JKPostProcessingTarget, converterContext: ConverterContext?, - rangeMarker: RangeMarker?, onPhaseChanged: ((Int, String) -> Unit)? ) } +sealed class JKPostProcessingTarget + +data class JKPieceOfCodePostProcessingTarget( + val file: KtFile, + val rangeMarker: RangeMarker +) : JKPostProcessingTarget() + + +data class JKMultipleFilesPostProcessingTarget( + val files: List +) : JKPostProcessingTarget() + +fun JKPostProcessingTarget.elements() = when (this) { + is JKPieceOfCodePostProcessingTarget -> runReadAction { + val range = rangeMarker.range ?: return@runReadAction emptyList() + file.elementsInRange(range) + } + is JKMultipleFilesPostProcessingTarget -> files +} + +fun JKPostProcessingTarget.files() = when (this) { + is JKPieceOfCodePostProcessingTarget -> listOf(file) + is JKMultipleFilesPostProcessingTarget -> files +} + enum class ParseContext { TOP_LEVEL, CODE_BLOCK @@ -270,7 +297,7 @@ interface WithProgressProcessor { processItem: (TInputItem) -> TOutputItem ): List - fun updateState(fileIndex: Int, phase: Int, description: String) + fun updateState(fileIndex: Int?, phase: Int, description: String) fun process(action: () -> T): T } @@ -318,7 +345,7 @@ class OldWithProgressProcessor(private val progress: ProgressIndicator?, private throw AbstractMethodError("Should not be called for old J2K") } - override fun updateState(fileIndex: Int, phase: Int, description: String) { + override fun updateState(fileIndex: Int?, phase: Int, description: String) { throw AbstractMethodError("Should not be called for old J2K") } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt index 84b70e51e99..f678e67a33c 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt @@ -22,7 +22,9 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialSta import org.jetbrains.kotlin.idea.quickfix.* import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.j2k.ConverterContext +import org.jetbrains.kotlin.j2k.JKPostProcessingTarget import org.jetbrains.kotlin.j2k.PostProcessor +import org.jetbrains.kotlin.j2k.files import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext @@ -42,23 +44,23 @@ class NewJ2kPostProcessor : PostProcessor { override val phasesCount = processings.size + override fun doAdditionalProcessing( - file: KtFile, + target: JKPostProcessingTarget, converterContext: ConverterContext?, - rangeMarker: RangeMarker?, onPhaseChanged: ((Int, String) -> Unit)? ) { for ((i, group) in processings.withIndex()) { onPhaseChanged?.invoke(i + 1, group.description) for (processing in group.processings) { try { - processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext) + processing.runProcessing(target, converterContext as NewJ2kConverterContext) } catch (e: ProcessCanceledException) { throw e } catch (t: Throwable) { LOG.error(t) } finally { - commitFile(file) + target.files().forEach(::commitFile) } } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/JKInMemoryFilesSearcher.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/JKInMemoryFilesSearcher.kt new file mode 100644 index 00000000000..a0a08d5652c --- /dev/null +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/JKInMemoryFilesSearcher.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.nj2k.postProcessing + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.search.LocalSearchScope +import com.intellij.psi.search.searches.ReferencesSearch +import org.jetbrains.kotlin.psi.KtElement + +internal abstract class JKInMemoryFilesSearcher { + abstract fun search(element: KtElement): Iterable + + companion object { + fun create(files: List) = when { + files.size == 1 -> JKSingleFileInMemoryFilesSearcher(files.single()) + else -> JKMultipleFilesInMemoryFilesSearcher(files) + } + } +} + +internal class JKSingleFileInMemoryFilesSearcher(private val scopeElement: PsiElement) : JKInMemoryFilesSearcher() { + override fun search(element: KtElement): Iterable = + ReferencesSearch.search(element, LocalSearchScope(scopeElement)) +} + + +// it does not cover all cases e.g, just-changed reference +// maybe the solution is to do searching manually +// firstly by-text and then resolving +internal class JKMultipleFilesInMemoryFilesSearcher(private val scopeElements: List) : JKInMemoryFilesSearcher() { + override fun search(element: KtElement): Iterable { + val result = mutableListOf() + for (scopeElement in scopeElements) { + result += ReferencesSearch.search(element, LocalSearchScope(scopeElement)) + } + return result + } +} diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt index 5d4c3fdb129..768723616f6 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.nj2k.postProcessing import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade @@ -15,6 +16,7 @@ import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.psi.KtElement @@ -23,7 +25,7 @@ import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.utils.addToStdlib.safeAs -class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List) : ProcessingGroup { +class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List) : FileBasedPostProcessing() { constructor(vararg diagnosticBasedProcessings: DiagnosticBasedProcessing) : this(diagnosticBasedProcessings.toList()) private val diagnosticToFix = @@ -33,8 +35,9 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + val resolutionFacade = runReadAction { KotlinCacheService.getInstance(converterContext.project).getResolutionFacade(allFiles) } + val diagnostics = runReadAction { analyzeFileRange(file, rangeMarker, resolutionFacade).all() } runUndoTransparentActionInEdt(inWriteAction = true) { for (diagnostic in diagnostics) { val range = rangeMarker?.range ?: file.textRange @@ -49,7 +52,7 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List listOf(file) rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!).filterIsInstance() @@ -57,7 +60,7 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List -) : ProcessingGroup { +) : FileBasedPostProcessing() { constructor(vararg processings: InspectionLikeProcessing) : this( runSingleTime = false, acceptNonKtElements = false, @@ -35,8 +33,7 @@ class InspectionLikeProcessingGroup( private val processingsToPriorityMap = processings.mapToIndex() fun priority(processing: InspectionLikeProcessing): Int = processingsToPriorityMap.getValue(processing) - - override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + override fun runProcessing(file: KtFile, allFiles: List, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { do { var modificationStamp: Long? = file.modificationStamp val elementToActions = runReadAction { diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt index eff0ea13ce1..de75de090e5 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt @@ -7,27 +7,35 @@ package org.jetbrains.kotlin.nj2k.postProcessing import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.idea.core.util.range -import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.j2k.JKMultipleFilesPostProcessingTarget +import org.jetbrains.kotlin.j2k.JKPieceOfCodePostProcessingTarget +import org.jetbrains.kotlin.j2k.JKPostProcessingTarget +import org.jetbrains.kotlin.j2k.elements import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.psiUtil.elementsInRange interface GeneralPostProcessing { - fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) + fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) } +abstract class FileBasedPostProcessing : GeneralPostProcessing { + final override fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) = when (target) { + is JKPieceOfCodePostProcessingTarget -> + runProcessing(target.file, listOf(target.file), target.rangeMarker, converterContext) + is JKMultipleFilesPostProcessingTarget -> + target.files.forEach { file -> + runProcessing(file, target.files, rangeMarker = null, converterContext = converterContext) + } + } + + abstract fun runProcessing(file: KtFile, allFiles: List, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) +} + abstract class ElementsBasedPostProcessing : GeneralPostProcessing { - final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { - val elements = runReadAction { - rangeMarker?.let { marker -> - val range = marker.range ?: return@let emptyList() - file.elementsInRange(range) - } ?: listOf(file) - } - runProcessing(elements, converterContext) + final override fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) { + runProcessing(target.elements(), converterContext) } abstract fun runProcessing(elements: List, converterContext: NewJ2kConverterContext) diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt index 980ad385ad4..60c40f8c316 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt @@ -8,9 +8,9 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings import com.intellij.psi.PsiElement import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.OverridingMethodsSearch -import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.refactoring.rename.RenamePsiElementProcessor import org.jetbrains.kotlin.asJava.toLightMethods +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -22,17 +22,21 @@ import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.readWriteAccess +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.nj2k.* +import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext +import org.jetbrains.kotlin.nj2k.asGetterName +import org.jetbrains.kotlin.nj2k.asSetterName import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKFakeFieldData import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKFieldData import org.jetbrains.kotlin.nj2k.externalCodeProcessing.JKMethodData import org.jetbrains.kotlin.nj2k.externalCodeProcessing.NewExternalCodeProcessing +import org.jetbrains.kotlin.nj2k.fqNameWithoutCompanions import org.jetbrains.kotlin.nj2k.postProcessing.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* @@ -51,16 +55,59 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.mapToIndex class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing() { + override fun runProcessing(elements: List, converterContext: NewJ2kConverterContext) { + val ktElements = elements.filterIsInstance() + val resolutionFacade = runReadAction { + KotlinCacheService.getInstance(converterContext.project).getResolutionFacade(ktElements) + } + ConvertGettersAndSettersToPropertyStatefulProcessing( + resolutionFacade, + ktElements, + converterContext.externalCodeProcessor + ).runProcessing() + } +} + +private class ConvertGettersAndSettersToPropertyStatefulProcessing( + private val resolutionFacade: ResolutionFacade, + private val elements: List, + private val externalCodeUpdater: NewExternalCodeProcessing +) { + private val searcher = JKInMemoryFilesSearcher.create(elements) + + + fun runProcessing() { + val collectingState = CollectingState() + val classesWithPropertiesData = runReadAction { + elements + .descendantsOfType() + .sortedByInheritance() + .map { klass -> + klass to klass.collectPropertiesData(collectingState) + } + } + if (classesWithPropertiesData.isEmpty()) return + runUndoTransparentActionInEdt(inWriteAction = true) { + for ((klass, propertiesData) in classesWithPropertiesData) { + convertClass(klass, propertiesData) + } + } + } + private fun KtNamedFunction.hasOverrides(): Boolean = toLightMethods().singleOrNull()?.let { lightMethod -> - OverridingMethodsSearch.search(lightMethod).findFirst() - } != null + if (OverridingMethodsSearch.search(lightMethod).findFirst() != null) return@let true + if (elements.size == 1) return@let false + elements.any { element -> + OverridingMethodsSearch.search(lightMethod, LocalSearchScope(element), true).findFirst() != null + } + } == true private fun KtNamedFunction.hasSuperFunction(): Boolean = - resolveToDescriptorIfAny()?.original?.overriddenDescriptors?.isNotEmpty() == true + resolveToDescriptorIfAny(resolutionFacade)?.original?.overriddenDescriptors?.isNotEmpty() == true private fun KtNamedFunction.hasInvalidSuperDescriptors(): Boolean = - resolveToDescriptorIfAny() + resolveToDescriptorIfAny(resolutionFacade) ?.original ?.overriddenDescriptors ?.any { it.isJavaDescriptor || it is FunctionDescriptor } == true @@ -216,7 +263,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing } private fun KtElement.usages() = - ReferencesSearch.search(this, LocalSearchScope(containingKtFile)) + searcher.search(this) private fun T.withReplacedExpressionInBody( from: KtElement, @@ -249,7 +296,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing val sorted = mutableListOf() val visited = Array(size) { false } - val descriptors = map { it.resolveToDescriptorIfAny()!! } + val descriptors = map { it.resolveToDescriptorIfAny(resolutionFacade)!! } val descriptorToIndex = descriptors.mapToIndex() val outers = descriptors.map { descriptor -> descriptor.superClassAndSuperInterfaces().mapNotNull { descriptorToIndex[it] } @@ -273,25 +320,6 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing return sorted } - - override fun runProcessing(elements: List, converterContext: NewJ2kConverterContext) { - val collectingState = CollectingState() - val classesWithPropertiesData = runReadAction { - elements - .descendantsOfType() - .sortedByInheritance() - .map { klass -> - klass to klass.collectPropertiesData(collectingState) - } - } - if (classesWithPropertiesData.isEmpty()) return - runUndoTransparentActionInEdt(inWriteAction = true) { - for ((klass, propertiesData) in classesWithPropertiesData) { - convertClass(klass, propertiesData, converterContext.externalCodeProcessor) - } - } - } - private fun causesNameConflictInCurrentDeclarationAndItsParents(name: String, declaration: DeclarationDescriptor?): Boolean = when (declaration) { is ClassDescriptor -> { @@ -310,27 +338,11 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing } private fun calculatePropertyType(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? { - val getterType = getter?.resolveToDescriptorIfAny()?.returnType - val setterType = setter?.resolveToDescriptorIfAny()?.valueParameters?.singleOrNull()?.type + val getterType = getter?.resolveToDescriptorIfAny(resolutionFacade)?.returnType + val setterType = setter?.resolveToDescriptorIfAny(resolutionFacade)?.valueParameters?.singleOrNull()?.type return calculatePropertyType(getterType, setterType) } - private fun calculatePropertyTypeBasedOnSuperDescriptors(getter: KtNamedFunction?, setter: KtNamedFunction?): KotlinType? { - val superGetterType = getter - ?.resolveToDescriptorIfAny() - ?.overriddenDescriptors - ?.firstOrNull() - ?.returnType - val superSetterType = setter - ?.resolveToDescriptorIfAny() - ?.overriddenDescriptors - ?.firstOrNull() - ?.valueParameters - ?.singleOrNull() - ?.type - return calculatePropertyType(superGetterType, superSetterType) - } - private fun KtClassOrObject.collectPropertiesData(collectingState: CollectingState): List { return declarations .asSequence() @@ -356,7 +368,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing val name = realGetter?.name ?: realSetter?.name!! val superDeclarationOwner = (realGetter?.function ?: realSetter?.function) - ?.resolveToDescriptorIfAny() + ?.resolveToDescriptorIfAny(resolutionFacade) ?.overriddenDescriptors ?.firstOrNull() ?.findPsi() @@ -378,7 +390,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing klass: KtClassOrObject, factory: KtPsiFactory ): List { - val classDescriptor = klass.resolveToDescriptorIfAny() ?: return emptyList() + val classDescriptor = klass.resolveToDescriptorIfAny(resolutionFacade) ?: return emptyList() val variablesDescriptorsMap = (listOfNotNull(classDescriptor.getSuperClassNotAny()) + classDescriptor.getSuperInterfaces()) @@ -462,7 +474,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing val getter = realGetter ?: when { - realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any { + realProperty?.property?.resolveToDescriptorIfAny(resolutionFacade)?.overriddenDescriptors?.any { it.safeAs()?.isVar == true } == true -> FakeGetter(name, null, "") @@ -487,7 +499,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing realProperty?.property?.isVar == true -> FakeSetter(name, null, "") - realProperty?.property?.resolveToDescriptorIfAny()?.overriddenDescriptors?.any { + realProperty?.property?.resolveToDescriptorIfAny(resolutionFacade)?.overriddenDescriptors?.any { it.safeAs()?.isVar == true } == true || variablesDescriptorsMap[name]?.isVar == true -> @@ -523,7 +535,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing } private fun KtProperty.renameTo(newName: String, factory: KtPsiFactory) { - for (usage in usages().toList()) { + for (usage in usages()) { val element = usage.element val isBackingField = element is KtNameReferenceExpression && element.text == KtTokens.FIELD_KEYWORD.value @@ -540,8 +552,7 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing private fun convertClass( klass: KtClassOrObject, - propertiesData: List, - externalCodeUpdater: NewExternalCodeProcessing + propertiesData: List ) { val factory = KtPsiFactory(klass) val accessors = propertiesData.filterGettersAndSetters(klass, factory) diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt index fb61ae7c69c..0b025c86ce5 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt @@ -5,9 +5,8 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings -import com.intellij.openapi.editor.RangeMarker -import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.core.util.range +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext @@ -20,19 +19,16 @@ import org.jetbrains.kotlin.nj2k.inference.common.collectors.CommonConstraintsCo import org.jetbrains.kotlin.nj2k.inference.common.collectors.FunctionConstraintsCollector import org.jetbrains.kotlin.nj2k.inference.mutability.* import org.jetbrains.kotlin.nj2k.inference.nullability.* -import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing +import org.jetbrains.kotlin.nj2k.postProcessing.ElementsBasedPostProcessing import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.psiUtil.elementsInRange -abstract class InferenceProcessing : GeneralPostProcessing { - final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { - val elements = if (rangeMarker != null) { - val range = rangeMarker.range ?: return - runReadAction { file.elementsInRange(range) }.filterIsInstance() - } else listOf(file) - val resolutionFacade = runReadAction { file.getResolutionFacade() } - createInferenceFacade(resolutionFacade, converterContext).runOn(elements) +abstract class InferenceProcessing : ElementsBasedPostProcessing() { + override fun runProcessing(elements: List, converterContext: NewJ2kConverterContext) { + val kotlinElements = elements.filterIsInstance() + val resolutionFacade = runReadAction { + KotlinCacheService.getInstance(converterContext.project).getResolutionFacade(kotlinElements) + } + createInferenceFacade(resolutionFacade, converterContext).runOn(kotlinElements) } abstract fun createInferenceFacade( diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt index 4dc54cbff55..c740c222c45 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt @@ -10,12 +10,13 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.nj2k.JKImportStorage import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext +import org.jetbrains.kotlin.nj2k.postProcessing.FileBasedPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtQualifiedExpression -class ShortenReferenceProcessing : GeneralPostProcessing { +class ShortenReferenceProcessing : FileBasedPostProcessing() { private val filter = filter@{ element: PsiElement -> when (element) { is KtQualifiedExpression -> when { @@ -26,7 +27,7 @@ class ShortenReferenceProcessing : GeneralPostProcessing { } } - override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + override fun runProcessing(file: KtFile, allFiles: List, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { runUndoTransparentActionInEdt(inWriteAction = false) { if (rangeMarker != null) { if (rangeMarker.isValid) { 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 d33e5f0ed8a..14a43a10b25 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 @@ -13,16 +13,19 @@ import com.intellij.psi.PsiElementVisitor import com.intellij.psi.codeStyle.CodeStyleManager import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.j2k.JKPostProcessingTarget +import org.jetbrains.kotlin.j2k.elements import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.asLabel +import org.jetbrains.kotlin.nj2k.postProcessing.FileBasedPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.elementsInRange -class FormatCodeProcessing : GeneralPostProcessing { - override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { +class FormatCodeProcessing : FileBasedPostProcessing() { + override fun runProcessing(file: KtFile, allFiles: List, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { val codeStyleManager = CodeStyleManager.getInstance(file.project) runUndoTransparentActionInEdt(inWriteAction = true) { if (rangeMarker != null) { @@ -38,28 +41,30 @@ class FormatCodeProcessing : GeneralPostProcessing { class ClearUnknownLabelsProcessing : GeneralPostProcessing { - override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + override fun runProcessing(target: JKPostProcessingTarget, converterContext: NewJ2kConverterContext) { val comments = mutableListOf() runUndoTransparentActionInEdt(inWriteAction = true) { - file.accept(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - element.acceptChildren(this) - } - - override fun visitComment(comment: PsiComment) { - if (comment.text.asLabel() != null) { - comments += comment + target.elements().forEach { element -> + element.accept(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + element.acceptChildren(this) } - } - }) + + override fun visitComment(comment: PsiComment) { + if (comment.text.asLabel() != null) { + comments += comment + } + } + }) + } comments.forEach { it.delete() } } } } -class OptimizeImportsProcessing : GeneralPostProcessing { - override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { +class OptimizeImportsProcessing : FileBasedPostProcessing() { + override fun runProcessing(file: KtFile, allFiles: List, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { val elements = runReadAction { when { rangeMarker != null && rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!) diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt index e2be8e94671..915495cae05 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt @@ -17,10 +17,8 @@ package org.jetbrains.kotlin.nj2k import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project @@ -28,7 +26,6 @@ import com.intellij.openapi.util.Computable import com.intellij.psi.* import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.idea.project.languageVersionSettings -import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.j2k.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.nj2k.conversions.JKResolver @@ -68,36 +65,27 @@ class NewJavaToKotlinConverter( elementsToKotlin(files, withProgressProcessor) }) - val texts = results.mapIndexed { i, result -> - try { - val kotlinFile = ApplicationManager.getApplication().runReadAction(Computable { - KtPsiFactory(project).createFileWithLightClassSupport("dummy.kt", result!!.text, files[i]) - }) - - ApplicationManager.getApplication().invokeAndWait { - CommandProcessor.getInstance().runUndoTransparentAction { - runWriteAction { - kotlinFile.addImports(result!!.importsToAdd) - } - } + val kotlinFiles = results.mapIndexed { i, result -> + runUndoTransparentActionInEdt(inWriteAction = true) { + val javaFile = files[i] + KtPsiFactory(project).createFileWithLightClassSupport( + javaFile.name.replace(".java", ".kt"), + result!!.text, + files[i] + ).apply { + addImports(result.importsToAdd) } - AfterConversionPass(project, postProcessor).run( - kotlinFile, - context, - range = null, - onPhaseChanged = { phase, description -> - withProgressProcessor.updateState(i, phase + 1, description) - } - ) - kotlinFile.text - } catch (e: ProcessCanceledException) { - throw e - } catch (t: Throwable) { - LOG.error(t) - result!!.text } + } - FilesResult(texts, externalCodeProcessing) + + postProcessor.doAdditionalProcessing( + JKMultipleFilesPostProcessingTarget(kotlinFiles), + context + ) { phase, description -> + withProgressProcessor.updateState(fileIndex = null, phase = phase + 1, description = description) + } + FilesResult(kotlinFiles.map { it.text }, externalCodeProcessing) } } @@ -217,12 +205,13 @@ class NewJ2kWithProgressProcessor( val DEFAULT = NewJ2kWithProgressProcessor(null, null, 0) } - override fun updateState(fileIndex: Int, phase: Int, description: String) { + override fun updateState(fileIndex: Int?, phase: Int, description: String) { progress?.checkCanceled() progress?.fraction = phase / phasesCount.toDouble() progress?.text = "$description - phase $phase of $phasesCount" - if (files != null && files.isNotEmpty()) { - progress?.text2 = files[fileIndex].virtualFile.presentableUrl + progress?.text2 = when { + files != null && files.isNotEmpty() && fileIndex != null -> files[fileIndex].virtualFile.presentableUrl + else -> "" } } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt index b728d99153f..c7909ee2d6f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt @@ -7,11 +7,14 @@ package org.jetbrains.kotlin.nj2k import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature import com.intellij.lang.jvm.JvmClassKind +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.command.CommandProcessor import com.intellij.psi.* import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.MethodSignatureUtil import com.intellij.psi.util.PsiUtil +import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.j2k.ClassKind import org.jetbrains.kotlin.j2k.ReferenceSearcher import org.jetbrains.kotlin.j2k.isNullLiteral @@ -141,3 +144,16 @@ val KtDeclaration.fqNameWithoutCompanions .filter { it.safeAs()?.isCompanion() != true && it.name != null } .toList() .foldRight(containingKtFile.packageFqName) { container, acc -> acc.child(Name.identifier(container.name!!)) } + +internal fun runUndoTransparentActionInEdt(inWriteAction: Boolean, action: () -> T): T { + var result: T? = null + ApplicationManager.getApplication().invokeAndWait { + CommandProcessor.getInstance().runUndoTransparentAction { + result = when { + inWriteAction -> runWriteAction(action) + else -> action() + } + } + } + return result!! +} \ No newline at end of file diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.java b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.java new file mode 100644 index 00000000000..cb5f738f17a --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.java @@ -0,0 +1,31 @@ +package test; + +public class B { + public String getFromB1() { + return ""; + } + + public String getFromB2() { + return ""; + } + + public void setFromB2(String value) { + } + + public String getFromB3() { + return ""; + } + + public void setFromB3(String value) { + } + + public String getFromB4() { + return ""; + } + + public void setFromB4(String value) { + } + + public void setFromB5(String value) { + } +} diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.kt b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.kt new file mode 100644 index 00000000000..9cb811d296f --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/B.kt @@ -0,0 +1,20 @@ +package test + +open class B { + val fromB1: String + get() = "" + + var fromB2: String? + get() = "" + set(value) {} + + var fromB3: String? + get() = "" + set(value) {} + + var fromB4: String? + get() = "" + set(value) {} + + open fun setFromB5(value: String?) {} +} \ No newline at end of file diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.java b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.java new file mode 100644 index 00000000000..9a1a6fa4484 --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.java @@ -0,0 +1,57 @@ +package test; + +public abstract class C extends B implements I { + private final int mySomething1; + private int mySomething6; + + C(int something1) { + mySomething1 = something1; + } + + @Override + public int getSomething1() { + return mySomething1; + } + + @Override + public int getSomething2() { + return 0; + } + + @Override + public int getSomething3() { + return 0; + } + + @Override + public void setSomething3(int value) { + } + + @Override + public int getSomething4() { + return 0; + } + + @Override + public void setSomething5(int value) { + + } + + public int getSomething6() { + return mySomething6; + } + + @Override + public void setSomething6(int value) { + mySomething6 = value; + } + + public String getFromB5() { + return ""; + } + + @Override + public void setFromB5(String value) { + super.setFromB5(value); + } +} diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.kt b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.kt new file mode 100644 index 00000000000..5a6b43abcb1 --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/C.kt @@ -0,0 +1,34 @@ +package test + +abstract class C internal constructor(override val something1: Int) : B(), I { + private var mySomething6 = 0 + + override val something2: Int + get() = 0 + + override var something3: Int + get() = 0 + set(value) {} + + override fun getSomething4(): Int { + return 0 + } + + override fun setSomething5(value: Int) {} + fun getSomething6(): Int { + return mySomething6 + } + + override fun setSomething6(value: Int) { + mySomething6 = value + } + + fun getFromB5(): String { + return "" + } + + override fun setFromB5(value: String?) { + super.setFromB5(value) + } + +} \ No newline at end of file diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.java b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.java new file mode 100644 index 00000000000..303af774e81 --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.java @@ -0,0 +1,21 @@ +package test; + +public interface I { + int getSomething1(); + + int getSomething2(); + + int getSomething3(); + + void setSomething3(int value); + + int getSomething4(); + + void setSomething4(int value); + + int getSomething5(); + + void setSomething5(int value); + + void setSomething6(int value); +} diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.kt b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.kt new file mode 100644 index 00000000000..99b8a44c359 --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I.kt @@ -0,0 +1,13 @@ +package test + +interface I { + val something1: Int + val something2: Int + var something3: Int + + fun getSomething4(): Int + fun setSomething4(value: Int) + fun getSomething5(): Int + fun setSomething5(value: Int) + fun setSomething6(value: Int) +} diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.java b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.java new file mode 100644 index 00000000000..2950b6288ac --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.java @@ -0,0 +1,7 @@ +package test; + +public interface I1 extends I { + void setSomething1(int value); + + int getSomething6(); +} diff --git a/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.kt b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.kt new file mode 100644 index 00000000000..7b5bffaaa3b --- /dev/null +++ b/nj2k/testData/multiFile/DetectPropertiesMultipleFiles/I1.kt @@ -0,0 +1,6 @@ +package test + +interface I1 : I { + fun setSomething1(value: Int) + val something6: Int +} diff --git a/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.java b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.java new file mode 100644 index 00000000000..0d77e628404 --- /dev/null +++ b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.java @@ -0,0 +1,5 @@ +package test; + +public interface IUser { + String getName(); +} diff --git a/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.kt b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.kt new file mode 100644 index 00000000000..837991d7278 --- /dev/null +++ b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/IUser.kt @@ -0,0 +1,5 @@ +package test + +interface IUser { + val name: String +} diff --git a/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.java b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.java new file mode 100644 index 00000000000..9e3c75e26ae --- /dev/null +++ b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.java @@ -0,0 +1,14 @@ +package test; + +public class UserImpl implements IUser { + private final String name; + + public UserImpl(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.kt b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.kt new file mode 100644 index 00000000000..77f844aa9b7 --- /dev/null +++ b/nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/UserImpl.kt @@ -0,0 +1,3 @@ +package test + +class UserImpl(override val name: String) : IUser diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/AbstractNewJavaToKotlinConverterMultiFileTest.kt b/nj2k/tests/org/jetbrains/kotlin/nj2k/AbstractNewJavaToKotlinConverterMultiFileTest.kt index bbc94a35ca6..38cff6463af 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/AbstractNewJavaToKotlinConverterMultiFileTest.kt +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/AbstractNewJavaToKotlinConverterMultiFileTest.kt @@ -28,9 +28,11 @@ abstract class AbstractNewJavaToKotlinConverterMultiFileTest : AbstractJavaToKot psiManager.findFile(virtualFile) as PsiJavaFile } - val externalFiles = File(dirPath + File.separator + "external").listFiles { _, name -> - name.endsWith(".java") || name.endsWith(".kt") - }!! + val externalFiles = File(dirPath + File.separator + "external") + .takeIf { it.exists() } + ?.listFiles { _, name -> + name.endsWith(".java") || name.endsWith(".kt") + }.orEmpty() val externalPsiFiles = externalFiles.map { file -> val virtualFile = addFile(file, "test") diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java index 4ebddaeef6c..0d8a41bf97e 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java @@ -34,6 +34,11 @@ public class NewJavaToKotlinConverterMultiFileTestGenerated extends AbstractNewJ runTest("nj2k/testData/multiFile/AnnotationWithArrayParameter/"); } + @TestMetadata("DetectPropertiesMultipleFiles") + public void testDetectPropertiesMultipleFiles() throws Exception { + runTest("nj2k/testData/multiFile/DetectPropertiesMultipleFiles/"); + } + @TestMetadata("FieldToProperty") public void testFieldToProperty() throws Exception { runTest("nj2k/testData/multiFile/FieldToProperty/"); @@ -49,6 +54,11 @@ public class NewJavaToKotlinConverterMultiFileTestGenerated extends AbstractNewJ runTest("nj2k/testData/multiFile/GetterAndSetterUsages/"); } + @TestMetadata("InterfaceWithGetterInOtherFile") + public void testInterfaceWithGetterInOtherFile() throws Exception { + runTest("nj2k/testData/multiFile/InterfaceWithGetterInOtherFile/"); + } + @TestMetadata("KT11952") public void testKT11952() throws Exception { runTest("nj2k/testData/multiFile/KT11952/");