mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
[kotlin] J2K copy-paste: share most code, create extensions for K1/K2-specific classes
J2K copy-paste processors are enabled in K2 but don't work yet. Now all J2K-related code (except JavaToKotlinAction) is located in `j2k` modules. KTIJ-28714 (cherry picked from commit 71774b698b53420dc95637b720ab3e4c3ec05867) GitOrigin-RevId: 2e5432817ec7d8d512be25704dd0bb4f57e0c999
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9cae14134a
commit
d3622f59eb
@@ -525,14 +525,6 @@ project.view.class.initializer=class initializer
|
||||
project.view.expression=expression
|
||||
project.view.class.error.name=no name provided
|
||||
|
||||
copy.text.adding.imports=Adding imports\u2026
|
||||
copy.text.clipboard.content.seems.to.be.java.code.do.you.want.to.convert.it.to.kotlin=Clipboard content seems to be Java code. Do you want to convert it to Kotlin?
|
||||
copy.text.convert.java.to.kotlin.title=Convert Java to Kotlin
|
||||
copy.text.copied.kotlin.code=Copied Kotlin code
|
||||
copy.text.resolving.references=Resolving references\u2026
|
||||
copy.text.rendering.declaration.stubs=Rendering Declaration Stubs\u2026
|
||||
copy.title.convert.code.from.java=Convert Code From Java
|
||||
|
||||
editor.checkbox.title.auto.add.val.keyword.to.data.value.class.constructor.parameters=Auto add 'val' keyword to data/value class constructor parameters
|
||||
editor.checkbox.title.convert.pasted.java.code.to.kotlin=Convert pasted Java code to Kotlin
|
||||
editor.checkbox.title.don.t.show.java.to.kotlin.conversion.dialog.on.paste=Don't show Java to Kotlin conversion dialog on paste
|
||||
|
||||
@@ -73,8 +73,6 @@
|
||||
<orderEntry type="library" name="kotlinc.kotlin-jps-common" level="project" />
|
||||
<orderEntry type="library" name="kotlinc.kotlin-jps-plugin-classpath" level="project" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.shared" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.k1.old" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.k1.new" />
|
||||
<orderEntry type="module" module-name="kotlin.formatter" />
|
||||
<orderEntry type="module" module-name="kotlin.scripting" />
|
||||
<orderEntry type="module" module-name="kotlin.inspections" />
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.j2k.post.processing
|
||||
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
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.copyPaste.K1J2KCopyPasteConverter
|
||||
import org.jetbrains.kotlin.j2k.*
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension.Kind.K1_NEW
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.DataForConversion
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.J2KCopyPasteConverter
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.K1PlainTextPasteImportResolver
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.PlainTextPasteImportResolver
|
||||
import org.jetbrains.kotlin.nj2k.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
@@ -34,4 +42,23 @@ class NewJ2kConverterExtension : J2kConverterExtension() {
|
||||
|
||||
override fun getConversions(context: NewJ2kConverterContext): List<Conversion> =
|
||||
getNewJ2KConversions(context)
|
||||
|
||||
override fun createPlainTextPasteImportResolver(
|
||||
dataForConversion: DataForConversion,
|
||||
targetKotlinFile: KtFile
|
||||
): PlainTextPasteImportResolver {
|
||||
return K1PlainTextPasteImportResolver(dataForConversion, targetKotlinFile)
|
||||
}
|
||||
|
||||
override fun createCopyPasteConverter(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
dataForConversion: DataForConversion,
|
||||
j2kKind: Kind,
|
||||
targetFile: KtFile,
|
||||
targetBounds: RangeMarker,
|
||||
targetDocument: Document
|
||||
): J2KCopyPasteConverter {
|
||||
return K1J2KCopyPasteConverter(project, editor, dataForConversion, j2kKind, targetFile, targetBounds, targetDocument)
|
||||
}
|
||||
}
|
||||
@@ -40,5 +40,6 @@
|
||||
<orderEntry type="module" module-name="kotlin.base.plugin" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.shared" />
|
||||
<orderEntry type="module" module-name="kotlin.base.code-insight" />
|
||||
<orderEntry type="module" module-name="kotlin.idea" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -16,7 +16,8 @@ import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.j2k.ConverterContext
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension
|
||||
import org.jetbrains.kotlin.j2k.ParseContext
|
||||
import org.jetbrains.kotlin.j2k.ParseContext.*
|
||||
import org.jetbrains.kotlin.j2k.ParseContext.CODE_BLOCK
|
||||
import org.jetbrains.kotlin.j2k.ParseContext.TOP_LEVEL
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
@@ -25,7 +26,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
* Runs J2K on the pasted code and updates [targetFile] as a side effect.
|
||||
* Used by [ConvertJavaCopyPasteProcessor].
|
||||
*/
|
||||
class J2KCopyPasteConverter(
|
||||
class K1J2KCopyPasteConverter(
|
||||
private val project: Project,
|
||||
private val editor: Editor,
|
||||
private val dataForConversion: DataForConversion,
|
||||
@@ -33,7 +34,7 @@ class J2KCopyPasteConverter(
|
||||
private val targetFile: KtFile,
|
||||
private val targetBounds: RangeMarker,
|
||||
private val targetDocument: Document
|
||||
) {
|
||||
) : J2KCopyPasteConverter {
|
||||
/**
|
||||
* @property changedText The transformed Kotlin code, or `null` if no conversion occurred (the result is the same as original code).
|
||||
* @property referenceData A list of references within the converted Kotlin code that may need to be processed or resolved.
|
||||
@@ -48,7 +49,7 @@ class J2KCopyPasteConverter(
|
||||
|
||||
private lateinit var result: Result
|
||||
|
||||
fun convert() {
|
||||
override fun convert() {
|
||||
if (!::result.isInitialized && convertAndRestoreReferencesIfTextIsUnchanged()) return
|
||||
|
||||
val (changedText, referenceData, importsToAdd, converterContext) = result
|
||||
@@ -66,15 +67,7 @@ class J2KCopyPasteConverter(
|
||||
runPostProcessing(project, targetFile, newBounds, converterContext, j2kKind)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a shortcut for copy-pasting trivial code that doesn't need to be converted (for example, a single identifier).
|
||||
* In this case, we don't bother showing a J2K dialog and only restore references / insert required imports in the Kotlin file.
|
||||
*
|
||||
* Always runs the J2K conversion once and saves the result for later reference.
|
||||
*
|
||||
* @return `true` if the conversion text remains unchanged; `false` otherwise.
|
||||
*/
|
||||
fun convertAndRestoreReferencesIfTextIsUnchanged(): Boolean {
|
||||
override fun convertAndRestoreReferencesIfTextIsUnchanged(): Boolean {
|
||||
fun runConversion() {
|
||||
val conversionResult = dataForConversion.elementsAndTexts.convertCodeToKotlin(project, targetFile, j2kKind)
|
||||
val (text, parseContext, importsToAdd, isTextChanged, converterContext) = conversionResult
|
||||
@@ -167,4 +160,4 @@ class J2KCopyPasteConverter(
|
||||
|
||||
return rangeMarker.asTextRange
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.idea.base.projectStructure.RootKindFilter
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.matches
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfoOrNull
|
||||
import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.base.util.K1ModeProjectStructureApi
|
||||
import org.jetbrains.kotlin.idea.base.util.runReadActionInSmartMode
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
@@ -24,24 +24,17 @@ import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.nj2k.KotlinNJ2KBundle
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
|
||||
|
||||
/**
|
||||
* This class tries to prepare the plain text Java code for J2K by adding necessary imports so that
|
||||
* such code can be properly resolved and converted.
|
||||
*
|
||||
* 1. For every Kotlin file import statement, try to convert it to a Java PSI import and add it to the Java file.
|
||||
* 2. For every unresolved short reference in the dummy Java file:
|
||||
* * Try to find a visible class, method, or field with the same short name
|
||||
* * If such a declaration is found, add an import for it (usually to both the Java and Kotlin files).
|
||||
* Note: imports for Java are added at once, but for Kotlin they are returned as a list, to be converted by J2K later.
|
||||
*
|
||||
* Tests: [org.jetbrains.kotlin.nj2k.TextNewJavaToKotlinCopyPasteConversionTestGenerated].
|
||||
*/
|
||||
class PlainTextPasteImportResolver(private val dataForConversion: DataForConversion, private val targetKotlinFile: KtFile) {
|
||||
class K1PlainTextPasteImportResolver(private val dataForConversion: DataForConversion, private val targetKotlinFile: KtFile) :
|
||||
PlainTextPasteImportResolver {
|
||||
private val sourceJavaFile: PsiJavaFile = dataForConversion.sourceJavaFile
|
||||
private val javaFileImportList: PsiImportList = sourceJavaFile.importList!!
|
||||
private val project = targetKotlinFile.project
|
||||
@@ -55,7 +48,7 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
||||
private val failedToResolveReferenceNames: MutableSet<String> = mutableSetOf()
|
||||
private val importsToAddToKotlinFile: MutableList<PsiImportStatementBase> = mutableListOf()
|
||||
|
||||
fun generateRequiredImports(): List<PsiImportStatementBase> {
|
||||
override fun generateRequiredImports(): List<PsiImportStatementBase> {
|
||||
addImportsToJavaFileFromKotlinFile()
|
||||
tryToResolveShortReferencesByAddingImports()
|
||||
return importsToAddToKotlinFile
|
||||
@@ -67,14 +60,14 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
||||
if (javaFileImportList in dataForConversion.elementsAndTexts.toList()) return
|
||||
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
addImportsTask, KotlinBundle.message("copy.text.adding.imports"), /* canBeCanceled = */ true, project
|
||||
addImportsTask, KotlinNJ2KBundle.message("copy.text.adding.imports"), /* canBeCanceled = */ true, project
|
||||
)
|
||||
}
|
||||
|
||||
private fun tryToResolveShortReferencesByAddingImports() {
|
||||
ProgressManager.checkCanceled()
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
resolveReferencesTask, KotlinBundle.message("copy.text.resolving.references"), /* canBeCanceled = */ true, project
|
||||
resolveReferencesTask, KotlinNJ2KBundle.message("copy.text.resolving.references"), /* canBeCanceled = */ true, project
|
||||
)
|
||||
}
|
||||
|
||||
@@ -236,6 +229,7 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(K1ModeProjectStructureApi::class)
|
||||
private fun findUniqueMemberByShortName(name: String): PsiMember? {
|
||||
return runReadAction {
|
||||
val candidateMembers: List<PsiMember> =
|
||||
@@ -3,7 +3,7 @@
|
||||
package org.jetbrains.kotlin.nj2k
|
||||
|
||||
import org.jetbrains.kotlin.idea.base.test.KotlinRoot
|
||||
import org.jetbrains.kotlin.idea.conversion.copy.AbstractJavaToKotlinCopyPasteConversionTest
|
||||
import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinCopyPasteConversionTest
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractK1JavaToKotlinCopyPasteConversionTest : AbstractJavaToKotlinCopyPasteConversionTest() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.nj2k
|
||||
|
||||
import org.jetbrains.kotlin.idea.conversion.copy.AbstractTextJavaToKotlinCopyPasteConversionTest
|
||||
import org.jetbrains.kotlin.j2k.AbstractTextJavaToKotlinCopyPasteConversionTest
|
||||
|
||||
abstract class AbstractK1TextJavaToKotlinCopyPasteConversionTest : AbstractTextJavaToKotlinCopyPasteConversionTest() {
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
<orderEntry type="library" name="kotlinc.analysis-api" level="project" />
|
||||
<orderEntry type="module" module-name="kotlin.base.util" />
|
||||
<orderEntry type="module" module-name="kotlin.core" />
|
||||
<orderEntry type="module" module-name="kotlin.idea" />
|
||||
<orderEntry type="module" module-name="kotlin.fir.frontend-independent" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang" />
|
||||
<orderEntry type="module" module-name="intellij.java.psi.impl" />
|
||||
@@ -38,5 +39,6 @@
|
||||
<orderEntry type="module" module-name="intellij.java.analysis.impl" />
|
||||
<orderEntry type="module" module-name="kotlin.base.plugin" />
|
||||
<orderEntry type="module" module-name="kotlin.base.fe10.code-insight" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.k1.new" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -2,11 +2,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.j2k
|
||||
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
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.copyPaste.K1J2KCopyPasteConverter
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension.Kind.K1_OLD
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.DataForConversion
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.J2KCopyPasteConverter
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.K1PlainTextPasteImportResolver
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.PlainTextPasteImportResolver
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
class OldJ2kConverterExtension : J2kConverterExtension() {
|
||||
@@ -32,4 +40,23 @@ class OldJ2kConverterExtension : J2kConverterExtension() {
|
||||
|
||||
override fun doCheckBeforeConversion(project: Project, module: Module): Boolean =
|
||||
true
|
||||
|
||||
override fun createPlainTextPasteImportResolver(
|
||||
dataForConversion: DataForConversion,
|
||||
targetKotlinFile: KtFile
|
||||
): PlainTextPasteImportResolver {
|
||||
return K1PlainTextPasteImportResolver(dataForConversion, targetKotlinFile)
|
||||
}
|
||||
|
||||
override fun createCopyPasteConverter(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
dataForConversion: DataForConversion,
|
||||
j2kKind: Kind,
|
||||
targetFile: KtFile,
|
||||
targetBounds: RangeMarker,
|
||||
targetDocument: Document
|
||||
): J2KCopyPasteConverter {
|
||||
return K1J2KCopyPasteConverter(project, editor, dataForConversion, j2kKind, targetFile, targetBounds, targetDocument)
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.j2k.k2
|
||||
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
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.*
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension.Kind.K2
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.DataForConversion
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.J2KCopyPasteConverter
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.PlainTextPasteImportResolver
|
||||
import org.jetbrains.kotlin.nj2k.Conversion
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kWithProgressProcessor
|
||||
@@ -40,4 +46,23 @@ class K2J2KConverterExtension : J2kConverterExtension() {
|
||||
|
||||
override fun getConversions(context: NewJ2kConverterContext): List<Conversion> =
|
||||
getK2J2KConversions(context)
|
||||
|
||||
override fun createPlainTextPasteImportResolver(
|
||||
dataForConversion: DataForConversion,
|
||||
targetKotlinFile: KtFile
|
||||
): PlainTextPasteImportResolver {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun createCopyPasteConverter(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
dataForConversion: DataForConversion,
|
||||
j2kKind: Kind,
|
||||
targetFile: KtFile,
|
||||
targetBounds: RangeMarker,
|
||||
targetDocument: Document
|
||||
): J2KCopyPasteConverter {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -44,5 +44,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="kotlin.project-configuration" />
|
||||
<orderEntry type="module" module-name="kotlin.preferences" />
|
||||
<orderEntry type="module" module-name="kotlin.base.statistics" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -16,4 +16,12 @@ converter.kotlin.not.configured.no.configurators.available=There are no configur
|
||||
converter.kotlin.not.configured.configure=OK, Configure Kotlin In the Project
|
||||
converter.kotlin.not.configured.cancel.conversion=No, Cancel Conversion
|
||||
converter.kotlin.not.configured.choose.configurator=Choose configurator
|
||||
converter.kotlin.wait.for.sync.to.be.finished=Waiting for sync to be finished
|
||||
converter.kotlin.wait.for.sync.to.be.finished=Waiting for sync to be finished
|
||||
|
||||
copy.text.convert.java.to.kotlin.title=Convert Java to Kotlin
|
||||
copy.title.convert.code.from.java=Convert Code From Java
|
||||
copy.text.clipboard.content.seems.to.be.java.code.do.you.want.to.convert.it.to.kotlin=Clipboard content seems to be Java code. Do you want to convert it to Kotlin?
|
||||
copy.text.copied.kotlin.code=Copied Kotlin code
|
||||
copy.text.rendering.declaration.stubs=Rendering Declaration Stubs\u2026
|
||||
copy.text.adding.imports=Adding Imports\u2026
|
||||
copy.text.resolving.references=Resolving References\u2026
|
||||
@@ -8,18 +8,24 @@ import com.intellij.psi.PsiExpression
|
||||
import com.intellij.psi.PsiMember
|
||||
import org.jetbrains.kotlin.j2k.ConverterSettings
|
||||
import org.jetbrains.kotlin.j2k.ConverterSettings.Companion.defaultSettings
|
||||
import org.jetbrains.kotlin.j2k.OldJavaToKotlinConverter
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension.Kind.K1_OLD
|
||||
import org.jetbrains.kotlin.j2k.Result
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
|
||||
// Old J2K utilities used from "kotlin.idea" module in K1.
|
||||
// They are located in "kotlin.j2k.shared" module to avoid circular dependencies.
|
||||
|
||||
fun PsiElement.j2kText(settings: ConverterSettings = defaultSettings): String? =
|
||||
convertToKotlin(settings)?.results?.single()?.text //TODO: insert imports
|
||||
|
||||
fun PsiElement.convertToKotlin(settings: ConverterSettings = defaultSettings): Result? {
|
||||
if (language != JavaLanguage.INSTANCE) return null
|
||||
val j2kConverter = OldJavaToKotlinConverter(project, settings)
|
||||
val extension = J2kConverterExtension.extension(kind = K1_OLD)
|
||||
extension.createJavaToKotlinConverter(project, targetModule = null, settings)
|
||||
val j2kConverter = extension.createJavaToKotlinConverter(project, targetModule = null, settings)
|
||||
return j2kConverter.elementsToKotlin(listOf(this))
|
||||
}
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.j2k
|
||||
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
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.psi.PsiJavaFile
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.DataForConversion
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.J2KCopyPasteConverter
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.PlainTextPasteImportResolver
|
||||
import org.jetbrains.kotlin.nj2k.Conversion
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -44,6 +50,21 @@ abstract class J2kConverterExtension {
|
||||
open fun getConversions(context: NewJ2kConverterContext): List<Conversion> =
|
||||
emptyList()
|
||||
|
||||
abstract fun createPlainTextPasteImportResolver(
|
||||
dataForConversion: DataForConversion,
|
||||
targetKotlinFile: KtFile
|
||||
): PlainTextPasteImportResolver
|
||||
|
||||
abstract fun createCopyPasteConverter(
|
||||
project: Project,
|
||||
editor: Editor,
|
||||
dataForConversion: DataForConversion,
|
||||
j2kKind: Kind,
|
||||
targetFile: KtFile,
|
||||
targetBounds: RangeMarker,
|
||||
targetDocument: Document
|
||||
): J2KCopyPasteConverter
|
||||
|
||||
companion object {
|
||||
val EP_NAME = ExtensionPointName<J2kConverterExtension>("org.jetbrains.kotlin.j2kConverterExtension")
|
||||
|
||||
|
||||
@@ -169,4 +169,4 @@ internal object ConversionTextClipper {
|
||||
|
||||
return clipTo
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions
|
||||
import org.jetbrains.kotlin.idea.statistics.ConversionType
|
||||
import org.jetbrains.kotlin.idea.statistics.J2KFusCollector
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension
|
||||
import org.jetbrains.kotlin.j2k.J2kConverterExtension.Kind.K1_NEW
|
||||
import java.awt.datatransfer.Transferable
|
||||
import kotlin.system.measureTimeMillis
|
||||
@@ -70,7 +71,9 @@ class ConvertJavaCopyPasteProcessor : CopyPastePostProcessor<TextBlockTransferab
|
||||
val copiedJavaCode = values.single() as CopiedJavaCode
|
||||
val dataForConversion = DataForConversion.prepare(copiedJavaCode, project)
|
||||
val j2kKind = getJ2kKind(targetFile)
|
||||
val converter = J2KCopyPasteConverter(project, editor, dataForConversion, j2kKind, targetFile, targetBounds, targetDocument)
|
||||
|
||||
val converter = J2kConverterExtension.extension(j2kKind)
|
||||
.createCopyPasteConverter(project, editor, dataForConversion, j2kKind, targetFile, targetBounds, targetDocument)
|
||||
|
||||
val textLength = copiedJavaCode.startOffsets.indices.sumOf { copiedJavaCode.endOffsets[it] - copiedJavaCode.startOffsets[it] }
|
||||
if (textLength < MAX_TEXT_LENGTH_TO_CONVERT_WITHOUT_ASKING_USER && converter.convertAndRestoreReferencesIfTextIsUnchanged()) {
|
||||
@@ -97,4 +100,4 @@ class ConvertJavaCopyPasteProcessor : CopyPastePostProcessor<TextBlockTransferab
|
||||
@get:TestOnly
|
||||
var conversionPerformed: Boolean = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,7 @@
|
||||
package org.jetbrains.kotlin.j2k.copyPaste
|
||||
|
||||
import com.intellij.codeInsight.editorActions.TextBlockTransferableData
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.KotlinNJ2KBundle
|
||||
import java.awt.datatransfer.DataFlavor
|
||||
|
||||
/**
|
||||
@@ -15,6 +14,6 @@ class CopiedKotlinCode : TextBlockTransferableData {
|
||||
override fun getFlavor(): DataFlavor = DATA_FLAVOR
|
||||
|
||||
companion object {
|
||||
val DATA_FLAVOR: DataFlavor = DataFlavor(CopiedKotlinCode::class.java, KotlinBundle.message("copy.text.copied.kotlin.code"))
|
||||
val DATA_FLAVOR: DataFlavor = DataFlavor(CopiedKotlinCode::class.java, KotlinNJ2KBundle.message("copy.text.copied.kotlin.code"))
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,6 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.base.util.module
|
||||
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures.NewJ2k
|
||||
import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions
|
||||
@@ -21,6 +19,7 @@ import org.jetbrains.kotlin.j2k.J2kConverterExtension.Kind.K1_OLD
|
||||
import org.jetbrains.kotlin.j2k.ParseContext.CODE_BLOCK
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.nj2k.KotlinNJ2KBundle
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
|
||||
@@ -53,7 +52,7 @@ fun ElementAndTextList.convertCodeToKotlin(
|
||||
ThrowableComputable {
|
||||
runReadAction { converter.elementsToKotlin(inputElements) }
|
||||
},
|
||||
JavaToKotlinAction.Handler.title,
|
||||
KotlinNJ2KBundle.message("copy.text.convert.java.to.kotlin.title"),
|
||||
true,
|
||||
project
|
||||
)
|
||||
@@ -162,11 +161,11 @@ fun runPostProcessing(
|
||||
}
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
runnable,
|
||||
KotlinBundle.message("copy.text.convert.java.to.kotlin.title"),
|
||||
KotlinNJ2KBundle.message("copy.text.convert.java.to.kotlin.title"),
|
||||
/* canBeCanceled = */ true,
|
||||
project
|
||||
)
|
||||
} else {
|
||||
J2KPostProcessingRunner.run(postProcessor, file, converterContext, bounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,4 +128,4 @@ private fun extractSignificantImportsAndPackage(sourceFile: PsiJavaFile): String
|
||||
}
|
||||
//TODO: static imports
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,4 +45,4 @@ class ElementAndTextList() {
|
||||
interface ElementsAndTextsProcessor {
|
||||
fun processElement(element: PsiElement)
|
||||
fun processText(text: String)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.j2k.copyPaste
|
||||
|
||||
/**
|
||||
* Runs J2K on the pasted code and updates the target Kotlin file as a side effect.
|
||||
* Used by [ConvertJavaCopyPasteProcessor].
|
||||
*/
|
||||
interface J2KCopyPasteConverter {
|
||||
fun convert()
|
||||
|
||||
/**
|
||||
* This is a shortcut for copy-pasting trivial code that doesn't need to be converted (for example, a single identifier).
|
||||
* In this case, we don't bother showing a J2K dialog and only restore references / insert required imports in the Kotlin file.
|
||||
*
|
||||
* Always runs the J2K conversion once and saves the result for later reference.
|
||||
*
|
||||
* @return `true` if the conversion text remains unchanged; `false` otherwise.
|
||||
*/
|
||||
fun convertAndRestoreReferencesIfTextIsUnchanged(): Boolean
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
* Runs J2K on the pasted code and updates [targetFile] as a side effect.
|
||||
* Used by [ConvertTextJavaCopyPasteProcessor].
|
||||
*/
|
||||
class J2KTextCopyPasteConverter(
|
||||
internal class J2KTextCopyPasteConverter(
|
||||
private val project: Project,
|
||||
private val editor: Editor,
|
||||
private val dataForConversion: DataForConversion,
|
||||
@@ -67,11 +67,12 @@ class J2KTextCopyPasteConverter(
|
||||
}
|
||||
|
||||
private fun tryToResolveImports(dataForConversion: DataForConversion, targetFile: KtFile): ElementAndTextList {
|
||||
val imports = PlainTextPasteImportResolver(dataForConversion, targetFile).generateRequiredImports()
|
||||
val resolver = J2kConverterExtension.extension(j2kKind).createPlainTextPasteImportResolver(dataForConversion, targetFile)
|
||||
val imports = resolver.generateRequiredImports()
|
||||
val newlineSeparatedImports = imports.flatMap { importStatement ->
|
||||
listOf("\n", importStatement)
|
||||
} + "\n\n"
|
||||
|
||||
return ElementAndTextList(newlineSeparatedImports)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,15 @@ import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
import org.jetbrains.kotlin.analysis.api.types.symbol
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.getFqNameIfPackageOrNonLocal
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.nj2k.KotlinNJ2KBundle
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.blockExpressionsOrSingle
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
internal data class JavaContextDeclarationStubs(
|
||||
data class JavaContextDeclarationStubs(
|
||||
val localDeclarations: String,
|
||||
val memberDeclarations: String
|
||||
)
|
||||
@@ -37,7 +37,7 @@ internal data class JavaContextDeclarationStubs(
|
||||
* In plain text conversion, we don't have an original Java `PsiFile` from which to draw context.
|
||||
* So, we do the next best thing: take an approximation of the context from the target Kotlin file.
|
||||
*/
|
||||
internal object JavaContextDeclarationRenderer {
|
||||
object JavaContextDeclarationRenderer {
|
||||
fun render(contextElement: KtElement): JavaContextDeclarationStubs {
|
||||
val task: () -> JavaContextDeclarationStubs = {
|
||||
runReadAction {
|
||||
@@ -52,7 +52,7 @@ internal object JavaContextDeclarationRenderer {
|
||||
}
|
||||
|
||||
return ProgressManager.getInstance().runProcessWithProgressSynchronously<JavaContextDeclarationStubs, Exception>(
|
||||
task, KotlinBundle.message("copy.text.rendering.declaration.stubs"), /* canBeCanceled = */ true, contextElement.project
|
||||
task, KotlinNJ2KBundle.message("copy.text.rendering.declaration.stubs"), /* canBeCanceled = */ true, contextElement.project
|
||||
)
|
||||
}
|
||||
|
||||
@@ -165,4 +165,4 @@ private class Renderer {
|
||||
private fun append(s: String) {
|
||||
builder.append(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle;
|
||||
import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions;
|
||||
import org.jetbrains.kotlin.nj2k.KotlinNJ2KBundle;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -23,10 +23,10 @@ public class KotlinPasteFromJavaDialog extends DialogWrapper {
|
||||
super(project, true);
|
||||
setModal(true);
|
||||
getRootPane().setDefaultButton(buttonOK);
|
||||
setTitle(KotlinBundle.message("copy.title.convert.code.from.java"));
|
||||
setTitle(KotlinNJ2KBundle.message("copy.title.convert.code.from.java"));
|
||||
if (isPlainText) {
|
||||
questionLabel.setText(
|
||||
KotlinBundle.message("copy.text.clipboard.content.seems.to.be.java.code.do.you.want.to.convert.it.to.kotlin"));
|
||||
KotlinNJ2KBundle.message("copy.text.clipboard.content.seems.to.be.java.code.do.you.want.to.convert.it.to.kotlin"));
|
||||
//TODO: should we also use different set of settings?
|
||||
}
|
||||
init();
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.j2k.copyPaste
|
||||
|
||||
import com.intellij.psi.PsiImportStatementBase
|
||||
|
||||
/**
|
||||
* This class tries to prepare the plain text Java code for J2K by adding necessary imports so that
|
||||
* such code can be properly resolved and converted.
|
||||
*
|
||||
* 1. For every Kotlin file import statement, try to convert it to a Java PSI import and add it to the Java file.
|
||||
* 2. For every unresolved short reference in the dummy Java file:
|
||||
* * Try to find a visible class, method, or field with the same short name
|
||||
* * If such a declaration is found, add an import for it (usually to both the Java and Kotlin files).
|
||||
* Note: imports for Java are added at once, but for Kotlin they are returned as a list, to be converted by J2K later.
|
||||
*/
|
||||
interface PlainTextPasteImportResolver {
|
||||
fun generateRequiredImports(): List<PsiImportStatementBase>
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
@ApiStatus.Internal
|
||||
package org.jetbrains.kotlin.j2k.copyPaste;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -27,6 +27,7 @@
|
||||
<orderEntry type="library" name="kotlinc.analysis-api" level="project" />
|
||||
<orderEntry type="library" name="kotlinc.kotlin-compiler-common" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="kotlinc.kotlin-compiler-tests" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="kotlin-test" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.java.psi" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.fir.frontend-independent" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.shared" scope="TEST" />
|
||||
@@ -36,5 +37,7 @@
|
||||
<orderEntry type="module" module-name="kotlin.base.plugin" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.base.util" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.code-insight.utils" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.idea.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.base.code-insight.minimal" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package org.jetbrains.kotlin.idea.conversion.copy
|
||||
package org.jetbrains.kotlin.j2k
|
||||
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package org.jetbrains.kotlin.idea.conversion.copy
|
||||
package org.jetbrains.kotlin.j2k
|
||||
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.ide.CopyPasteManager
|
||||
@@ -50,5 +50,7 @@
|
||||
<orderEntry type="library" scope="TEST" name="jackson" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="jackson-module-kotlin" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="okhttp" level="project" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.shared.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.j2k.shared" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -10,7 +10,7 @@ import com.intellij.testFramework.RunAll
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
|
||||
import org.jetbrains.kotlin.idea.conversion.copy.AbstractJavaToKotlinCopyPasteConversionTest
|
||||
import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinCopyPasteConversionTest
|
||||
import org.jetbrains.kotlin.j2k.copyPaste.ConvertJavaCopyPasteProcessor
|
||||
import org.jetbrains.kotlin.idea.testFramework.Stats
|
||||
import org.jetbrains.kotlin.idea.testFramework.Stats.Companion.WARM_UP
|
||||
|
||||
@@ -574,6 +574,8 @@
|
||||
<!-- Copy-paste -->
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<filePasteProvider implementation="org.jetbrains.kotlin.idea.codeInsight.copyPaste.KotlinFilePasteProvider" order="first"/>
|
||||
<copyPastePostProcessor implementation="org.jetbrains.kotlin.j2k.copyPaste.ConvertJavaCopyPasteProcessor"/>
|
||||
<copyPastePostProcessor implementation="org.jetbrains.kotlin.j2k.copyPaste.ConvertTextJavaCopyPasteProcessor"/>
|
||||
</extensions>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -275,8 +275,6 @@
|
||||
|
||||
<!-- Copy-paste -->
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<copyPastePostProcessor implementation="org.jetbrains.kotlin.j2k.copyPaste.ConvertJavaCopyPasteProcessor"/>
|
||||
<copyPastePostProcessor implementation="org.jetbrains.kotlin.j2k.copyPaste.ConvertTextJavaCopyPasteProcessor"/>
|
||||
<copyPastePostProcessor implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinCopyPasteReferenceProcessor"/>
|
||||
<copyPastePostProcessor implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsCopyPasteProcessor"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user