J2K: updated to use of Kotlin's KClass instead of Java's class in annotation declarations and usages
This commit is contained in:
@@ -102,12 +102,6 @@ public abstract class JetCodeFragment(
|
|||||||
|
|
||||||
override fun addImportsFromString(imports: String?) {
|
override fun addImportsFromString(imports: String?) {
|
||||||
if (imports == null || imports.isEmpty()) return
|
if (imports == null || imports.isEmpty()) return
|
||||||
|
|
||||||
// We should increment modification tracker after inserting import in code fragment to invalidate resolve caches.
|
|
||||||
// Without this modification references with new import won't be resolved without any modification in code fragment.
|
|
||||||
// Also shorten references won't work.
|
|
||||||
(PsiModificationTracker.SERVICE.getInstance(getProject()) as PsiModificationTrackerImpl).incOutOfCodeBlockModificationCounter()
|
|
||||||
|
|
||||||
myImports.addAll(imports.split(IMPORT_SEPARATOR))
|
myImports.addAll(imports.split(IMPORT_SEPARATOR))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,10 @@ public class JavaToKotlinAction : AnAction() {
|
|||||||
val javaFiles = selectedJavaFiles(e).toList()
|
val javaFiles = selectedJavaFiles(e).toList()
|
||||||
val project = CommonDataKeys.PROJECT.getData(e.getDataContext())!!
|
val project = CommonDataKeys.PROJECT.getData(e.getDataContext())!!
|
||||||
|
|
||||||
var converterResult: JavaToKotlinConverter.Result? = null
|
var converterResult: JavaToKotlinConverter.FilesResult? = null
|
||||||
fun convert() {
|
fun convert() {
|
||||||
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings,
|
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaReferenceSearcher, IdeaResolverForConverter)
|
||||||
IdeaReferenceSearcher, IdeaResolverForConverter, J2kPostProcessor(formatCode = true))
|
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().getProgressIndicator())
|
||||||
val inputElements = javaFiles.map { JavaToKotlinConverter.InputElement(it, it) }
|
|
||||||
converterResult = converter.elementsToKotlin(inputElements, ProgressManager.getInstance().getProgressIndicator())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val title = "Convert Java to Kotlin"
|
val title = "Convert Java to Kotlin"
|
||||||
@@ -85,7 +83,7 @@ public class JavaToKotlinAction : AnAction() {
|
|||||||
project.executeWriteCommand("Convert files from Java to Kotlin") {
|
project.executeWriteCommand("Convert files from Java to Kotlin") {
|
||||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project)
|
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project)
|
||||||
|
|
||||||
val newFiles = saveResults(javaFiles, converterResult!!.results.map { it!!.text /*conversion of a file always succeeds*/ })
|
val newFiles = saveResults(javaFiles, converterResult!!.results)
|
||||||
|
|
||||||
externalCodeUpdate?.invoke()
|
externalCodeUpdate?.invoke()
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -145,11 +145,10 @@ public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor<TextBloc
|
|||||||
project,
|
project,
|
||||||
ConverterSettings.defaultSettings,
|
ConverterSettings.defaultSettings,
|
||||||
IdeaReferenceSearcher,
|
IdeaReferenceSearcher,
|
||||||
IdeaResolverForConverter,
|
IdeaResolverForConverter
|
||||||
null
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val inputElements = elementsAndTexts.filterIsInstance<PsiElement>().map { JavaToKotlinConverter.InputElement(it, null) }
|
val inputElements = elementsAndTexts.filterIsInstance<PsiElement>()
|
||||||
val results = converter.elementsToKotlin(inputElements).results
|
val results = converter.elementsToKotlin(inputElements).results
|
||||||
|
|
||||||
var resultIndex = 0
|
var resultIndex = 0
|
||||||
@@ -163,6 +162,8 @@ public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor<TextBloc
|
|||||||
|
|
||||||
val result = results[resultIndex++]
|
val result = results[resultIndex++]
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
//TODO: insert imports
|
||||||
|
|
||||||
convertedCodeBuilder.append(result.text)
|
convertedCodeBuilder.append(result.text)
|
||||||
if (parseContext == null) { // use parse context of the first converted element as parse context for the whole text
|
if (parseContext == null) { // use parse context of the first converted element as parse context for the whole text
|
||||||
parseContext = result.parseContext
|
parseContext = result.parseContext
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.I
|
|||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention
|
||||||
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
||||||
import org.jetbrains.kotlin.idea.quickfix.RemoveRightPartOfBinaryExpressionFix
|
import org.jetbrains.kotlin.idea.quickfix.RemoveRightPartOfBinaryExpressionFix
|
||||||
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
import org.jetbrains.kotlin.j2k.PostProcessor
|
import org.jetbrains.kotlin.j2k.PostProcessor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -49,6 +51,11 @@ public class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
|
|||||||
return file.getResolutionFacade().analyzeFullyAndGetResult(elements).bindingContext
|
return file.getResolutionFacade().analyzeFullyAndGetResult(elements).bindingContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun insertImport(file: JetFile, fqName: FqName) {
|
||||||
|
val descriptors = file.getResolutionFacade().resolveImportReference(file, fqName)
|
||||||
|
descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.getProject()).importDescriptor(file, it) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun fixForProblem(problem: Diagnostic): (() -> Unit)? {
|
override fun fixForProblem(problem: Diagnostic): (() -> Unit)? {
|
||||||
val psiElement = problem.getPsiElement()
|
val psiElement = problem.getPsiElement()
|
||||||
return when (problem.getFactory()) {
|
return when (problem.getFactory()) {
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMeth
|
|||||||
val defaultValueExpr = if (getLanguage().`is`(JavaLanguage.INSTANCE) && !defaultValueText.isNullOrEmpty()) {
|
val defaultValueExpr = if (getLanguage().`is`(JavaLanguage.INSTANCE) && !defaultValueText.isNullOrEmpty()) {
|
||||||
PsiElementFactory.SERVICE.getInstance(method.getProject())
|
PsiElementFactory.SERVICE.getInstance(method.getProject())
|
||||||
.createExpressionFromText(defaultValueText!!, null)
|
.createExpressionFromText(defaultValueText!!, null)
|
||||||
.j2k(originalChangeSignatureDescriptor.baseDeclaration)
|
.j2k()
|
||||||
}
|
}
|
||||||
else null
|
else null
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -76,7 +76,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe
|
|||||||
data.getParametersToRemove().toNativeArray().toList().sortDescending().forEach { changeInfo.removeParameter(it) }
|
data.getParametersToRemove().toNativeArray().toList().sortDescending().forEach { changeInfo.removeParameter(it) }
|
||||||
|
|
||||||
// Temporarily assume that the new parameter is of Any type. Actual type is substituted during the signature update phase
|
// Temporarily assume that the new parameter is of Any type. Actual type is substituted during the signature update phase
|
||||||
val defaultValueForCall = (data.getParameterInitializer().getExpression()!! as? PsiExpression)?.let { it.j2k(it) }
|
val defaultValueForCall = (data.getParameterInitializer().getExpression()!! as? PsiExpression)?.let { it.j2k() }
|
||||||
changeInfo.addParameter(JetParameterInfo(functionDescriptor = psiMethodDescriptor,
|
changeInfo.addParameter(JetParameterInfo(functionDescriptor = psiMethodDescriptor,
|
||||||
name = data.getParameterName(),
|
name = data.getParameterName(),
|
||||||
type = KotlinBuiltIns.getInstance().getAnyType(),
|
type = KotlinBuiltIns.getInstance().getAnyType(),
|
||||||
|
|||||||
@@ -558,16 +558,14 @@ fun createJavaClass(klass: JetClass, targetClass: PsiClass): PsiMember {
|
|||||||
return javaClass
|
return javaClass
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PsiExpression.j2k(postProcessingContext: PsiElement): JetExpression? {
|
fun PsiExpression.j2k(): JetExpression? {
|
||||||
if (getLanguage() != JavaLanguage.INSTANCE) return null
|
if (getLanguage() != JavaLanguage.INSTANCE) return null
|
||||||
|
|
||||||
val project = getProject()
|
val project = getProject()
|
||||||
val j2kConverter = JavaToKotlinConverter(project,
|
val j2kConverter = JavaToKotlinConverter(project,
|
||||||
ConverterSettings.defaultSettings,
|
ConverterSettings.defaultSettings,
|
||||||
IdeaReferenceSearcher,
|
IdeaReferenceSearcher,
|
||||||
IdeaResolverForConverter,
|
IdeaResolverForConverter)
|
||||||
J2kPostProcessor(true))
|
val text = j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports
|
||||||
val inputElements = Collections.singletonList(JavaToKotlinConverter.InputElement(this, postProcessingContext))
|
|
||||||
val text = j2kConverter.elementsToKotlin(inputElements).results.singleOrNull()?.text ?: return null
|
|
||||||
return JetPsiFactory(getProject()).createExpression(text)
|
return JetPsiFactory(getProject()).createExpression(text)
|
||||||
}
|
}
|
||||||
@@ -18,41 +18,37 @@ package org.jetbrains.kotlin.util
|
|||||||
|
|
||||||
import com.intellij.codeInsight.CodeInsightSettings
|
import com.intellij.codeInsight.CodeInsightSettings
|
||||||
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
||||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.name.*
|
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
||||||
import org.jetbrains.kotlin.psi.*
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||||
import com.intellij.psi.PsiElement
|
import org.jetbrains.kotlin.idea.imports.getImportableTargets
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.idea.imports.importableFqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper.ImportDescriptorResult
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper.ImportDescriptorResult
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||||
import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import java.util.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.idea.imports.*
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.Comparator
|
||||||
|
import java.util.LinkedHashSet
|
||||||
|
|
||||||
public class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() {
|
public class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() {
|
||||||
|
|
||||||
@@ -70,6 +66,11 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addImport(file: JetFile, importPath: ImportPath): JetImportDirective {
|
private fun addImport(file: JetFile, importPath: ImportPath): JetImportDirective {
|
||||||
|
//TODO: it's a temporary hack for JetCodeFragment's and non-physical files
|
||||||
|
// We should increment modification tracker after inserting import to invalidate resolve caches.
|
||||||
|
// Without this modification references with new import won't be resolved.
|
||||||
|
(PsiModificationTracker.SERVICE.getInstance(project) as PsiModificationTrackerImpl).incOutOfCodeBlockModificationCounter()
|
||||||
|
|
||||||
val psiFactory = JetPsiFactory(project)
|
val psiFactory = JetPsiFactory(project)
|
||||||
if (file is JetCodeFragment) {
|
if (file is JetCodeFragment) {
|
||||||
val newDirective = psiFactory.createImportDirective(importPath)
|
val newDirective = psiFactory.createImportDirective(importPath)
|
||||||
|
|||||||
@@ -39,10 +39,16 @@ public class AfterConversionPass(val project: Project, val postProcessor: PostPr
|
|||||||
}
|
}
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
|
|
||||||
val document = kotlinFile.getViewProvider().getDocument()!!
|
val rangeMarker = if (range != null) {
|
||||||
val rangeMarker = if (range != null) document.createRangeMarker(range.getStartOffset(), range.getEndOffset()) else null
|
val document = kotlinFile.getViewProvider().getDocument()!!
|
||||||
rangeMarker?.setGreedyToLeft(true)
|
val marker = document.createRangeMarker(range.getStartOffset(), range.getEndOffset())
|
||||||
rangeMarker?.setGreedyToRight(true)
|
marker.setGreedyToLeft(true)
|
||||||
|
marker.setGreedyToRight(true)
|
||||||
|
marker
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
for ((psiElement, fix) in fixes) {
|
for ((psiElement, fix) in fixes) {
|
||||||
if (psiElement.isValid()) {
|
if (psiElement.isValid()) {
|
||||||
|
|||||||
@@ -121,7 +121,18 @@ class AnnotationConverter(private val converter: Converter) {
|
|||||||
|
|
||||||
private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List<(CodeConverter) -> Expression> {
|
private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List<(CodeConverter) -> Expression> {
|
||||||
when (value) {
|
when (value) {
|
||||||
is PsiExpression -> return listOf({ codeConverter -> codeConverter.convertExpression(value, expectedType).assignPrototype(value) })
|
is PsiExpression -> {
|
||||||
|
return listOf({ codeConverter ->
|
||||||
|
val expression = if (value is PsiClassObjectAccessExpression) {
|
||||||
|
val typeElement = converter.convertTypeElement(value.getOperand())
|
||||||
|
ClassLiteralExpression(typeElement.type.toNotNullType())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
codeConverter.convertExpression(value, expectedType)
|
||||||
|
}
|
||||||
|
expression.assignPrototype(value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
is PsiArrayInitializerMemberValue -> {
|
is PsiArrayInitializerMemberValue -> {
|
||||||
val componentType = (expectedType as? PsiArrayType)?.getComponentType()
|
val componentType = (expectedType as? PsiArrayType)?.getComponentType()
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.intellij.psi.*
|
|||||||
import com.intellij.psi.javadoc.PsiDocComment
|
import com.intellij.psi.javadoc.PsiDocComment
|
||||||
import org.jetbrains.kotlin.j2k.ast.CommentsAndSpacesInheritance
|
import org.jetbrains.kotlin.j2k.ast.CommentsAndSpacesInheritance
|
||||||
import org.jetbrains.kotlin.j2k.ast.Element
|
import org.jetbrains.kotlin.j2k.ast.Element
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
@@ -55,9 +56,15 @@ class CodeBuilder(private val topElement: PsiElement?) {
|
|||||||
|
|
||||||
private val commentsAndSpacesUsed = HashSet<PsiElement>()
|
private val commentsAndSpacesUsed = HashSet<PsiElement>()
|
||||||
|
|
||||||
|
private val imports = ArrayList<FqName>()
|
||||||
|
|
||||||
public fun append(text: String): CodeBuilder
|
public fun append(text: String): CodeBuilder
|
||||||
= append(text, false)
|
= append(text, false)
|
||||||
|
|
||||||
|
public fun addImport(fqName: FqName) {
|
||||||
|
imports.add(fqName)
|
||||||
|
}
|
||||||
|
|
||||||
private fun appendCommentOrWhiteSpace(element: PsiElement) {
|
private fun appendCommentOrWhiteSpace(element: PsiElement) {
|
||||||
if (element is PsiDocComment) {
|
if (element is PsiDocComment) {
|
||||||
append(DocCommentConverter.convertDocComment(element), false)
|
append(DocCommentConverter.convertDocComment(element), false)
|
||||||
@@ -83,9 +90,12 @@ class CodeBuilder(private val topElement: PsiElement?) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public val result: String
|
public val resultText: String
|
||||||
get() = builder.toString()
|
get() = builder.toString()
|
||||||
|
|
||||||
|
public val importsToAdd: Collection<FqName>
|
||||||
|
get() = imports
|
||||||
|
|
||||||
public fun append(element: Element): CodeBuilder {
|
public fun append(element: Element): CodeBuilder {
|
||||||
if (element.isEmpty) return this // do not insert comment and spaces for empty elements to avoid multiple blank lines
|
if (element.isEmpty) return this // do not insert comment and spaces for empty elements to avoid multiple blank lines
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.j2k.ast.Object
|
|||||||
import org.jetbrains.kotlin.j2k.usageProcessing.FieldToPropertyProcessing
|
import org.jetbrains.kotlin.j2k.usageProcessing.FieldToPropertyProcessing
|
||||||
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
|
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
|
||||||
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessingExpressionConverter
|
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessingExpressionConverter
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions.*
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions.*
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
@@ -77,10 +78,15 @@ class Converter private(
|
|||||||
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
|
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
|
||||||
|
|
||||||
public data class IntermediateResult(
|
public data class IntermediateResult(
|
||||||
val codeGenerator: (Map<PsiElement, Collection<UsageProcessing>>) -> String,
|
val codeGenerator: (Map<PsiElement, Collection<UsageProcessing>>) -> Result,
|
||||||
val parseContext: ParseContext
|
val parseContext: ParseContext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
public data class Result(
|
||||||
|
val text: String,
|
||||||
|
val importsToAdd: Collection<FqName>
|
||||||
|
)
|
||||||
|
|
||||||
public fun convert(): IntermediateResult? {
|
public fun convert(): IntermediateResult? {
|
||||||
val element = convertTopElement(elementToConvert) ?: return null
|
val element = convertTopElement(elementToConvert) ?: return null
|
||||||
val parseContext = when (elementToConvert) {
|
val parseContext = when (elementToConvert) {
|
||||||
@@ -93,7 +99,7 @@ class Converter private(
|
|||||||
|
|
||||||
val builder = CodeBuilder(elementToConvert)
|
val builder = CodeBuilder(elementToConvert)
|
||||||
builder.append(element)
|
builder.append(element)
|
||||||
builder.result
|
Result(builder.resultText, builder.importsToAdd)
|
||||||
},
|
},
|
||||||
parseContext)
|
parseContext)
|
||||||
}
|
}
|
||||||
@@ -253,24 +259,24 @@ class Converter private(
|
|||||||
annotationConverter.convertAnnotationMethodDefault(method)).assignPrototype(method, noBlankLinesInheritance)
|
annotationConverter.convertAnnotationMethodDefault(method)).assignPrototype(method, noBlankLinesInheritance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun convertType(psiType: PsiType?): Type {
|
||||||
|
return typeConverter.convertType(psiType, Nullability.NotNull, inAnnotationType = true)
|
||||||
|
}
|
||||||
|
|
||||||
val parameters =
|
val parameters =
|
||||||
// Argument named `value` comes first if it exists
|
// Argument named `value` comes first if it exists
|
||||||
// Convert it as vararg if it's array
|
// Convert it as vararg if it's array
|
||||||
methodsNamedValue.
|
methodsNamedValue.map { method ->
|
||||||
map { method ->
|
|
||||||
val returnType = method.getReturnType()
|
val returnType = method.getReturnType()
|
||||||
val typeConverted = if (returnType is PsiArrayType)
|
val typeConverted = if (returnType is PsiArrayType)
|
||||||
VarArgType(typeConverter.convertType(returnType.getComponentType(), Nullability.NotNull))
|
VarArgType(convertType(returnType.getComponentType()))
|
||||||
else
|
else
|
||||||
typeConverter.convertType(returnType, Nullability.NotNull)
|
convertType(returnType)
|
||||||
|
|
||||||
createParameter(typeConverted, method)
|
createParameter(typeConverted, method)
|
||||||
} +
|
} +
|
||||||
otherMethods
|
otherMethods.map { method -> createParameter(convertType(method.getReturnType()), method) }
|
||||||
.map { method ->
|
|
||||||
val typeConverted = typeConverter.convertType(method.getReturnType(), Nullability.NotNull)
|
|
||||||
createParameter(typeConverted, method)
|
|
||||||
}
|
|
||||||
val parameterList = ParameterList(parameters).assignNoPrototype()
|
val parameterList = ParameterList(parameters).assignNoPrototype()
|
||||||
val constructorSignature = if (parameterList.parameters.isNotEmpty())
|
val constructorSignature = if (parameterList.parameters.isNotEmpty())
|
||||||
PrimaryConstructorSignature(Annotations.Empty, Modifiers.Empty, parameterList).assignNoPrototype()
|
PrimaryConstructorSignature(Annotations.Empty, Modifiers.Empty, parameterList).assignNoPrototype()
|
||||||
|
|||||||
@@ -26,16 +26,14 @@ import com.intellij.openapi.progress.ProgressIndicator
|
|||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.PsiNamedElement
|
|
||||||
import com.intellij.psi.PsiReference
|
|
||||||
import com.intellij.psi.impl.source.DummyHolder
|
import com.intellij.psi.impl.source.DummyHolder
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.JetLanguage
|
import org.jetbrains.kotlin.idea.JetLanguage
|
||||||
import org.jetbrains.kotlin.j2k.ast.Element
|
import org.jetbrains.kotlin.j2k.ast.Element
|
||||||
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
|
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
@@ -45,9 +43,11 @@ import java.util.Comparator
|
|||||||
import java.util.LinkedHashMap
|
import java.util.LinkedHashMap
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
public trait PostProcessor {
|
public interface PostProcessor {
|
||||||
public fun analyzeFile(file: JetFile, range: TextRange?): BindingContext
|
public fun analyzeFile(file: JetFile, range: TextRange?): BindingContext
|
||||||
|
|
||||||
|
public fun insertImport(file: JetFile, fqName: FqName)
|
||||||
|
|
||||||
public open fun fixForProblem(problem: Diagnostic): (() -> Unit)? {
|
public open fun fixForProblem(problem: Diagnostic): (() -> Unit)? {
|
||||||
val psiElement = problem.getPsiElement()
|
val psiElement = problem.getPsiElement()
|
||||||
return when (problem.getFactory()) {
|
return when (problem.getFactory()) {
|
||||||
@@ -77,30 +77,57 @@ public enum class ParseContext {
|
|||||||
CODE_BLOCK
|
CODE_BLOCK
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JavaToKotlinConverter(private val project: Project,
|
public class JavaToKotlinConverter(
|
||||||
private val settings: ConverterSettings,
|
private val project: Project,
|
||||||
private val referenceSearcher: ReferenceSearcher,
|
private val settings: ConverterSettings,
|
||||||
private val resolverForConverter: ResolverForConverter,
|
private val referenceSearcher: ReferenceSearcher,
|
||||||
private val postProcessor: PostProcessor?) {
|
private val resolverForConverter: ResolverForConverter
|
||||||
|
) {
|
||||||
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter")
|
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.j2k.JavaToKotlinConverter")
|
||||||
|
|
||||||
public data class InputElement(
|
public interface ExternalCodeProcessing {
|
||||||
val element: PsiElement,
|
|
||||||
val postProcessingContext: PsiElement?
|
|
||||||
)
|
|
||||||
|
|
||||||
public data class ElementResult(val text: String, val parseContext: ParseContext)
|
|
||||||
|
|
||||||
public trait ExternalCodeProcessing {
|
|
||||||
public fun prepareWriteOperation(progress: ProgressIndicator): () -> Unit
|
public fun prepareWriteOperation(progress: ProgressIndicator): () -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public data class ElementResult(val text: String, val importsToAdd: Collection<FqName>, val parseContext: ParseContext)
|
||||||
|
|
||||||
public data class Result(val results: List<ElementResult?>, val externalCodeProcessing: ExternalCodeProcessing?)
|
public data class Result(val results: List<ElementResult?>, val externalCodeProcessing: ExternalCodeProcessing?)
|
||||||
|
|
||||||
public fun elementsToKotlin(
|
public data class FilesResult(val results: List<String>, val externalCodeProcessing: ExternalCodeProcessing?)
|
||||||
inputElements: List<InputElement>,
|
|
||||||
progress: ProgressIndicator = EmptyProgressIndicator()
|
public fun filesToKotlin(files: List<PsiJavaFile>, postProcessor: PostProcessor, progress: ProgressIndicator = EmptyProgressIndicator()): FilesResult {
|
||||||
): Result {
|
val withProgressProcessor = WithProgressProcessor(progress, files)
|
||||||
|
|
||||||
|
val (results, externalCodeProcessing) = elementsToKotlin(files, withProgressProcessor)
|
||||||
|
|
||||||
|
val texts = withProgressProcessor.processItems(0.5, results.withIndex()) { pair ->
|
||||||
|
val (i, result) = pair
|
||||||
|
try {
|
||||||
|
val kotlinFile = JetPsiFactory(project).createAnalyzableFile("dummy.kt", result!!.text, files[i])
|
||||||
|
|
||||||
|
result.importsToAdd.forEach { postProcessor.insertImport(kotlinFile, it) }
|
||||||
|
|
||||||
|
AfterConversionPass(project, postProcessor).run(kotlinFile, range = null)
|
||||||
|
|
||||||
|
kotlinFile.getText()
|
||||||
|
}
|
||||||
|
catch(e: ProcessCanceledException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch(t: Throwable) {
|
||||||
|
LOG.error(t)
|
||||||
|
result!!.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilesResult(texts, externalCodeProcessing)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun elementsToKotlin(inputElements: List<PsiElement>): Result {
|
||||||
|
return elementsToKotlin(inputElements, WithProgressProcessor.DEFAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun elementsToKotlin(inputElements: List<PsiElement>, processor: WithProgressProcessor): Result {
|
||||||
try {
|
try {
|
||||||
val usageProcessings = LinkedHashMap<PsiElement, MutableCollection<UsageProcessing>>()
|
val usageProcessings = LinkedHashMap<PsiElement, MutableCollection<UsageProcessing>>()
|
||||||
val usageProcessingCollector: (UsageProcessing) -> Unit = {
|
val usageProcessingCollector: (UsageProcessing) -> Unit = {
|
||||||
@@ -108,87 +135,25 @@ public class JavaToKotlinConverter(private val project: Project,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun inConversionScope(element: PsiElement)
|
fun inConversionScope(element: PsiElement)
|
||||||
= inputElements.any { it.element.isAncestor(element, strict = false) }
|
= inputElements.any { it.isAncestor(element, strict = false) }
|
||||||
|
|
||||||
val progressText = "Converting Java to Kotlin"
|
|
||||||
val elementCount = inputElements.size()
|
|
||||||
val fileCountText = elementCount.toString() + " " + if (elementCount > 1) "files" else "file"
|
|
||||||
var fraction = 0.0
|
|
||||||
var pass = 1
|
|
||||||
|
|
||||||
fun processFilesWithProgress<TInputItem, TOutputItem>(
|
val intermediateResults = processor.processItems(0.25, inputElements) { inputElement ->
|
||||||
fractionPortion: Double,
|
Converter.create(inputElement, settings, ::inConversionScope, referenceSearcher, resolverForConverter, usageProcessingCollector).convert()
|
||||||
inputItems: Iterable<TInputItem>,
|
|
||||||
processItem: (TInputItem) -> TOutputItem
|
|
||||||
): List<TOutputItem> {
|
|
||||||
val outputItems = ArrayList<TOutputItem>(elementCount)
|
|
||||||
// we use special process with EmptyProgressIndicator to avoid changing text in our progress by inheritors search inside etc
|
|
||||||
ProgressManager.getInstance().runProcess(
|
|
||||||
{
|
|
||||||
progress.setText("$progressText ($fileCountText) - pass $pass of 3")
|
|
||||||
|
|
||||||
for ((i, item) in inputItems.withIndex()) {
|
|
||||||
progress.checkCanceled()
|
|
||||||
progress.setFraction(fraction + fractionPortion * i / elementCount)
|
|
||||||
|
|
||||||
val psiFile = inputElements[i].element as? PsiFile
|
|
||||||
if (psiFile != null) {
|
|
||||||
progress.setText2(psiFile.getVirtualFile().getPresentableUrl())
|
|
||||||
}
|
|
||||||
|
|
||||||
outputItems.add(processItem(item))
|
|
||||||
}
|
|
||||||
|
|
||||||
pass++
|
|
||||||
fraction += fractionPortion
|
|
||||||
},
|
|
||||||
EmptyProgressIndicator())
|
|
||||||
return outputItems
|
|
||||||
}
|
|
||||||
|
|
||||||
val intermediateResults = processFilesWithProgress(0.25, inputElements) { inputElement ->
|
|
||||||
Converter.create(inputElement.element, settings, ::inConversionScope, referenceSearcher, resolverForConverter, usageProcessingCollector).convert()
|
|
||||||
}.toArrayList()
|
}.toArrayList()
|
||||||
|
|
||||||
val results = processFilesWithProgress(0.25, intermediateResults.withIndex()) { pair ->
|
val results = processor.processItems(0.25, intermediateResults.withIndex()) { pair ->
|
||||||
val (i, result) = pair
|
val (i, result) = pair
|
||||||
intermediateResults[i] = null // to not hold unused objects in the heap
|
intermediateResults[i] = null // to not hold unused objects in the heap
|
||||||
if (result != null)
|
result?.let {
|
||||||
ElementResult(result.codeGenerator(usageProcessings), result.parseContext)
|
val (text, importsToAdd) = it.codeGenerator(usageProcessings)
|
||||||
else
|
ElementResult(text, importsToAdd, it.parseContext)
|
||||||
null
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val externalCodeProcessing = buildExternalCodeProcessing(usageProcessings, ::inConversionScope)
|
val externalCodeProcessing = buildExternalCodeProcessing(usageProcessings, ::inConversionScope)
|
||||||
|
|
||||||
if (postProcessor == null) {
|
return Result(results, externalCodeProcessing)
|
||||||
assert(progress is EmptyProgressIndicator, "Progress indicator not supported for postProcessor == null")
|
|
||||||
return Result(results, externalCodeProcessing)
|
|
||||||
}
|
|
||||||
|
|
||||||
val finalResults = processFilesWithProgress(0.5, results.withIndex()) { pair ->
|
|
||||||
val (i, result) = pair
|
|
||||||
if (result != null) {
|
|
||||||
try {
|
|
||||||
//TODO: post processing does not work correctly for ParseContext different from TOP_LEVEL
|
|
||||||
val kotlinFile = JetPsiFactory(project).createAnalyzableFile("dummy.kt", result.text, inputElements[i].postProcessingContext!!)
|
|
||||||
AfterConversionPass(project, postProcessor).run(kotlinFile, range = null)
|
|
||||||
ElementResult(kotlinFile.getText(), result.parseContext)
|
|
||||||
}
|
|
||||||
catch(e: ProcessCanceledException) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
catch(t: Throwable) {
|
|
||||||
LOG.error(t)
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result(finalResults, 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
|
// if we got this exception then we need to turn element creation stack traces on to get better diagnostic
|
||||||
@@ -202,7 +167,7 @@ public class JavaToKotlinConverter(private val project: Project,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ReferenceInfo(
|
private data class ReferenceInfo(
|
||||||
val reference: PsiReference,
|
val reference: PsiReference,
|
||||||
val target: PsiElement,
|
val target: PsiElement,
|
||||||
val file: PsiFile,
|
val file: PsiFile,
|
||||||
@@ -295,6 +260,45 @@ public class JavaToKotlinConverter(private val project: Project,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class WithProgressProcessor(private val progress: ProgressIndicator?, private val files: List<PsiJavaFile>?) {
|
||||||
|
public 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 processItems<TInputItem, TOutputItem>(
|
||||||
|
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?.setText("$progressText ($fileCountText) - pass $pass of 3")
|
||||||
|
|
||||||
|
for ((i, item) in inputItems.withIndex()) {
|
||||||
|
progress?.checkCanceled()
|
||||||
|
progress?.setFraction(fraction + fractionPortion * i / fileCount)
|
||||||
|
|
||||||
|
progress?.setText2(files!![i].getVirtualFile().getPresentableUrl())
|
||||||
|
|
||||||
|
outputItems.add(processItem(item))
|
||||||
|
}
|
||||||
|
|
||||||
|
pass++
|
||||||
|
fraction += fractionPortion
|
||||||
|
},
|
||||||
|
EmptyProgressIndicator())
|
||||||
|
return outputItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ProgressPortionReporter(
|
private class ProgressPortionReporter(
|
||||||
indicator: ProgressIndicator,
|
indicator: ProgressIndicator,
|
||||||
private val start: Double,
|
private val start: Double,
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ public object JavaToKotlinTranslator {
|
|||||||
public fun generateKotlinCode(javaCode: String, project: Project): String {
|
public fun generateKotlinCode(javaCode: String, project: Project): String {
|
||||||
val file = createFile(javaCode, project)
|
val file = createFile(javaCode, project)
|
||||||
if (file is PsiJavaFile) {
|
if (file is PsiJavaFile) {
|
||||||
val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, EmptyReferenceSearcher, EmptyResolverForConverter, null)
|
val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, EmptyReferenceSearcher, EmptyResolverForConverter)
|
||||||
return prettify(converter.elementsToKotlin(listOf(JavaToKotlinConverter.InputElement(file, null))).results.single()!!.text)
|
return prettify(converter.elementsToKotlin(listOf(file)).results.single()!!.text) //TODO: imports
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,15 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
|
||||||
class TypeConverter(val converter: Converter) {
|
class TypeConverter(val converter: Converter) {
|
||||||
public fun convertType(type: PsiType?, nullability: Nullability = Nullability.Default, mutability: Mutability = Mutability.Default): Type {
|
public fun convertType(
|
||||||
|
type: PsiType?,
|
||||||
|
nullability: Nullability = Nullability.Default,
|
||||||
|
mutability: Mutability = Mutability.Default,
|
||||||
|
inAnnotationType: Boolean = false
|
||||||
|
): Type {
|
||||||
if (type == null) return ErrorType().assignNoPrototype()
|
if (type == null) return ErrorType().assignNoPrototype()
|
||||||
|
|
||||||
val result = type.accept<Type>(TypeVisitor(converter, type, mutability))!!.assignNoPrototype()
|
val result = type.accept<Type>(TypeVisitor(converter, type, mutability, inAnnotationType))!!.assignNoPrototype()
|
||||||
return when (nullability) {
|
return when (nullability) {
|
||||||
Nullability.NotNull -> result.toNotNullType()
|
Nullability.NotNull -> result.toNotNullType()
|
||||||
Nullability.Nullable -> result.toNullableType()
|
Nullability.Nullable -> result.toNullableType()
|
||||||
|
|||||||
@@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.j2k
|
package org.jetbrains.kotlin.j2k
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.source.PsiClassReferenceType
|
import com.intellij.psi.impl.source.PsiClassReferenceType
|
||||||
import org.jetbrains.kotlin.j2k.ast.*
|
import org.jetbrains.kotlin.j2k.ast.*
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||||
|
|
||||||
private val PRIMITIVE_TYPES_NAMES = JvmPrimitiveType.values().map { it.getName() }
|
private val PRIMITIVE_TYPES_NAMES = JvmPrimitiveType.values().map { it.getName() }
|
||||||
@@ -27,7 +28,8 @@ private val PRIMITIVE_TYPES_NAMES = JvmPrimitiveType.values().map { it.getName()
|
|||||||
class TypeVisitor(
|
class TypeVisitor(
|
||||||
private val converter: Converter,
|
private val converter: Converter,
|
||||||
private val topLevelType: PsiType,
|
private val topLevelType: PsiType,
|
||||||
private val topLevelTypeMutability: Mutability
|
private val topLevelTypeMutability: Mutability,
|
||||||
|
private val inAnnotationType: Boolean
|
||||||
) : PsiTypeVisitor<Type>() {
|
) : PsiTypeVisitor<Type>() {
|
||||||
|
|
||||||
private val typeConverter: TypeConverter = converter.typeConverter
|
private val typeConverter: TypeConverter = converter.typeConverter
|
||||||
@@ -49,7 +51,7 @@ class TypeVisitor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitArrayType(arrayType: PsiArrayType): Type {
|
override fun visitArrayType(arrayType: PsiArrayType): Type {
|
||||||
return ArrayType(typeConverter.convertType(arrayType.getComponentType()), Nullability.Default, converter.settings)
|
return ArrayType(typeConverter.convertType(arrayType.getComponentType(), inAnnotationType = inAnnotationType), Nullability.Default, converter.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClassType(classType: PsiClassType): Type {
|
override fun visitClassType(classType: PsiClassType): Type {
|
||||||
@@ -69,6 +71,12 @@ class TypeVisitor(
|
|||||||
if (kotlinClassName != null) {
|
if (kotlinClassName != null) {
|
||||||
return ReferenceElement(Identifier(getShortName(kotlinClassName)).assignNoPrototype(), typeArgs).assignNoPrototype()
|
return ReferenceElement(Identifier(getShortName(kotlinClassName)).assignNoPrototype(), typeArgs).assignNoPrototype()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inAnnotationType && javaClassName == "java.lang.Class") {
|
||||||
|
val fqName = FqName("kotlin.reflect.KClass")
|
||||||
|
val identifier = Identifier(fqName.shortName().getIdentifier(), imports = listOf(fqName)).assignNoPrototype()
|
||||||
|
return ReferenceElement(identifier, typeArgs).assignNoPrototype()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classType is PsiClassReferenceType) {
|
if (classType is PsiClassReferenceType) {
|
||||||
@@ -78,8 +86,7 @@ class TypeVisitor(
|
|||||||
return ReferenceElement(Identifier(classType.getClassName() ?: "").assignNoPrototype(), typeArgs).assignNoPrototype()
|
return ReferenceElement(Identifier(classType.getClassName() ?: "").assignNoPrototype(), typeArgs).assignNoPrototype()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPackageName(className: String): String = className.substring(0, className.lastIndexOf('.'))
|
private fun getShortName(className: String): String = className.substringAfterLast('.', className)
|
||||||
private fun getShortName(className: String): String = className.substring(className.lastIndexOf('.') + 1)
|
|
||||||
|
|
||||||
private fun convertTypeArgs(classType: PsiClassType): List<Type> {
|
private fun convertTypeArgs(classType: PsiClassType): List<Type> {
|
||||||
if (classType.getParameterCount() == 0) {
|
if (classType.getParameterCount() == 0) {
|
||||||
@@ -112,7 +119,7 @@ class TypeVisitor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitEllipsisType(ellipsisType: PsiEllipsisType): Type {
|
override fun visitEllipsisType(ellipsisType: PsiEllipsisType): Type {
|
||||||
return VarArgType(typeConverter.convertType(ellipsisType.getComponentType()))
|
return VarArgType(typeConverter.convertType(ellipsisType.getComponentType(), inAnnotationType = inAnnotationType))
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ data class CommentsAndSpacesInheritance(val blankLinesBefore: Boolean = true,
|
|||||||
fun Element.canonicalCode(): String {
|
fun Element.canonicalCode(): String {
|
||||||
val builder = CodeBuilder(null)
|
val builder = CodeBuilder(null)
|
||||||
builder.append(this)
|
builder.append(this)
|
||||||
return builder.result
|
return builder.resultText
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Element {
|
abstract class Element {
|
||||||
|
|||||||
@@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.j2k.ast
|
package org.jetbrains.kotlin.j2k.ast
|
||||||
|
|
||||||
import org.jetbrains.kotlin.j2k.CodeBuilder
|
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner
|
import com.intellij.psi.PsiNameIdentifierOwner
|
||||||
|
import org.jetbrains.kotlin.j2k.CodeBuilder
|
||||||
import org.jetbrains.kotlin.lexer.JetKeywordToken
|
import org.jetbrains.kotlin.lexer.JetKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier {
|
fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier {
|
||||||
val name = getName()
|
val name = getName()
|
||||||
@@ -29,7 +30,8 @@ fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier {
|
|||||||
class Identifier(
|
class Identifier(
|
||||||
val name: String,
|
val name: String,
|
||||||
override val isNullable: Boolean = true,
|
override val isNullable: Boolean = true,
|
||||||
private val quotingNeeded: Boolean = true
|
private val quotingNeeded: Boolean = true,
|
||||||
|
private val imports: Collection<FqName> = emptyList()
|
||||||
) : Expression() {
|
) : Expression() {
|
||||||
|
|
||||||
override val isEmpty: Boolean
|
override val isEmpty: Boolean
|
||||||
@@ -45,6 +47,8 @@ class Identifier(
|
|||||||
|
|
||||||
override fun generateCode(builder: CodeBuilder) {
|
override fun generateCode(builder: CodeBuilder) {
|
||||||
builder.append(toKotlin())
|
builder.append(toKotlin())
|
||||||
|
|
||||||
|
imports.forEach { builder.addImport(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun quote(str: String): String = "`" + str + "`"
|
private fun quote(str: String): String = "`" + str + "`"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ Anon3(e = E.A, stringArray = array(), value = *array("a", "b"))
|
|||||||
Anon4("x", "y")
|
Anon4("x", "y")
|
||||||
Anon5(1)
|
Anon5(1)
|
||||||
Anon6("x", "y")
|
Anon6("x", "y")
|
||||||
Anon7(javaClass<String>(), javaClass<StringBuilder>())
|
Anon7(String::class, StringBuilder::class)
|
||||||
Anon8(classes = array(javaClass<String>(), javaClass<StringBuilder>()))
|
Anon8(classes = array(String::class, StringBuilder::class))
|
||||||
class C {
|
class C {
|
||||||
Anon5(1) deprecated("") private val field1 = 0
|
Anon5(1) deprecated("") private val field1 = 0
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@interface Ann {
|
||||||
|
Class<?> value();
|
||||||
|
Class<?> other();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ann(other = String.class, value = Object.class)
|
||||||
|
class C {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
annotation class Ann(public val value: KClass<*>, public val other: KClass<*>)
|
||||||
|
|
||||||
|
Ann(other = String::class, value = Any::class)
|
||||||
|
class C
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
@interface Ann {
|
||||||
|
Class<?>[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ann({String.class, Object.class})
|
||||||
|
class C {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ann({})
|
||||||
|
class D {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
annotation class Ann(public vararg val value: KClass<*>)
|
||||||
|
|
||||||
|
Ann(String::class, Any::class)
|
||||||
|
class C
|
||||||
|
|
||||||
|
Ann
|
||||||
|
class D
|
||||||
@@ -54,10 +54,8 @@ public abstract class AbstractJavaToKotlinConverterMultiFileTest : AbstractJavaT
|
|||||||
assert(psiFile is PsiJavaFile || psiFile is JetFile)
|
assert(psiFile is PsiJavaFile || psiFile is JetFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings,
|
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaReferenceSearcher, IdeaResolverForConverter)
|
||||||
IdeaReferenceSearcher, IdeaResolverForConverter, J2kPostProcessor(formatCode = true))
|
val (results, externalCodeProcessor) = converter.filesToKotlin(psiFilesToConvert, J2kPostProcessor(formatCode = true))
|
||||||
val inputElements = psiFilesToConvert.map { JavaToKotlinConverter.InputElement(it, it) }
|
|
||||||
val (results, externalCodeProcessor) = converter.elementsToKotlin(inputElements)
|
|
||||||
|
|
||||||
val process = externalCodeProcessor?.prepareWriteOperation(EmptyProgressIndicator())
|
val process = externalCodeProcessor?.prepareWriteOperation(EmptyProgressIndicator())
|
||||||
project.executeWriteCommand("") { process?.invoke() }
|
project.executeWriteCommand("") { process?.invoke() }
|
||||||
@@ -67,7 +65,7 @@ public abstract class AbstractJavaToKotlinConverterMultiFileTest : AbstractJavaT
|
|||||||
val resultFiles = ArrayList<JetFile>()
|
val resultFiles = ArrayList<JetFile>()
|
||||||
for ((i, javaFile) in psiFilesToConvert.withIndex()) {
|
for ((i, javaFile) in psiFilesToConvert.withIndex()) {
|
||||||
deleteFile(javaFile.getVirtualFile())
|
deleteFile(javaFile.getVirtualFile())
|
||||||
val virtualFile = addFile(results.map { it!!.text }[i], expectedResultFile(i).getName(), "test")
|
val virtualFile = addFile(results[i], expectedResultFile(i).getName(), "test")
|
||||||
resultFiles.add(psiManager.findFile(virtualFile) as JetFile)
|
resultFiles.add(psiManager.findFile(virtualFile) as JetFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,9 +108,8 @@ public abstract class AbstractJavaToKotlinConverterSingleFileTest : AbstractJava
|
|||||||
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
||||||
val file = createJavaFile(text)
|
val file = createJavaFile(text)
|
||||||
val converter = JavaToKotlinConverter(project, settings,
|
val converter = JavaToKotlinConverter(project, settings,
|
||||||
IdeaReferenceSearcher, IdeaResolverForConverter, J2kPostProcessor(formatCode = false))
|
IdeaReferenceSearcher, IdeaResolverForConverter)
|
||||||
val inputElements = listOf(JavaToKotlinConverter.InputElement(file, file))
|
return converter.filesToKotlin(listOf(file), J2kPostProcessor(formatCode = true)).results.single()
|
||||||
return converter.elementsToKotlin(inputElements).results.single()!!.text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun methodToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
private fun methodToKotlin(text: String, settings: ConverterSettings, project: Project): String {
|
||||||
|
|||||||
@@ -73,6 +73,18 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaClassArgument.java")
|
||||||
|
public void testJavaClassArgument() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/javaClassArgument.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaClassArrayArgument.java")
|
||||||
|
public void testJavaClassArrayArgument() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/javaClassArrayArgument.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("jetbrainsNotNull.java")
|
@TestMetadata("jetbrainsNotNull.java")
|
||||||
public void testJetbrainsNotNull() throws Exception {
|
public void testJetbrainsNotNull() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/jetbrainsNotNull.java");
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/jetbrainsNotNull.java");
|
||||||
|
|||||||
@@ -73,6 +73,18 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaClassArgument.java")
|
||||||
|
public void testJavaClassArgument() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/javaClassArgument.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaClassArrayArgument.java")
|
||||||
|
public void testJavaClassArrayArgument() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/javaClassArrayArgument.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("jetbrainsNotNull.java")
|
@TestMetadata("jetbrainsNotNull.java")
|
||||||
public void testJetbrainsNotNull() throws Exception {
|
public void testJetbrainsNotNull() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/jetbrainsNotNull.java");
|
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/jetbrainsNotNull.java");
|
||||||
|
|||||||
Reference in New Issue
Block a user