From 1a9deed5d870728c7599d368c571028c35e480a2 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 5 Jun 2019 17:18:34 +0300 Subject: [PATCH] New J2K: add conversion progress bar Relates to #KT-31812 --- .../kotlin/idea/j2k/J2kPostProcessor.kt | 12 +- .../idea/j2k/JavaToKotlinConverterFactory.kt | 13 ++ .../idea/j2k/OldJ2kConverterExtension.kt | 9 ++ .../evaluate/KotlinCodeFragmentFactory.kt | 3 +- .../copy/ConvertJavaCopyPasteProcessor.kt | 43 +++++-- .../copy/ConvertTextJavaCopyPasteProcessor.kt | 9 +- .../kotlin/j2k/AfterConversionPass.kt | 17 ++- .../kotlin/j2k/J2KConverterExtension.kt | 8 ++ .../kotlin/j2k/JavaToKotlinConverter.kt | 47 ++++++-- .../kotlin/nj2k/NewJ2kConveterExtension.kt | 9 ++ .../nj2k/postProcessing/J2kPostProcessor.kt | 21 +++- .../inspectionLikePostProcessings.kt | 15 ++- .../nj2k/postProcessing/postProcessings.kt | 12 +- ...rtGettersAndSettersToPropertyProcessing.kt | 16 ++- .../ConvertToDataClassProcessing.kt | 2 +- .../postProcessing/processings/processings.kt | 8 +- .../kotlin/nj2k/NewJavaToKotlinConverter.kt | 112 ++++++++++++++---- 17 files changed, 277 insertions(+), 79 deletions(-) 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 a44869f707e..b77f5bf669a 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 @@ -27,8 +27,8 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference -import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.core.util.EDT +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 @@ -42,6 +42,9 @@ import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import java.util.* class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor { + + override val phasesCount: Int = 1 + override fun insertImport(file: KtFile, fqName: FqName) { ApplicationManager.getApplication().invokeAndWait { runWriteAction { @@ -57,7 +60,12 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor { PROCESS } - override fun doAdditionalProcessing(file: KtFile, converterContext: ConverterContext?, rangeMarker: RangeMarker?) = + override fun doAdditionalProcessing( + file: KtFile, + converterContext: ConverterContext?, + rangeMarker: RangeMarker?, + onPhaseChanged: ((Int, String) -> Unit)? + ) = runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { do { var modificationStamp: Long? = file.modificationStamp diff --git a/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/JavaToKotlinConverterFactory.kt b/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/JavaToKotlinConverterFactory.kt index 9c87e7a3a71..244d7a3cfb7 100644 --- a/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/JavaToKotlinConverterFactory.kt +++ b/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/JavaToKotlinConverterFactory.kt @@ -6,7 +6,9 @@ package org.jetbrains.kotlin.idea.j2k import com.intellij.openapi.module.Module +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project +import com.intellij.psi.PsiJavaFile import org.jetbrains.kotlin.j2k.* object JavaToKotlinConverterFactory { @@ -20,6 +22,17 @@ object JavaToKotlinConverterFactory { fun createPostProcessor(formatCode: Boolean): PostProcessor = J2kConverterExtension.extension.createPostProcessor(formatCode) + fun createWithProgressIndicator( + progress: ProgressIndicator?, + files: List?, + phasesCount: Int + ): WithProgressProcessor = + J2kConverterExtension.extension.createWithProgressProcessor(progress, files, phasesCount) + + fun doCheckBeforeConversion(project: Project, module: Module): Boolean = J2kConverterExtension.extension.doCheckBeforeConversion(project, module) + + val isNewJ2k: Boolean + get() = J2kConverterExtension.extension.isNewJ2k } \ No newline at end of file diff --git a/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/OldJ2kConverterExtension.kt b/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/OldJ2kConverterExtension.kt index 9c906970175..9ccbfb4213a 100644 --- a/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/OldJ2kConverterExtension.kt +++ b/idea/idea-j2k/src/org/jetbrains/kotlin/idea/j2k/OldJ2kConverterExtension.kt @@ -1,6 +1,8 @@ package org.jetbrains.kotlin.idea.j2k +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project +import com.intellij.psi.PsiJavaFile import org.jetbrains.kotlin.j2k.* class OldJ2kConverterExtension : J2kConverterExtension() { @@ -15,4 +17,11 @@ class OldJ2kConverterExtension : J2kConverterExtension() { override fun createPostProcessor(formatCode: Boolean): PostProcessor = J2kPostProcessor(formatCode) + + override fun createWithProgressProcessor( + progress: ProgressIndicator?, + files: List?, + phasesCount: Int + ): WithProgressProcessor = + OldWithProgressProcessor(progress, files) } \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt index 106b823129b..5ce72737d84 100644 --- a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt +++ b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt @@ -257,7 +257,8 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() { .run( convertedFragment!!, conversionContext, - range = null + range = null, + onPhaseChanged = null ) } } catch (e: Throwable) { diff --git a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt index 251b8ceb19f..e6a79531e56 100644 --- a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt @@ -33,8 +33,8 @@ import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.codeInsight.KotlinCopyPasteReferenceProcessor import org.jetbrains.kotlin.idea.codeInsight.KotlinReferenceData -import org.jetbrains.kotlin.idea.core.util.start import org.jetbrains.kotlin.idea.core.util.range +import org.jetbrains.kotlin.idea.core.util.start import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory @@ -161,12 +161,7 @@ class ConvertJavaCopyPasteProcessor : CopyPastePostProcessor + processor.updateState(0, phase, description) + } + }, + "Convert Java to Kotlin", + true, + project + ) + } else { + AfterConversionPass(project, postProcessor) + .run( + file, + converterContext, + bounds + ) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertTextJavaCopyPasteProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertTextJavaCopyPasteProcessor.kt index ab6ebfb96e5..2ff75684ccc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertTextJavaCopyPasteProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertTextJavaCopyPasteProcessor.kt @@ -36,9 +36,7 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions -import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.j2k.AfterConversionPass import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType @@ -130,12 +128,7 @@ class ConvertTextJavaCopyPasteProcessor : CopyPastePostProcessor Unit)? = null + ) { val rangeMarker = if (range != null) { val document = kotlinFile.viewProvider.document!! - val marker = document.createRangeMarker(range.startOffset, range.endOffset) + val marker = runReadAction { document.createRangeMarker(range.startOffset, range.endOffset) } marker.isGreedyToLeft = true marker.isGreedyToRight = true marker - } else { - null - } + } else null - postProcessor.doAdditionalProcessing(kotlinFile, converterContext, rangeMarker) + postProcessor.doAdditionalProcessing(kotlinFile, converterContext, rangeMarker, onPhaseChanged) } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/J2KConverterExtension.kt b/j2k/src/org/jetbrains/kotlin/j2k/J2KConverterExtension.kt index 3c3bc848894..218fd61bc56 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/J2KConverterExtension.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/J2KConverterExtension.kt @@ -3,8 +3,10 @@ package org.jetbrains.kotlin.j2k import com.intellij.openapi.extensions.AbstractExtensionPointBean import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.openapi.module.Module +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.util.registry.Registry +import com.intellij.psi.PsiJavaFile abstract class J2kConverterExtension : AbstractExtensionPointBean() { abstract val isNewJ2k: Boolean @@ -20,6 +22,12 @@ abstract class J2kConverterExtension : AbstractExtensionPointBean() { open fun doCheckBeforeConversion(project: Project, module: Module): Boolean = true + abstract fun createWithProgressProcessor( + progress: ProgressIndicator?, + files: List?, + phasesCount: Int + ): WithProgressProcessor + companion object { private fun useNewJ2k() = Registry.`is`("kotlin.use.new.j2k", false) diff --git a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt index e76847e408b..51ae114042d 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt @@ -40,7 +40,14 @@ import java.util.* interface PostProcessor { fun insertImport(file: KtFile, fqName: FqName) - fun doAdditionalProcessing(file: KtFile, converterContext: ConverterContext?, rangeMarker: RangeMarker?) + val phasesCount: Int + + fun doAdditionalProcessing( + file: KtFile, + converterContext: ConverterContext?, + rangeMarker: RangeMarker?, + onPhaseChanged: ((Int, String) -> Unit)? + ) } enum class ParseContext { @@ -73,9 +80,7 @@ abstract class JavaToKotlinConverter { progress: ProgressIndicator = EmptyProgressIndicator() ): FilesResult - fun elementsToKotlin(inputElements: List): Result { - return elementsToKotlin(inputElements, WithProgressProcessor.DEFAULT) - } + abstract fun elementsToKotlin(inputElements: List): Result } class OldJavaToKotlinConverter( @@ -91,7 +96,7 @@ class OldJavaToKotlinConverter( postProcessor: PostProcessor, progress: ProgressIndicator ): FilesResult { - val withProgressProcessor = WithProgressProcessor(progress, files) + val withProgressProcessor = OldWithProgressProcessor(progress, files) val (results, externalCodeProcessing) = ApplicationManager.getApplication().runReadAction(Computable { elementsToKotlin(files, withProgressProcessor) }) @@ -106,7 +111,7 @@ class OldJavaToKotlinConverter( result!!.importsToAdd.forEach { postProcessor.insertImport(kotlinFile, it) } - AfterConversionPass(project, postProcessor).run(kotlinFile, converterContext = null, range = null) + AfterConversionPass(project, postProcessor).run(kotlinFile, converterContext = null, range = null, onPhaseChanged = null) kotlinFile.text } catch (e: ProcessCanceledException) { @@ -157,6 +162,11 @@ class OldJavaToKotlinConverter( } } + override fun elementsToKotlin(inputElements: List): Result { + return elementsToKotlin(inputElements, OldWithProgressProcessor.DEFAULT) + } + + private data class ReferenceInfo( val reference: PsiReference, val target: PsiElement, @@ -252,10 +262,21 @@ class OldJavaToKotlinConverter( } } +interface WithProgressProcessor { + fun processItems( + fractionPortion: Double, + inputItems: Iterable, + processItem: (TInputItem) -> TOutputItem + ): List -class WithProgressProcessor(private val progress: ProgressIndicator?, private val files: List?) { + fun updateState(fileIndex: Int, phase: Int, description: String) + fun process(action: () -> T): T +} + + +class OldWithProgressProcessor(private val progress: ProgressIndicator?, private val files: List?) : WithProgressProcessor { companion object { - val DEFAULT = WithProgressProcessor(null, null) + val DEFAULT = OldWithProgressProcessor(null, null) } private val progressText = "Converting Java to Kotlin" @@ -264,7 +285,7 @@ class WithProgressProcessor(private val progress: ProgressIndicator?, private va private var fraction = 0.0 private var pass = 1 - fun processItems( + override fun processItems( fractionPortion: Double, inputItems: Iterable, processItem: (TInputItem) -> TOutputItem @@ -291,6 +312,14 @@ class WithProgressProcessor(private val progress: ProgressIndicator?, private va ) return outputItems } + + override fun process(action: () -> T): T { + throw AbstractMethodError("Should not be called for old J2K") + } + + override fun updateState(fileIndex: Int, phase: Int, description: String) { + throw AbstractMethodError("Should not be called for old J2K") + } } private class ProgressPortionReporter( diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kConveterExtension.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kConveterExtension.kt index 8432a278957..10fd523d2d8 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kConveterExtension.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kConveterExtension.kt @@ -1,8 +1,10 @@ package org.jetbrains.kotlin.nj2k import com.intellij.openapi.module.Module +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.ui.Messages +import com.intellij.psi.PsiJavaFile import org.jetbrains.kotlin.idea.configuration.getAbleToRunConfigurators import org.jetbrains.kotlin.idea.configuration.hasAnyKotlinRuntimeInScope import org.jetbrains.kotlin.idea.configuration.isModuleConfigured @@ -27,6 +29,13 @@ class NewJ2kConverterExtension : J2kConverterExtension() { override fun doCheckBeforeConversion(project: Project, module: Module): Boolean = checkKotlinIsConfigured(project, module) + override fun createWithProgressProcessor( + progress: ProgressIndicator?, + files: List?, + phasesCount: Int + ): WithProgressProcessor = + NewJ2kWithProgressProcessor(progress, files, phasesCount) + private fun checkKotlinIsConfigured(project: Project, module: Module): Boolean { val kotlinIsConfigured = hasAnyKotlinRuntimeInScope(module) || isModuleConfigured(module.toModuleGroup()) 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 ffc94ab0d8d..b15702815cf 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 @@ -58,9 +58,17 @@ class NewJ2kPostProcessor : PostProcessor { } } - override fun doAdditionalProcessing(file: KtFile, converterContext: ConverterContext?, rangeMarker: RangeMarker?) { + override val phasesCount = processings.size + + override fun doAdditionalProcessing( + file: KtFile, + converterContext: ConverterContext?, + rangeMarker: RangeMarker?, + onPhaseChanged: ((Int, String) -> Unit)? + ) { runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { - for (processing in processings) { + for ((i, processing) in processings.withIndex()) { + onPhaseChanged?.invoke(i, processing.description) processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext) commitFile(file) } @@ -82,15 +90,20 @@ private val processings: List = listOf( nullabilityProcessing, formatCodeProcessing, shortenReferencesProcessing, - InspectionLikeProcessingGroup(VarToValProcessing()), + InspectionLikeProcessingGroup(ConvertGettersAndSettersToPropertyProcessing.DESCRIPTION, VarToValProcessing()), ConvertGettersAndSettersToPropertyProcessing(), - InspectionLikeProcessingGroup(MoveGetterAndSetterAnnotationsToPropertyProcessing()), InspectionLikeProcessingGroup( + ConvertGettersAndSettersToPropertyProcessing.DESCRIPTION, + MoveGetterAndSetterAnnotationsToPropertyProcessing() + ), + InspectionLikeProcessingGroup( + ConvertGettersAndSettersToPropertyProcessing.DESCRIPTION, generalInspectionBasedProcessing(RedundantGetterInspection()), generalInspectionBasedProcessing(RedundantSetterInspection()) ), ConvertToDataClassProcessing(), InspectionLikeProcessingGroup( + "Cleaning up Kotlin code", RemoveRedundantVisibilityModifierProcessing(), RemoveRedundantModalityModifierProcessing(), RemoveRedundantConstructorKeywordProcessing(), diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt index 47f641c0c4e..a6f82007f11 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt @@ -16,8 +16,8 @@ import kotlinx.coroutines.withContext import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.core.util.EDT +import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.idea.quickfix.QuickFixActionBase import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.j2k.ConverterSettings -import org.jetbrains.kotlin.nj2k.* +import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.elementsInRange @@ -36,13 +36,18 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.utils.mapToIndex -import java.util.ArrayList +import java.util.* import kotlin.reflect.KClass import kotlin.reflect.full.isSubclassOf -class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List) : ProcessingGroup { - constructor(vararg inspectionLikeProcessings: InspectionLikeProcessing) : this(inspectionLikeProcessings.toList()) +class InspectionLikeProcessingGroup( + override val description: String, + val inspectionLikeProcessings: List +) : ProcessingGroup { + + constructor(description: String, vararg inspectionLikeProcessings: InspectionLikeProcessing) : + this(description, inspectionLikeProcessings.toList()) private val processingsToPriorityMap = inspectionLikeProcessings.mapToIndex() fun priority(processing: InspectionLikeProcessing): Int = processingsToPriorityMap.getValue(processing) 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 ca12037f525..21fef678e4f 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 @@ -18,10 +18,11 @@ import org.jetbrains.kotlin.psi.psiUtil.elementsInRange interface GeneralPostProcessing { + val description: String suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) } -abstract class SimplePostProcessing : GeneralPostProcessing { +abstract class SimplePostProcessing(override val description: String) : GeneralPostProcessing { final override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { withContext(EDT) { CommandProcessor.getInstance().runUndoTransparentAction { @@ -35,7 +36,7 @@ abstract class SimplePostProcessing : GeneralPostProcessing { abstract fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) } -abstract class ElementsBasedPostProcessing : SimplePostProcessing() { +abstract class ElementsBasedPostProcessing(description: String) : SimplePostProcessing(description) { final override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { val elements = rangeMarker?.let { marker -> @@ -49,8 +50,11 @@ abstract class ElementsBasedPostProcessing : SimplePostProcessing() { interface ProcessingGroup : GeneralPostProcessing -fun postProcessing(action: (file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) -> Unit): GeneralPostProcessing = - object : SimplePostProcessing() { +fun postProcessing( + description: String, + action: (file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) -> Unit +): GeneralPostProcessing = + object : SimplePostProcessing(description) { override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { action(file, rangeMarker, converterContext) } 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 07e790c4b06..6846b0ff889 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 @@ -11,7 +11,10 @@ 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.descriptors.* +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.setVisibility import org.jetbrains.kotlin.idea.refactoring.isAbstract @@ -21,11 +24,13 @@ import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.readWriteAccess import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.lexer.KtTokens -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.parentOfType import org.jetbrains.kotlin.nj2k.postProcessing.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* -import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -38,7 +43,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.mapToIndex -class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing() { +class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing(DESCRIPTION) { private fun KtNamedFunction.hasOverrides(): Boolean = toLightMethods().singleOrNull()?.let { lightMethod -> OverridingMethodsSearch.search(lightMethod).findFirst() @@ -520,6 +525,9 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing } } } + companion object { + const val DESCRIPTION = "Converting POJOs to data classes" + } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt index c640e5c611f..ab30d97c23d 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierTypeOrDefault import org.jetbrains.kotlin.types.typeUtil.makeNotNullable -class ConvertToDataClassProcessing : ElementsBasedPostProcessing() { +class ConvertToDataClassProcessing : ElementsBasedPostProcessing(ConvertGettersAndSettersToPropertyProcessing.DESCRIPTION) { private fun KtCallableDeclaration.rename(newName: String) { val factory = KtPsiFactory(this) val escapedName = newName.escaped() 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 23655b72f4b..c098cbdc26f 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 @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.KtPackageDirective import org.jetbrains.kotlin.psi.psiUtil.elementsInRange val formatCodeProcessing = - postProcessing { file, rangeMarker, _ -> + postProcessing("Formating code") { file, rangeMarker, _ -> file.commitAndUnblockDocument() val codeStyleManager = CodeStyleManager.getInstance(file.project) if (rangeMarker != null) { @@ -35,7 +35,7 @@ val formatCodeProcessing = } val nullabilityProcessing = - postProcessing { file, rangeMarker, converterContext -> + postProcessing("Inferring declarations nullability") { file, rangeMarker, converterContext -> NullabilityAnalysisFacade( converterContext, getTypeElementNullability = ::nullabilityByUndefinedNullabilityComment, @@ -45,7 +45,7 @@ val nullabilityProcessing = } val shortenReferencesProcessing = - postProcessing { file, rangeMarker, _ -> + postProcessing("Shortening fully-qualified references") { file, rangeMarker, _ -> if (rangeMarker != null) { ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset) } else { @@ -54,7 +54,7 @@ val shortenReferencesProcessing = } val optimizeImportsProcessing = - postProcessing { file, rangeMarker, _ -> + postProcessing("Optimizing imports") { file, rangeMarker, _ -> val elements = if (rangeMarker != null) { file.elementsInRange(TextRange(rangeMarker.startOffset, rangeMarker.endOffset)) } else file.children.asList() diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt index 522ce1833bf..5890abc5c9a 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt @@ -20,8 +20,10 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ModalityState import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.EmptyProgressIndicator import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project import com.intellij.openapi.util.Computable import com.intellij.psi.PsiElement @@ -50,13 +52,15 @@ class NewJavaToKotlinConverter( postProcessor: PostProcessor, progress: ProgressIndicator ): FilesResult { - val withProgressProcessor = WithProgressProcessor(progress, files) - val (results, externalCodeProcessing, context) = ApplicationManager.getApplication().runReadAction(Computable { - elementsToKotlin(files, withProgressProcessor) - }) + val phasesCount = postProcessor.phasesCount + 1 + val withProgressProcessor = NewJ2kWithProgressProcessor(progress, files, phasesCount) + val (results, externalCodeProcessing, context) = withProgressProcessor.process { + ApplicationManager.getApplication().runReadAction(Computable { + elementsToKotlin(files, withProgressProcessor) + }) + } - val texts = withProgressProcessor.processItems(0.5, results.withIndex()) { pair -> - val (i, result) = pair + val texts = results.mapIndexed { i, result -> try { val kotlinFile = ApplicationManager.getApplication().runReadAction(Computable { KtPsiFactory(project).createFileWithLightClassSupport("dummy.kt", result!!.text, files[i]) @@ -71,9 +75,15 @@ class NewJavaToKotlinConverter( } } } - - AfterConversionPass(project, postProcessor).run(kotlinFile, context, range = null) - + withProgressProcessor.process { + AfterConversionPass(project, postProcessor).run( + kotlinFile, + context, + range = null, + onPhaseChanged = { phase, description -> + withProgressProcessor.updateState(i, phase + 1, description) + }) + } kotlinFile.text } catch (e: ProcessCanceledException) { throw e @@ -87,12 +97,19 @@ class NewJavaToKotlinConverter( } override fun elementsToKotlin(inputElements: List, processor: WithProgressProcessor): Result { + @Suppress("NAME_SHADOWING") + val processor = processor as NewJ2kWithProgressProcessor + + val phaseDescription = "Converting Java code to Kotlin code" val symbolProvider = JKSymbolProvider() symbolProvider.preBuildTree(inputElements) val importStorage = ImportStorage() val treeBuilder = JavaToJKTreeBuilder(symbolProvider, converterServices, importStorage) - val asts = inputElements.map { element -> - element to treeBuilder.buildTree(element) + val asts = processor.process { + inputElements.mapIndexed { i, element -> + processor.updateState(i, 1, phaseDescription) + element to treeBuilder.buildTree(element) + } } val context = NewJ2kConverterContext( @@ -102,22 +119,69 @@ class NewJavaToKotlinConverter( importStorage, JKElementInfoStorage() ) - - ConversionsRunner.doApply(asts.mapNotNull { it.second }, context) - val results = asts.map { (element, ast) -> - if (ast == null) return@map null - val code = NewCodeBuilder(context).run { printCodeOut(ast) } - val parseContext = when (element) { - is PsiStatement, is PsiExpression -> ParseContext.CODE_BLOCK - else -> ParseContext.TOP_LEVEL + processor.process { + ConversionsRunner.doApply(asts.withIndex().mapNotNull { (i, ast) -> + processor.updateState(i, 1, phaseDescription) + ast.second + }, context) + } + val results = processor.process { + asts.mapIndexed { i, elementWithAst -> + processor.updateState(i, 1, phaseDescription) + val (element, ast) = elementWithAst + if (ast == null) return@mapIndexed null + val code = NewCodeBuilder(context).run { printCodeOut(ast) } + val parseContext = when (element) { + is PsiStatement, is PsiExpression -> ParseContext.CODE_BLOCK + else -> ParseContext.TOP_LEVEL + } + ElementResult( + code, + importsToAdd = importStorage.getImports(), + parseContext = parseContext + ) } - ElementResult( - code, - importsToAdd = importStorage.getImports(), - parseContext = parseContext - ) } return Result(results, null, context) } + + override fun elementsToKotlin(inputElements: List): Result { + return elementsToKotlin(inputElements, NewJ2kWithProgressProcessor.DEFAULT) + } +} + +class NewJ2kWithProgressProcessor( + private val progress: ProgressIndicator?, + private val files: List?, + private val phasesCount: Int +) : WithProgressProcessor { + companion object { + val DEFAULT = NewJ2kWithProgressProcessor(null, null, 0) + } + + 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 + } + } + + override fun processItems( + fractionPortion: Double, + inputItems: Iterable, + processItem: (TInputItem) -> TOutputItem + ): List { + throw AbstractMethodError("Should not be called for new J2K") + } + + override fun process(action: () -> T): T { + // we use special process with EmptyProgressIndicator to avoid changing text in our progress by inheritors search inside etc + var result: T? = null + ProgressManager.getInstance().runProcess({ result = action() }, EmptyProgressIndicator()) + return result!! + } + } \ No newline at end of file