New J2K: Add IDEA integration of J2k

This commit is contained in:
Ilya Kirillov
2019-03-13 14:46:02 +03:00
committed by Ilya Kirillov
parent a4e3e7abcc
commit a7d2238af4
25 changed files with 378 additions and 209 deletions
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
import org.jetbrains.kotlin.idea.debugger.evaluate.compilation.DebugLabelPropertyDescriptorProvider
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory
import org.jetbrains.kotlin.idea.refactoring.j2k
import org.jetbrains.kotlin.idea.refactoring.j2kText
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -253,7 +253,7 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() {
kotlinCodeFragment.context
)
AfterConversionPass(project, J2kPostProcessor(formatCode = false)).run(convertedFragment!!, range = null)
AfterConversionPass(project, JavaToKotlinConverterFactory.createPostProcessor(formatCode = false)).run(convertedFragment!!, range = null)
}
} catch (e: Throwable) {
// ignored because text can be invalid
@@ -57,6 +57,9 @@
<extensionPoint qualifiedName="org.jetbrains.kotlin.resolveScopeEnlarger"
interface="org.jetbrains.kotlin.idea.caches.resolve.util.KotlinResolveScopeEnlarger"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.j2kConverterExtension"
interface="org.jetbrains.kotlin.j2k.J2kConverterExtension"/>
</extensionPoints>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
@@ -88,5 +91,15 @@
<scratchFileLanguageProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileLanguageProvider"/>
<scriptRelatedModulesProvider implementation="org.jetbrains.kotlin.idea.scratch.ScratchModuleDependencyProvider"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.idea.j2k.OldJ2kConverterExtension"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.nj2k.NewJ2kConverterExtension"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<registryKey key="kotlin.use.new.j2k"
description="Use new Java to Kotlin Converter (experimental)"
defaultValue="false"
restartRequired="false"/>
</extensions>
</idea-plugin>
@@ -49,6 +49,9 @@
<extensionPoint qualifiedName="org.jetbrains.kotlin.resolveScopeEnlarger"
interface="org.jetbrains.kotlin.idea.caches.resolve.util.KotlinResolveScopeEnlarger"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.j2kConverterExtension"
interface="org.jetbrains.kotlin.j2k.J2kConverterExtension"/>
</extensionPoints>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
@@ -80,5 +83,15 @@
<scratchFileLanguageProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileLanguageProvider"/>
<scriptRelatedModulesProvider implementation="org.jetbrains.kotlin.idea.scratch.ScratchModuleDependencyProvider"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.idea.j2k.OldJ2kConverterExtension"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.nj2k.NewJ2kConverterExtension"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<registryKey key="kotlin.use.new.j2k"
description="Use new Java to Kotlin Converter (experimental)"
defaultValue="false"
restartRequired="false"/>
</extensions>
</idea-plugin>
@@ -47,6 +47,9 @@
interface="org.jetbrains.kotlin.synthetic.SyntheticScopeProviderExtension"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.j2kConverterExtension"
interface="org.jetbrains.kotlin.j2k.J2kConverterExtension"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.resolveScopeEnlarger"
interface="org.jetbrains.kotlin.idea.caches.resolve.util.KotlinResolveScopeEnlarger"/>
</extensionPoints>
@@ -80,5 +83,15 @@
<scratchFileLanguageProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileLanguageProvider"/>
<scriptRelatedModulesProvider implementation="org.jetbrains.kotlin.idea.scratch.ScratchModuleDependencyProvider"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.idea.j2k.OldJ2kConverterExtension"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.nj2k.NewJ2kConverterExtension"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<registryKey key="kotlin.use.new.j2k"
description="Use new Java to Kotlin Converter (experimental)"
defaultValue="false"
restartRequired="false"/>
</extensions>
</idea-plugin>
@@ -47,6 +47,9 @@
interface="org.jetbrains.kotlin.synthetic.SyntheticScopeProviderExtension"
area="IDEA_PROJECT"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.j2kConverterExtension"
interface="org.jetbrains.kotlin.j2k.J2kConverterExtension"/>
<extensionPoint qualifiedName="org.jetbrains.kotlin.resolveScopeEnlarger"
interface="org.jetbrains.kotlin.idea.caches.resolve.util.KotlinResolveScopeEnlarger"/>
</extensionPoints>
@@ -80,5 +83,14 @@
<scratchFileLanguageProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.scratch.KtScratchFileLanguageProvider"/>
<scriptRelatedModulesProvider implementation="org.jetbrains.kotlin.idea.scratch.ScratchModuleDependencyProvider"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.idea.j2k.OldJ2kConverterExtension"/>
<j2kConverterExtension implementation="org.jetbrains.kotlin.nj2k.NewJ2kConverterExtension"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<registryKey key="kotlin.use.new.j2k"
description="Use new Java to Kotlin Converter (experimental)"
defaultValue="false"
restartRequired="false"/>
</extensions>
</idea-plugin>
@@ -44,14 +44,14 @@ import com.intellij.psi.PsiManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.isRunningInCidrIde
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.j2k.FilesResult
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.UserDataProperty
import java.io.File
@@ -110,12 +110,18 @@ class JavaToKotlinAction : AnAction() {
enableExternalCodeProcessing: Boolean = true,
askExternalCodeProcessing: Boolean = true
): List<KtFile> {
var converterResult: JavaToKotlinConverter.FilesResult? = null
var converterResult: FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
val converter =
JavaToKotlinConverterFactory.createJavaToKotlinConverter(
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
javaFiles,
JavaToKotlinConverterFactory.createPostProcessor(formatCode = true),
progress = ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -31,7 +31,6 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.MessageType
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.ex.MessagesEx
import com.intellij.openapi.util.Key
import com.intellij.openapi.ui.popup.JBPopupFactory
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
@@ -44,13 +43,13 @@ import com.intellij.psi.PsiManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.j2k.FilesResult
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
import java.io.IOException
@@ -105,11 +104,17 @@ class JavaToKotlinAction : AnAction() {
enableExternalCodeProcessing: Boolean = true,
askExternalCodeProcessing: Boolean = true
): List<KtFile> {
var converterResult: JavaToKotlinConverter.FilesResult? = null
var converterResult: FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
val converter =
JavaToKotlinConverterFactory.createJavaToKotlinConverter(
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
javaFiles,
JavaToKotlinConverterFactory.createPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -43,13 +43,13 @@ import com.intellij.psi.PsiManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.j2k.FilesResult
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
import java.io.IOException
@@ -104,12 +104,18 @@ class JavaToKotlinAction : AnAction() {
enableExternalCodeProcessing: Boolean = true,
askExternalCodeProcessing: Boolean = true
): List<KtFile> {
var converterResult: JavaToKotlinConverter.FilesResult? = null
var converterResult: FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
val converter =
JavaToKotlinConverterFactory.createJavaToKotlinConverter(
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
javaFiles,
JavaToKotlinConverterFactory.createPostProcessor(formatCode = true),
progress = ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -35,13 +35,12 @@ import org.jetbrains.kotlin.idea.codeInsight.KotlinCopyPasteReferenceProcessor
import org.jetbrains.kotlin.idea.codeInsight.KotlinReferenceData
import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory
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.AfterConversionPass
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.j2k.ParseContext
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
@@ -154,7 +153,7 @@ class ConvertJavaCopyPasteProcessor : CopyPastePostProcessor<TextBlockTransferab
val newBounds = insertImports(boundsAfterReplace, referenceData, explicitImports)
PsiDocumentManager.getInstance(project).commitAllDocuments()
AfterConversionPass(project, J2kPostProcessor(formatCode = true)).run(targetFile, newBounds)
AfterConversionPass(project, JavaToKotlinConverterFactory.createPostProcessor(formatCode = true)).run(targetFile, newBounds)
conversionPerformed = true
}
@@ -207,16 +206,17 @@ internal class ConversionResult(
)
internal fun ElementAndTextList.convertCodeToKotlin(project: Project): ConversionResult {
val converter = JavaToKotlinConverter(
val converter =
JavaToKotlinConverterFactory.createJavaToKotlinConverter(
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
)
)
val inputElements = this.toList().filterIsInstance<PsiElement>()
val results =
ProgressManager.getInstance().runProcessWithProgressSynchronously(
ThrowableComputable<JavaToKotlinConverter.Result, Exception> {
ThrowableComputable<org.jetbrains.kotlin.j2k.Result, Exception> {
runReadAction { converter.elementsToKotlin(inputElements) }
},
JavaToKotlinAction.title,
@@ -36,7 +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.J2kPostProcessor
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
@@ -129,7 +129,7 @@ class ConvertTextJavaCopyPasteProcessor : CopyPastePostProcessor<TextBlockTransf
}
psiDocumentManager.commitAllDocuments()
AfterConversionPass(project, J2kPostProcessor(formatCode = true)).run(targetFile, newBounds)
AfterConversionPass(project, JavaToKotlinConverterFactory.createPostProcessor(formatCode = true)).run(targetFile, newBounds)
conversionPerformed = true
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.idea.j2k
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.j2k.*
object JavaToKotlinConverterFactory {
fun createJavaToKotlinConverter(
project: Project,
settings: ConverterSettings,
services: JavaToKotlinConverterServices
): JavaToKotlinConverter =
J2kConverterExtension.extension.createJavaToKotlinConverter(project, settings, services)
fun createPostProcessor(formatCode: Boolean, settings: ConverterSettings = ConverterSettings.defaultSettings): PostProcessor =
J2kConverterExtension.extension.createPostProcessor(formatCode, settings)
}
@@ -0,0 +1,18 @@
package org.jetbrains.kotlin.idea.j2k
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.j2k.*
class OldJ2kConverterExtension : J2kConverterExtension() {
override val isNewJ2k = false
override fun createJavaToKotlinConverter(
project: Project,
settings: ConverterSettings,
services: JavaToKotlinConverterServices
): JavaToKotlinConverter =
OldJavaToKotlinConverter(project, settings, services)
override fun createPostProcessor(formatCode: Boolean, settings: ConverterSettings): PostProcessor =
J2kPostProcessor(formatCode)
}
@@ -75,6 +75,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.core.util.showYesNoCancelDialog
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.JavaToKotlinConverterFactory
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
@@ -644,11 +645,12 @@ fun createJavaClass(klass: KtClass, targetClass: PsiClass?, forcePlainClass: Boo
fun PsiElement.j2kText(): String? {
if (language != JavaLanguage.INSTANCE) return null
val j2kConverter = JavaToKotlinConverter(
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
)
val j2kConverter =
JavaToKotlinConverterFactory.createJavaToKotlinConverter(
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
)
return j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports
}
@@ -28,8 +28,7 @@ class AfterConversionPass(val project: Project, val postProcessor: PostProcessor
marker.isGreedyToLeft = true
marker.isGreedyToRight = true
marker
}
else {
} else {
null
}
@@ -0,0 +1,29 @@
package org.jetbrains.kotlin.j2k
import com.intellij.openapi.extensions.AbstractExtensionPointBean
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.registry.Registry
abstract class J2kConverterExtension : AbstractExtensionPointBean() {
abstract val isNewJ2k: Boolean
abstract fun createJavaToKotlinConverter(
project: Project,
settings: ConverterSettings,
services: JavaToKotlinConverterServices
): JavaToKotlinConverter
abstract fun createPostProcessor(formatCode: Boolean, settings: ConverterSettings = ConverterSettings.defaultSettings): PostProcessor
companion object {
private fun useNewJ2k() = Registry.`is`("kotlin.use.new.j2k", false)
val EP_NAME = ExtensionPointName.create<J2kConverterExtension>("org.jetbrains.kotlin.j2kConverterExtension")
val extension: J2kConverterExtension
get() = EP_NAME.extensions.first { it.isNewJ2k == useNewJ2k() }
}
}
@@ -47,35 +47,37 @@ enum class ParseContext {
CODE_BLOCK
}
class JavaToKotlinConverter(
private val project: Project,
private val settings: ConverterSettings,
private val services: JavaToKotlinConverterServices
) {
interface ExternalCodeProcessing {
fun prepareWriteOperation(progress: ProgressIndicator): () -> Unit
}
data class ElementResult(val text: String, val importsToAdd: Set<FqName>, val parseContext: ParseContext)
data class Result(val results: List<ElementResult?>, val externalCodeProcessing: ExternalCodeProcessing?)
data class FilesResult(val results: List<String>, val externalCodeProcessing: ExternalCodeProcessing?)
abstract class JavaToKotlinConverter(private val project: Project) {
protected abstract fun elementsToKotlin(inputElements: List<PsiElement>, processor: WithProgressProcessor): Result
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter")
interface ExternalCodeProcessing {
fun prepareWriteOperation(progress: ProgressIndicator): () -> Unit
}
data class ElementResult(val text: String, val importsToAdd: Set<FqName>, val parseContext: ParseContext)
data class Result(val results: List<ElementResult?>, val externalCodeProcessing: ExternalCodeProcessing?)
data class FilesResult(val results: List<String>, val externalCodeProcessing: ExternalCodeProcessing?)
fun filesToKotlin(files: List<PsiJavaFile>, postProcessor: PostProcessor, progress: ProgressIndicator = EmptyProgressIndicator()): FilesResult {
fun filesToKotlin(
files: List<PsiJavaFile>,
postProcessor: PostProcessor,
progress: ProgressIndicator = EmptyProgressIndicator()
): FilesResult {
val withProgressProcessor = WithProgressProcessor(progress, files)
val (results, externalCodeProcessing) = ApplicationManager.getApplication().runReadAction(Computable {
elementsToKotlin(files, withProgressProcessor)
})
val texts = withProgressProcessor.processItems(0.5, results.withIndex()) { pair ->
val (i, result) = pair
try {
val kotlinFile = ApplicationManager.getApplication().runReadAction(Computable {
KtPsiFactory(project).createAnalyzableFile("dummy.kt", result!!.text, files[i])
KtPsiFactory(project).createFileWithLightClassSupport("dummy.kt", result!!.text, files[i])
})
result!!.importsToAdd.forEach { postProcessor.insertImport(kotlinFile, it) }
@@ -83,11 +85,9 @@ class JavaToKotlinConverter(
AfterConversionPass(project, postProcessor).run(kotlinFile, range = null)
kotlinFile.text
}
catch(e: ProcessCanceledException) {
} catch (e: ProcessCanceledException) {
throw e
}
catch(t: Throwable) {
} catch (t: Throwable) {
LOG.error(t)
result!!.text
}
@@ -99,16 +99,22 @@ class JavaToKotlinConverter(
fun elementsToKotlin(inputElements: List<PsiElement>): Result {
return elementsToKotlin(inputElements, WithProgressProcessor.DEFAULT)
}
}
private fun elementsToKotlin(inputElements: List<PsiElement>, processor: WithProgressProcessor): Result {
class OldJavaToKotlinConverter(
project: Project,
private val settings: ConverterSettings,
private val services: JavaToKotlinConverterServices
) : JavaToKotlinConverter(project) {
protected override fun elementsToKotlin(inputElements: List<PsiElement>, processor: WithProgressProcessor): Result {
try {
val usageProcessings = LinkedHashMap<PsiElement, MutableCollection<UsageProcessing>>()
val usageProcessingCollector: (UsageProcessing) -> Unit = {
usageProcessings.getOrPut(it.targetElement, { ArrayList() }).add(it)
}
fun inConversionScope(element: PsiElement)
= inputElements.any { it.isAncestor(element, strict = false) }
fun inConversionScope(element: PsiElement) = inputElements.any { it.isAncestor(element, strict = false) }
val intermediateResults = processor.processItems(0.25, inputElements) { inputElement ->
@@ -127,14 +133,12 @@ class JavaToKotlinConverter(
val externalCodeProcessing = buildExternalCodeProcessing(usageProcessings, ::inConversionScope)
return Result(results, externalCodeProcessing)
}
catch(e: ElementCreationStackTraceRequiredException) {
} catch (e: ElementCreationStackTraceRequiredException) {
// if we got this exception then we need to turn element creation stack traces on to get better diagnostic
Element.saveCreationStacktraces = true
try {
return elementsToKotlin(inputElements)
}
finally {
} finally {
Element.saveCreationStacktraces = false
}
}
@@ -162,7 +166,7 @@ class JavaToKotlinConverter(
.groupBy { it.targetElement }
if (map.isEmpty()) return null
return object: ExternalCodeProcessing {
return object : ExternalCodeProcessing {
override fun prepareWriteOperation(progress: ProgressIndicator): () -> Unit {
val refs = ArrayList<ReferenceInfo>()
@@ -183,7 +187,8 @@ class JavaToKotlinConverter(
.filterNot { inConversionScope(it.element) }
.mapTo(refs) { ReferenceInfo(it, psiElement, it.element.containingFile, processings) }
},
ProgressPortionReporter(progress, i / map.size.toDouble(), 1.0 / map.size))
ProgressPortionReporter(progress, i / map.size.toDouble(), 1.0 / map.size)
)
}
@@ -232,86 +237,89 @@ class JavaToKotlinConverter(
return -info1.offset.compareTo(info2.offset)
}
}
}
private class WithProgressProcessor(private val progress: ProgressIndicator?, private val files: List<PsiJavaFile>?) {
companion object {
val DEFAULT = WithProgressProcessor(null, null)
}
private val progressText = "Converting Java to Kotlin"
private val fileCount = files?.size ?: 0
private val fileCountText = fileCount.toString() + " " + if (fileCount > 1) "files" else "file"
private var fraction = 0.0
private var pass = 1
fun <TInputItem, TOutputItem> processItems(
fractionPortion: Double,
inputItems: Iterable<TInputItem>,
processItem: (TInputItem) -> TOutputItem
): List<TOutputItem> {
val outputItems = ArrayList<TOutputItem>()
// we use special process with EmptyProgressIndicator to avoid changing text in our progress by inheritors search inside etc
ProgressManager.getInstance().runProcess(
{
progress?.text = "$progressText ($fileCountText) - pass $pass of 3"
for ((i, item) in inputItems.withIndex()) {
progress?.checkCanceled()
progress?.fraction = fraction + fractionPortion * i / fileCount
progress?.text2 = files!![i].virtualFile.presentableUrl
outputItems.add(processItem(item))
}
pass++
fraction += fractionPortion
},
EmptyProgressIndicator())
return outputItems
}
class WithProgressProcessor(private val progress: ProgressIndicator?, private val files: List<PsiJavaFile>?) {
companion object {
val DEFAULT = WithProgressProcessor(null, null)
}
private class ProgressPortionReporter(
indicator: ProgressIndicator,
private val start: Double,
private val portion: Double
) : DelegatingProgressIndicator(indicator) {
private val progressText = "Converting Java to Kotlin"
private val fileCount = files?.size ?: 0
private val fileCountText = fileCount.toString() + " " + if (fileCount > 1) "files" else "file"
private var fraction = 0.0
private var pass = 1
init {
fraction = 0.0
}
fun <TInputItem, TOutputItem> processItems(
fractionPortion: Double,
inputItems: Iterable<TInputItem>,
processItem: (TInputItem) -> TOutputItem
): List<TOutputItem> {
val outputItems = ArrayList<TOutputItem>()
// we use special process with EmptyProgressIndicator to avoid changing text in our progress by inheritors search inside etc
ProgressManager.getInstance().runProcess(
{
progress?.text = "$progressText ($fileCountText) - pass $pass of 3"
override fun start() {
fraction = 0.0
}
for ((i, item) in inputItems.withIndex()) {
progress?.checkCanceled()
progress?.fraction = fraction + fractionPortion * i / fileCount
override fun stop() {
fraction = portion
}
progress?.text2 = files!![i].virtualFile.presentableUrl
override fun setFraction(fraction: Double) {
super.setFraction(start + (fraction * portion))
}
outputItems.add(processItem(item))
}
override fun getFraction(): Double {
return (super.getFraction() - start) / portion
}
pass++
fraction += fractionPortion
},
EmptyProgressIndicator()
)
return outputItems
}
}
override fun setText(text: String?) {
}
private class ProgressPortionReporter(
indicator: ProgressIndicator,
private val start: Double,
private val portion: Double
) : DelegatingProgressIndicator(indicator) {
override fun setText2(text: String?) {
}
init {
fraction = 0.0
}
// Copied from com.intellij.ide.util.DelegatingProgressIndicator
private open class DelegatingProgressIndicator : WrappedProgressIndicator, StandardProgressIndicator {
protected val delegate: ProgressIndicator
override fun start() {
fraction = 0.0
}
constructor(indicator: ProgressIndicator) {
delegate = indicator
}
override fun stop() {
fraction = portion
}
override fun setFraction(fraction: Double) {
super.setFraction(start + (fraction * portion))
}
override fun getFraction(): Double {
return (super.getFraction() - start) / portion
}
override fun setText(text: String?) {
}
override fun setText2(text: String?) {
}
}
// Copied from com.intellij.ide.util.DelegatingProgressIndicator
open class DelegatingProgressIndicator : WrappedProgressIndicator, StandardProgressIndicator {
protected val delegate: ProgressIndicator
constructor(indicator: ProgressIndicator) {
delegate = indicator
}
constructor() {
// BUNCH: 181
@@ -320,49 +328,48 @@ class JavaToKotlinConverter(
delegate = indicator ?: EmptyProgressIndicator()
}
override fun start() = delegate.start()
override fun stop() = delegate.stop()
override fun isRunning() = delegate.isRunning
override fun cancel() = delegate.cancel()
override fun isCanceled() = delegate.isCanceled
override fun start() = delegate.start()
override fun stop() = delegate.stop()
override fun isRunning() = delegate.isRunning
override fun cancel() = delegate.cancel()
override fun isCanceled() = delegate.isCanceled
override fun setText(text: String?) {
delegate.text = text
}
override fun getText() = delegate.text
override fun setText2(text: String?) {
delegate.text2 = text
}
override fun getText2() = delegate.text2
override fun getFraction() = delegate.fraction
override fun setFraction(fraction: Double) {
delegate.fraction = fraction
}
override fun pushState() = delegate.pushState()
override fun popState() = delegate.popState()
override fun startNonCancelableSection() = delegate.startNonCancelableSection()
override fun finishNonCancelableSection() = delegate.finishNonCancelableSection()
override fun isModal() = delegate.isModal
override fun getModalityState() = delegate.modalityState
override fun setModalityProgress(modalityProgress: ProgressIndicator?) {
delegate.setModalityProgress(modalityProgress)
}
override fun isIndeterminate() = delegate.isIndeterminate
override fun setIndeterminate(indeterminate: Boolean) {
delegate.isIndeterminate = indeterminate
}
override fun checkCanceled() = delegate.checkCanceled()
override fun getOriginalProgressIndicator() = delegate
override fun isPopupWasShown() = delegate.isPopupWasShown
override fun isShowing() = delegate.isShowing
override fun setText(text: String?) {
delegate.text = text
}
}
override fun getText() = delegate.text
override fun setText2(text: String?) {
delegate.text2 = text
}
override fun getText2() = delegate.text2
override fun getFraction() = delegate.fraction
override fun setFraction(fraction: Double) {
delegate.fraction = fraction
}
override fun pushState() = delegate.pushState()
override fun popState() = delegate.popState()
override fun startNonCancelableSection() = delegate.startNonCancelableSection()
override fun finishNonCancelableSection() = delegate.finishNonCancelableSection()
override fun isModal() = delegate.isModal
override fun getModalityState() = delegate.modalityState
override fun setModalityProgress(modalityProgress: ProgressIndicator?) {
delegate.setModalityProgress(modalityProgress)
}
override fun isIndeterminate() = delegate.isIndeterminate
override fun setIndeterminate(indeterminate: Boolean) {
delegate.isIndeterminate = indeterminate
}
override fun checkCanceled() = delegate.checkCanceled()
override fun getOriginalProgressIndicator() = delegate
override fun isPopupWasShown() = delegate.isPopupWasShown
override fun isShowing() = delegate.isShowing
}
@@ -45,7 +45,7 @@ object JavaToKotlinTranslator {
fun generateKotlinCode(javaCode: String, project: Project): String {
val file = createFile(javaCode, project)
if (file is PsiJavaFile) {
val converter = JavaToKotlinConverter(file.project, ConverterSettings.defaultSettings, EmptyJavaToKotlinServices)
val converter = OldJavaToKotlinConverter(file.project, ConverterSettings.defaultSettings, EmptyJavaToKotlinServices)
return prettify(converter.elementsToKotlin(listOf(file)).results.single()!!.text) //TODO: imports
}
return ""
@@ -53,7 +53,7 @@ abstract class AbstractJavaToKotlinConverterMultiFileTest : AbstractJavaToKotlin
assert(psiFile is PsiJavaFile || psiFile is KtFile)
}
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
val converter = OldJavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
val (results, externalCodeProcessor) = converter.filesToKotlin(psiFilesToConvert, J2kPostProcessor(formatCode = true))
val process = externalCodeProcessor?.prepareWriteOperation(EmptyProgressIndicator())
@@ -110,7 +110,7 @@ abstract class AbstractJavaToKotlinConverterSingleFileTest : AbstractJavaToKotli
protected open fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
val file = createJavaFile(text)
val converter = JavaToKotlinConverter(project, settings, IdeaJavaToKotlinServices)
val converter = OldJavaToKotlinConverter(project, settings, IdeaJavaToKotlinServices)
return converter.filesToKotlin(listOf(file), J2kPostProcessor(formatCode = true)).results.single()
}
+4 -1
View File
@@ -20,7 +20,7 @@ dependencies {
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
testCompile(project(":idea"))
compile(project(":nj2k:nj2k-services"))
testCompile(project(":nj2k:nj2k-services"))
testCompile(projectTests(":idea:idea-test-framework"))
testCompile(project(":compiler:light-classes"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
@@ -93,3 +93,6 @@ fun configureFreeCompilerArg(isEnabled: Boolean, compilerArgument: String) {
}
}
}
ideaPlugin()
+2
View File
@@ -28,6 +28,7 @@ dependencies {
compile(project(":compiler:plugin-api"))
compile(project(":eval4j"))
compile(project(":j2k"))
compile(project(":nj2k"))
compile(project(":idea"))
compile(project(":idea:formatter"))
compile(project(":idea:fir-view"))
@@ -74,3 +75,4 @@ sourceSets {
"main" { projectDefault() }
}
ideaPlugin()
@@ -0,0 +1,18 @@
package org.jetbrains.kotlin.nj2k
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.j2k.*
class NewJ2kConverterExtension : J2kConverterExtension() {
override val isNewJ2k = true
override fun createJavaToKotlinConverter(
project: Project,
settings: ConverterSettings,
services: JavaToKotlinConverterServices
): JavaToKotlinConverter =
NewJavaToKotlinConverter(project, settings, services)
override fun createPostProcessor(formatCode: Boolean, settings: ConverterSettings): PostProcessor =
NewJ2kPostProcessor(formatCode, settings)
}
@@ -28,8 +28,8 @@ class JKSymbolProvider {
private val elementVisitor = ElementVisitor()
fun preBuildTree(files: List<PsiJavaFile>) {
files.forEach { it.accept(elementVisitor) }
fun preBuildTree(inputElements: List<PsiElement>) {
inputElements.forEach { it.accept(elementVisitor) }
}
private fun symbolForNonKotlinElement(psi: PsiElement) =
@@ -16,20 +16,21 @@
package org.jetbrains.kotlin.nj2k
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiJavaFile
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.nj2k.tree.JKTreeElement
import org.jetbrains.kotlin.nj2k.tree.prettyDebugPrintTree
import org.jetbrains.kotlin.psi.KtPsiFactory
class NewJavaToKotlinConverter(
val project: Project,
val settings: ConverterSettings,
val converterServices: NewJavaToKotlinServices
) {
val oldConverterServices: JavaToKotlinConverterServices
) : JavaToKotlinConverter(project) {
val converterServices = object : NewJavaToKotlinServices {
override val oldServices = oldConverterServices
}
private fun List<JKTreeElement>.prettyPrintTrees() = buildString {
for (tree in this@prettyPrintTrees) {
@@ -39,25 +40,25 @@ class NewJavaToKotlinConverter(
}
}
fun filesToKotlin(files: List<PsiJavaFile>, progressIndicator: ProgressIndicator = EmptyProgressIndicator()): List<String> {
override fun elementsToKotlin(inputElements: List<PsiElement>, processor: WithProgressProcessor): Result {
val symbolProvider = JKSymbolProvider()
symbolProvider.preBuildTree(files)
symbolProvider.preBuildTree(inputElements)
val treeBuilder = JavaToJKTreeBuilder(symbolProvider, converterServices)
val fileTrees = files.mapNotNull(treeBuilder::buildTree)
// println(fileTrees.prettyPrintTrees())
val asts = inputElements.mapNotNull(treeBuilder::buildTree)
val factory = KtPsiFactory(project, true)
val context = ConversionContext(
symbolProvider,
this,
{ it: PsiElement -> it.containingFile in files }
{ it.containingFile in inputElements }
)
ConversionsRunner.doApply(asts, context)
val kotlinCodes = asts.map { NewCodeBuilder().run { printCodeOut(it) } }
return Result(
kotlinCodes.map { code ->
ElementResult(code, emptySet(), ParseContext.TOP_LEVEL)
},
null
)
ConversionsRunner.doApply(fileTrees, context)
// val resultTree = fileTrees.prettyPrintTrees()
// println(resultTree)
return fileTrees.map { NewCodeBuilder().run { printCodeOut(it) } }
}
}
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.nj2k
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.nj2k.NewJ2kPostProcessor
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterSingleFileTest
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.psi.KtPsiFactory
@@ -32,14 +32,15 @@ abstract class AbstractNewJavaToKotlinConverterSingleFileTest : AbstractJavaToKo
val postProcessor = NewJ2kPostProcessor(true, settings)
return NewJavaToKotlinConverter(project, settings, IdeaNewJavaToKotlinServices).filesToKotlin(listOf(file)).map {
factory.createFileWithLightClassSupport("Dummy.kt", it, file)
}.map {
CommandProcessor.getInstance().runUndoTransparentAction {
postProcessor.doAdditionalProcessing(it, null)
return NewJavaToKotlinConverter(project, settings, IdeaJavaToKotlinServices)
.filesToKotlin(listOf(file), NewJ2kPostProcessor(true, settings)).let { (results, _) ->
factory.createFileWithLightClassSupport("Dummy.kt", results.single(), file)
}.let {
CommandProcessor.getInstance().runUndoTransparentAction {
postProcessor.doAdditionalProcessing(it, null)
}
it.text
}
it.text
}.single()
}
override fun provideExpectedFile(javaPath: String): File =