KT-7135 Java to Kotlin converter should update usages in Java and Koltin code in the rest of the project

#KT-7135 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-04-07 13:06:31 +03:00
parent b810ebbb0e
commit 1afbb961ee
50 changed files with 962 additions and 156 deletions
@@ -21,6 +21,10 @@ import com.intellij.psi.*
import org.jetbrains.kotlin.j2k.ast.*
import org.jetbrains.kotlin.j2k.ast.Class
import org.jetbrains.kotlin.j2k.usageProcessing.AccessorToPropertyProcessing
import org.jetbrains.kotlin.j2k.usageProcessing.MethodIntoObjectProcessing
import org.jetbrains.kotlin.j2k.usageProcessing.ToObjectWithOnlyMethodsProcessing
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.SpecialNames
import java.util.ArrayList
import java.util.HashMap
import java.util.HashSet
@@ -71,6 +75,19 @@ class ClassBodyConverter(private val psiClass: PsiClass,
val rBrace = RBrace().assignPrototype(psiClass.getRBrace())
if (isObject) {
val psiMembers = convertedMembers.keySet()
if (psiMembers.all { it is PsiMethod }) { // for object with no fields we can use faster external usage processing
converter.addUsageProcessing(ToObjectWithOnlyMethodsProcessing(psiClass))
}
else {
for (psiMember in psiMembers) {
if (psiMember is PsiMethod /* fields in object can be accessed as fields from java */
&& !psiMember.hasModifierProperty(PsiModifier.PRIVATE)) {
converter.addUsageProcessing(MethodIntoObjectProcessing(psiMember, JvmAbi.INSTANCE_FIELD))
}
}
}
return ClassBody(null, null, convertedMembers.values().toList(), emptyList(), lBrace, rBrace)
}
@@ -87,6 +104,10 @@ class ClassBodyConverter(private val psiClass: PsiClass,
}
else if (useCompanionObject && member !is Class && psiMember !is PsiEnumConstant && psiMember.hasModifierProperty(PsiModifier.STATIC)) {
companionObjectMembers.add(member)
if (psiMember is PsiMethod /* fields in companion object can be accessed as fields from java */
&& !psiMember.hasModifierProperty(PsiModifier.PRIVATE)) {
converter.addUsageProcessing(MethodIntoObjectProcessing(psiMember, SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.getIdentifier()))
}
}
else {
members.add(member)
@@ -179,10 +200,11 @@ class ClassBodyConverter(private val psiClass: PsiClass,
private fun getAccessorInfo(method: PsiMethod): AccessorInfo? {
val name = method.getName()
val static = method.hasModifierProperty(PsiModifier.STATIC)
if (name.startsWith("get") && method.getParameterList().getParametersCount() == 0) {
val body = method.getBody() ?: return null
val returnStatement = (body.getStatements().singleOrNull() as? PsiReturnStatement) ?: return null
val field = fieldByExpression(returnStatement.getReturnValue()) ?: return null
val field = fieldByExpression(returnStatement.getReturnValue(), static) ?: return null
if (field.getType() != method.getReturnType()) return null
if (converter.typeConverter.variableMutability(field) != converter.typeConverter.methodMutability(method)) return null
val propertyName = StringUtil.decapitalize(name.substring("get".length()))
@@ -193,7 +215,7 @@ class ClassBodyConverter(private val psiClass: PsiClass,
val statement = (body.getStatements().singleOrNull() as? PsiExpressionStatement) ?: return null
val assignment = statement.getExpression() as? PsiAssignmentExpression ?: return null
if (assignment.getOperationTokenType() != JavaTokenType.EQ) return null
val field = fieldByExpression(assignment.getLExpression()) ?: return null
val field = fieldByExpression(assignment.getLExpression(), static) ?: return null
val parameter = method.getParameterList().getParameters().single()
if ((assignment.getRExpression() as? PsiReferenceExpression)?.resolve() != parameter) return null
if (field.getType() != parameter.getType()) return null
@@ -205,11 +227,16 @@ class ClassBodyConverter(private val psiClass: PsiClass,
}
}
private fun fieldByExpression(expression: PsiExpression?): PsiField? {
private fun fieldByExpression(expression: PsiExpression?, static: Boolean): PsiField? {
val refExpr = expression as? PsiReferenceExpression ?: return null
if (!refExpr.isQualifierEmptyOrThis()) return null
if (static) {
if (!refExpr.isQualifierEmptyOrClass(psiClass)) return null
}
else {
if (!refExpr.isQualifierEmptyOrThis()) return null
}
val field = refExpr.resolve() as? PsiField ?: return null
if (field.getContainingClass() != psiClass || field.hasModifierProperty(PsiModifier.STATIC)) return null
if (field.getContainingClass() != psiClass || field.hasModifierProperty(PsiModifier.STATIC) != static) return null
return field
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.j2k
import com.google.common.collect.Multimap
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.CommonClassNames.*
@@ -73,7 +74,7 @@ class Converter private(
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
public data class IntermediateResult(
val codeGenerator: (Map<PsiElement, UsageProcessing>) -> String,
val codeGenerator: (Map<PsiElement, Collection<UsageProcessing>>) -> String,
val parseContext: ParseContext
)
@@ -108,7 +109,7 @@ class Converter private(
else -> null
}
private fun unfoldDeferredElements(usageProcessings: Map<PsiElement, UsageProcessing>) {
private fun unfoldDeferredElements(usageProcessings: Map<PsiElement, Collection<UsageProcessing>>) {
val codeConverter = createDefaultCodeConverter().withSpecialExpressionConverter(UsageProcessingExpressionConverter(usageProcessings))
// we use loop with index because new deferred elements can be added during unfolding
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.j2k
import com.intellij.ide.util.DelegatingProgressIndicator
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.progress.EmptyProgressIndicator
@@ -26,15 +28,19 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.DummyHolder
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.JetLanguage
import org.jetbrains.kotlin.j2k.ast.Element
import org.jetbrains.kotlin.j2k.usageProcessing.UsageProcessing
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.BindingContext
import java.util.ArrayList
import java.util.HashMap
import java.util.*
public trait PostProcessor {
public fun analyzeFile(file: JetFile, range: TextRange?): BindingContext
@@ -80,22 +86,26 @@ public class JavaToKotlinConverter(private val project: Project,
val postProcessingContext: PsiElement?
)
public data class Result(val text: String, val parseContext: ParseContext)
public data class ElementResult(val text: String, val parseContext: ParseContext)
public data class Result(val results: List<ElementResult?>, val externalCodeProcessing: ((ProgressIndicator) -> (() -> Unit)?)?) //TODO: change interface to not perform write-actions under progress
public fun elementsToKotlin(
inputElements: List<InputElement>,
progress: ProgressIndicator = EmptyProgressIndicator()
): List<Result?> {
): Result {
try {
val elementCount = inputElements.size()
val intermediateResults = ArrayList<(Converter.IntermediateResult)?>(elementCount)
val usageProcessings = HashMap<PsiElement, UsageProcessing>()
val usageProcessingCollector: (UsageProcessing) -> Unit = { usageProcessing ->
assert(!usageProcessings.containsKey(usageProcessing.targetElement))
{ "Duplicated UsageProcessing for target element ${usageProcessing.targetElement}" }
usageProcessings.put(usageProcessing.targetElement, usageProcessing)
val usageProcessings = LinkedHashMap<PsiElement, MutableCollection<UsageProcessing>>()
val usageProcessingCollector: (UsageProcessing) -> Unit = {
usageProcessings.getOrPut(it.targetElement, { ArrayList() }).add(it)
}
fun inConversionScope(element: PsiElement)
= inputElements.any { it.element.isAncestor(element, strict = false) }
val progressText = "Converting Java to Kotlin"
val fileCountText = elementCount.toString() + " " + if (elementCount > 1) "files" else "file"
var fraction = 0.0
@@ -128,31 +138,29 @@ public class JavaToKotlinConverter(private val project: Project,
processFilesWithProgress(0.25) { i ->
val psiElement = inputElements[i].element
fun inConversionScope(element: PsiElement)
= inputElements.any { it.element.isAncestor(element, strict = false) }
val converter = Converter.create(psiElement, settings, ::inConversionScope, referenceSearcher, resolverForConverter, usageProcessingCollector)
val result = converter.convert()
intermediateResults.add(result)
}
val results = ArrayList<Result?>(elementCount)
val results = ArrayList<ElementResult?>(elementCount)
processFilesWithProgress(0.25) { i ->
val result = intermediateResults[i]
results.add(if (result != null)
Result(result.codeGenerator(usageProcessings), result.parseContext)
ElementResult(result.codeGenerator(usageProcessings), result.parseContext)
else
null)
intermediateResults[i] = null // to not hold unused objects in the heap
}
val externalCodeProcessing = buildExternalCodeProcessing(usageProcessings, ::inConversionScope)
if (postProcessor == null) {
assert(progress is EmptyProgressIndicator, "Progress indicator not supported for postProcessor == null")
return results
return Result(results, externalCodeProcessing)
}
val finalResults = ArrayList<Result?>(elementCount)
val finalResults = ArrayList<ElementResult?>(elementCount)
processFilesWithProgress(0.5) { i ->
val result = results[i]
if (result != null) {
@@ -160,7 +168,7 @@ public class JavaToKotlinConverter(private val project: Project,
//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)
finalResults.add(Result(kotlinFile.getText(), result.parseContext))
finalResults.add(ElementResult(kotlinFile.getText(), result.parseContext))
}
catch(e: ProcessCanceledException) {
throw e
@@ -175,7 +183,7 @@ public class JavaToKotlinConverter(private val project: Project,
}
}
return finalResults
return Result(finalResults, externalCodeProcessing)
}
catch(e: ElementCreationStackTraceRequiredException) {
// if we got this exception then we need to turn element creation stack traces on to get better diagnostic
@@ -188,4 +196,130 @@ public class JavaToKotlinConverter(private val project: Project,
}
}
}
data class ReferenceInfo(
val reference: PsiReference,
val target: PsiElement,
val file: PsiFile,
val processings: Collection<UsageProcessing>
)
private fun buildExternalCodeProcessing(
usageProcessings: Map<PsiElement, Collection<UsageProcessing>>,
inConversionScope: (PsiElement) -> Boolean
): ((ProgressIndicator) -> (() -> Unit)?)? {
if (usageProcessings.isEmpty()) return null
val map: Map<PsiElement, Collection<UsageProcessing>> = usageProcessings.values()
.flatMap { it }
.filter { it.javaCodeProcessor != null || it.kotlinCodeProcessor != null }
.groupBy { it.targetElement }
if (map.isEmpty()) return null
return fun(progress: ProgressIndicator): (() -> Unit)? {
val refs = ArrayList<ReferenceInfo>()
progress.setText("Searching usages to update...")
for ((i, entry) in map.entrySet().withIndex()) {
val psiElement = entry.key
val processings = entry.value
progress.setText2((psiElement as? PsiNamedElement)?.getName() ?: "")
progress.checkCanceled()
ProgressManager.getInstance().runProcess(
{
val searchJava = processings.any { it.javaCodeProcessor != null }
val searchKotlin = processings.any { it.kotlinCodeProcessor != null }
referenceSearcher.findExternalCodeProcessingUsages(psiElement, searchJava, searchKotlin)
.filterNot { inConversionScope(it.getElement()) }
.mapTo(refs) { ReferenceInfo(it, psiElement, it.getElement().getContainingFile(), processings) }
},
ProgressPortionReporter(progress, i / map.size().toDouble(), 1.0 / map.size()))
}
if (refs.isEmpty()) return null
return { processUsages(refs) }
}
}
private fun processUsages(refs: Collection<ReferenceInfo>) {
@ReferenceLoop
for ((reference, target, file, processings) in refs.sortBy(ReferenceComparator)) {
val processors = when (reference.getElement().getLanguage()) {
JavaLanguage.INSTANCE -> processings.map { it.javaCodeProcessor }.filterNotNull()
JetLanguage.INSTANCE -> processings.map { it.kotlinCodeProcessor }.filterNotNull()
else -> continue@ReferenceLoop
}
checkReferenceValid(reference)
var references = listOf(reference)
for (processor in processors) {
references = references.flatMap { processor.processUsage(it) ?: listOf(it) }
references.forEach { checkReferenceValid(it) }
}
}
}
private fun checkReferenceValid(reference: PsiReference) {
val element = reference.getElement()
assert(element.isValid() && element.getContainingFile() !is DummyHolder) { "Reference $reference got invalidated" }
}
private object ReferenceComparator : Comparator<ReferenceInfo> {
override fun compare(info1: ReferenceInfo, info2: ReferenceInfo): Int {
val element1 = info1.reference.getElement()
val element2 = info2.reference.getElement()
val deepness1 = element1.deepnessInTree()
val deepness2 = element2.deepnessInTree()
if (deepness1 != deepness2) { // put deeper elements first to not invalidate them when processing ancestors
return -deepness1.compareTo(deepness2)
}
// process elements of the same deepness from right to left so that right-side of assignments is not invalidated by processing of the left one
return -element1.getStartOffsetInParent().compareTo(element2.getStartOffsetInParent())
}
private fun PsiElement.deepnessInTree() = parents(withItself = true).takeWhile { it !is PsiFile }.count()
}
private class ProgressPortionReporter(
indicator: ProgressIndicator,
private val start: Double,
private val portion: Double
) : DelegatingProgressIndicator(indicator) {
init {
setFraction(0.0)
}
override fun start() {
setFraction(0.0)
}
override fun stop() {
setFraction(portion)
}
override fun setFraction(fraction: Double) {
super.setFraction(start + (fraction * portion))
}
override fun getFraction(): Double {
return (super.getFraction() - start) / portion
}
override fun setText(text: String?) {
}
override fun setText2(text: String?) {
}
}
}
@@ -135,7 +135,7 @@ public object JavaToKotlinTranslator {
val file = createFile(javaCode)
if (file is PsiJavaFile) {
val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, EmptyReferenceSearcher, EmptyResolverForConverter, null)
return prettify(converter.elementsToKotlin(listOf(JavaToKotlinConverter.InputElement(file, null))).single()!!.text)
return prettify(converter.elementsToKotlin(listOf(JavaToKotlinConverter.InputElement(file, null))).results.single()!!.text)
}
return ""
}
@@ -16,49 +16,67 @@
package org.jetbrains.kotlin.j2k
import com.intellij.psi.PsiVariable
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReferenceExpression
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
import com.intellij.psi.search.DelegatingGlobalSearchScope
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiClass
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.idea.JetLanguage
public trait ReferenceSearcher {
fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression>
fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression>
fun findLocalUsages(element: PsiElement, scope: PsiElement): Collection<PsiReference>
fun hasInheritors(`class`: PsiClass): Boolean
fun hasOverrides(method: PsiMethod): Boolean
fun findExternalCodeProcessingUsages(element: PsiElement, searchJava: Boolean, searchKotlin: Boolean): Collection<PsiReference>
}
public fun ReferenceSearcher.findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression>
= findLocalUsages(variable, scope).filterIsInstance<PsiReferenceExpression>()
public fun ReferenceSearcher.findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression> {
return findLocalUsages(method, scope).map {
if (it is PsiReferenceExpression) {
val methodCall = it.getParent() as? PsiMethodCallExpression
if (methodCall?.getMethodExpression() == it) methodCall else null
}
else {
null
}
}.filterNotNull()
}
public object EmptyReferenceSearcher: ReferenceSearcher {
override fun findVariableUsages(variable: PsiVariable, scope: PsiElement) = listOf<PsiReferenceExpression>()
override fun findMethodCalls(method: PsiMethod, scope: PsiElement) = listOf<PsiMethodCallExpression>()
override fun findLocalUsages(element: PsiElement, scope: PsiElement): Collection<PsiReference> = emptyList()
override fun hasInheritors(`class`: PsiClass) = false
override fun hasOverrides(method: PsiMethod) = false
override fun findExternalCodeProcessingUsages(element: PsiElement, searchJava: Boolean, searchKotlin: Boolean): Collection<PsiReference>
= throw UnsupportedOperationException()
}
public object IdeaReferenceSearcher : ReferenceSearcher {
override fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection<PsiReferenceExpression> {
return ReferencesSearch.search(variable, LocalSearchScope(scope)).findAll().filterIsInstance<PsiReferenceExpression>()
}
override fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection<PsiMethodCallExpression> {
return ReferencesSearch.search(method, LocalSearchScope(scope)).findAll().map {
if (it is PsiReferenceExpression) {
val methodCall = it.getParent() as? PsiMethodCallExpression
if (methodCall?.getMethodExpression() == it) methodCall else null
}
else {
null
}
}.filterNotNull()
}
public object IdeaReferenceSearcher: ReferenceSearcher {
override fun findLocalUsages(element: PsiElement, scope: PsiElement) = ReferencesSearch.search(element, LocalSearchScope(scope)).findAll()
override fun hasInheritors(`class`: PsiClass) = ClassInheritorsSearch.search(`class`, false).any()
override fun hasOverrides(method: PsiMethod) = OverridingMethodsSearch.search(method, false).any()
override fun findExternalCodeProcessingUsages(element: PsiElement, searchJava: Boolean, searchKotlin: Boolean): Collection<PsiReference> {
val searchScope = object : DelegatingGlobalSearchScope(GlobalSearchScope.projectScope(element.getProject())) {
override fun contains(file: VirtualFile): Boolean {
if (!super.contains(file)) return false
return when (FileTypeManager.getInstance().getFileTypeByFile(file)) {
JavaLanguage.INSTANCE.getAssociatedFileType() -> searchJava
JetLanguage.INSTANCE.getAssociatedFileType() -> searchKotlin
else -> false
}
}
}
return ReferencesSearch.search(element, searchScope).findAll()
}
}
@@ -79,6 +79,11 @@ fun PsiReferenceExpression.isQualifierEmptyOrThis(): Boolean {
return qualifier == null || (qualifier is PsiThisExpression && qualifier.getQualifier() == null)
}
fun PsiReferenceExpression.isQualifierEmptyOrClass(psiClass: PsiClass): Boolean {
val qualifier = getQualifierExpression()
return qualifier == null || (qualifier is PsiReferenceExpression && qualifier.isReferenceTo(psiClass))
}
fun PsiElement.isInSingleLine(): Boolean {
if (this is PsiWhiteSpace) {
val text = getText()!!
@@ -17,8 +17,10 @@
package org.jetbrains.kotlin.j2k.usageProcessing
import com.intellij.psi.*
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.AccessorKind
import org.jetbrains.kotlin.j2k.CodeConverter
import org.jetbrains.kotlin.j2k.ast.*
import org.jetbrains.kotlin.psi.*
class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKind: AccessorKind, val propertyName: String) : UsageProcessing {
override val targetElement: PsiElement get() = accessorMethod
@@ -34,11 +36,11 @@ class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKi
val propertyAccess = QualifiedExpression(codeConverter.convertExpression(methodExpr.getQualifierExpression()), propertyName).assignNoPrototype()
if (accessorKind == AccessorKind.GETTER) {
if (arguments.size != 0) return null // incorrect call
if (arguments.size() != 0) return null // incorrect call
return propertyAccess
}
else {
if (arguments.size != 1) return null // incorrect call
if (arguments.size() != 1) return null // incorrect call
val argument = codeConverter.convertExpression(arguments[0])
return AssignmentExpression(propertyAccess, argument, "=")
}
@@ -47,10 +49,42 @@ class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKi
override val javaCodeProcessor: ExternalCodeProcessor? = null
override val kotlinCodeProcessor: ExternalCodeProcessor? = object: ExternalCodeProcessor {
override fun processUsage(reference: PsiReference) {
//TODO
//reference.getElement() as JetSimpleNameExpression
override val kotlinCodeProcessor: ExternalCodeProcessor? = if (accessorMethod.hasModifierProperty(PsiModifier.PRIVATE))
null
else
object : ExternalCodeProcessor {
override fun processUsage(reference: PsiReference): Collection<PsiReference>? {
val nameExpr = reference.getElement() as? JetSimpleNameExpression ?: return null
val callExpr = nameExpr.getParent() as? JetCallExpression ?: return null
val arguments = callExpr.getValueArguments()
val factory = JetPsiFactory(nameExpr.getProject())
var propertyNameExpr = factory.createSimpleName(propertyName)
if (accessorKind == AccessorKind.GETTER) {
if (arguments.size() != 0) return null // incorrect call
propertyNameExpr = callExpr.replace(propertyNameExpr) as JetSimpleNameExpression
return listOf(propertyNameExpr.getReference())
}
else {
val value = arguments.singleOrNull()?.getArgumentExpression() ?: return null
var assignment = factory.createExpression("a = b") as JetBinaryExpression
assignment.getRight()!!.replace(value)
val qualifiedExpression = callExpr.getParent() as? JetQualifiedExpression
if (qualifiedExpression != null && qualifiedExpression.getSelectorExpression() == callExpr) {
callExpr.replace(propertyNameExpr)
assignment.getLeft()!!.replace(qualifiedExpression)
assignment = qualifiedExpression.replace(assignment) as JetBinaryExpression
return listOf((assignment.getLeft() as JetQualifiedExpression).getSelectorExpression()!!.getReference())
}
else {
assignment.getLeft()!!.replace(propertyNameExpr)
assignment = callExpr.replace(assignment) as JetBinaryExpression
return listOf(assignment.getLeft()!!.getReference())
}
}
}
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.usageProcessing
import com.intellij.psi.PsiReference
class ElementRenamedCodeProcessor(private val newName: String) : ExternalCodeProcessor {
override fun processUsage(reference: PsiReference): Collection<PsiReference>? {
val newReference = reference.handleElementRename(newName).getReference()!!
return listOf(newReference)
}
}
@@ -17,44 +17,135 @@
package org.jetbrains.kotlin.j2k.usageProcessing
import com.intellij.psi.*
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.j2k.AccessorKind
import org.jetbrains.kotlin.j2k.CodeConverter
import org.jetbrains.kotlin.j2k.ast.*
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
class FieldToPropertyProcessing(val field: PsiField, val propertyName: String, val isNullable: Boolean) : UsageProcessing {
override val targetElement: PsiElement get() = field
override val convertedCodeProcessor = if (field.getName() != propertyName) {
object: ConvertedCodeProcessor {
override fun convertVariableUsage(expression: PsiReferenceExpression, codeConverter: CodeConverter): Expression? {
val identifier = Identifier(propertyName, isNullable).assignNoPrototype()
override val convertedCodeProcessor = if (field.getName() != propertyName) MyConvertedCodeProcessor() else null
val qualifier = expression.getQualifierExpression()
if (qualifier != null) {
return QualifiedExpression(codeConverter.convertExpression(qualifier), identifier)
override var javaCodeProcessor = if (field.hasModifierProperty(PsiModifier.PRIVATE))
null
else if (!field.hasModifierProperty(PsiModifier.STATIC))
UseAccessorsJavaCodeProcessor()
else if (field.getName() != propertyName)
ElementRenamedCodeProcessor(propertyName)
else
null
override val kotlinCodeProcessor = if (field.getName() != propertyName) ElementRenamedCodeProcessor(propertyName) else null
private inner class MyConvertedCodeProcessor : ConvertedCodeProcessor {
override fun convertVariableUsage(expression: PsiReferenceExpression, codeConverter: CodeConverter): Expression? {
val identifier = Identifier(propertyName, isNullable).assignNoPrototype()
val qualifier = expression.getQualifierExpression()
if (qualifier != null) {
return QualifiedExpression(codeConverter.convertExpression(qualifier), identifier)
}
else {
// check if field name is shadowed
val elementFactory = PsiElementFactory.SERVICE.getInstance(expression.getProject())
val refExpr = try {
elementFactory.createExpressionFromText(propertyName, expression) as? PsiReferenceExpression ?: return identifier
}
else {
// check if field name is shadowed
val elementFactory = PsiElementFactory.SERVICE.getInstance(expression.getProject())
val refExpr = try {
elementFactory.createExpressionFromText(propertyName, expression) as? PsiReferenceExpression ?: return identifier
}
catch(e: IncorrectOperationException) {
return identifier
}
return if (refExpr.resolve() == null)
identifier
else
QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier) //TODO: this is not correct in case of nested/anonymous classes
catch(e: IncorrectOperationException) {
return identifier
}
return if (refExpr.resolve() == null)
identifier
else
QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier) //TODO: this is not correct in case of nested/anonymous classes
}
}
}
else {
null
private inner class UseAccessorsJavaCodeProcessor : ExternalCodeProcessor {
private val factory = PsiElementFactory.SERVICE.getInstance(field.getProject())
override fun processUsage(reference: PsiReference): Collection<PsiReference>? {
val refExpr = reference.getElement() as? PsiReferenceExpression ?: return null
val qualifier = refExpr.getQualifierExpression()
val parent = refExpr.getParent()
when (parent) {
is PsiAssignmentExpression -> {
if (refExpr == parent.getLExpression()) {
if (parent.getOperationTokenType() == JavaTokenType.EQ) {
val callExpr = parent.replace(generateSetterCall(qualifier, parent.getRExpression() ?: return null)) as PsiMethodCallExpression
return listOf(callExpr.getMethodExpression())
}
else {
val assignmentOpText = parent.getOperationSign().getText()
assert(assignmentOpText.endsWith("="))
val opText = assignmentOpText.substring(0, assignmentOpText.length() - 1)
return parent.replaceWithModificationCalls(qualifier, opText, parent.getRExpression() ?: return null)
}
}
}
is PsiPrefixExpression, is PsiPostfixExpression -> {
//TODO: what if it's used as value?
val operationType = if (parent is PsiPrefixExpression)
parent.getOperationTokenType()
else
(parent as PsiPostfixExpression).getOperationTokenType()
val opText = when (operationType) {
JavaTokenType.PLUSPLUS -> "+"
JavaTokenType.MINUSMINUS -> "-"
else -> null
}
if (opText != null) {
return (parent as PsiExpression).replaceWithModificationCalls(qualifier, opText, factory.createExpressionFromText("1", null))
}
}
}
val callExpr = refExpr.replace(generateGetterCall(qualifier)) as PsiMethodCallExpression
return listOf(callExpr.getMethodExpression())
}
//TODO: what if qualifier has side effects?
private fun PsiExpression.replaceWithModificationCalls(qualifier: PsiExpression?, op: String, value: PsiExpression): Collection<PsiReference> {
var getCall = generateGetterCall(qualifier)
var binary = factory.createExpressionFromText("x $op y", null) as PsiBinaryExpression
binary.getLOperand().replace(getCall)
binary.getROperand()!!.replace(value)
var setCall = generateSetterCall(qualifier, binary) as PsiMethodCallExpression
setCall = this.replace(setCall) as PsiMethodCallExpression
binary = setCall.getArgumentList().getExpressions().single() as PsiBinaryExpression
getCall = binary.getLOperand() as PsiMethodCallExpression
return listOf(getCall.getMethodExpression().getReference(), setCall.getMethodExpression().getReference())
}
private fun generateGetterCall(qualifier: PsiExpression?): PsiMethodCallExpression {
val text = accessorName(AccessorKind.GETTER) + "()"
val expressionText = if (qualifier != null)
"${qualifier.getText()}.$text"
else
text
return factory.createExpressionFromText(expressionText, null) as PsiMethodCallExpression
}
private fun generateSetterCall(qualifier: PsiExpression?, value: PsiExpression): PsiExpression {
val text = accessorName(AccessorKind.SETTER) + "(" + value.getText() + ")"
val expressionText = if (qualifier != null)
"${qualifier.getText()}.$text"
else
text
return factory.createExpressionFromText(expressionText, null)
}
}
override val javaCodeProcessor: ExternalCodeProcessor? get() = null //TODO
override val kotlinCodeProcessor: ExternalCodeProcessor? get() = null //TODO
private fun accessorName(kind: AccessorKind)
= (if (kind == AccessorKind.GETTER) "get" else "set") + propertyName.capitalize()
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.usageProcessing
import com.intellij.psi.*
public class MethodIntoObjectProcessing(private val method: PsiMethod, private val objectName: String) : UsageProcessing {
override val targetElement: PsiElement get() = method
override val convertedCodeProcessor: ConvertedCodeProcessor? get() = null
override val javaCodeProcessor = object: ExternalCodeProcessor {
override fun processUsage(reference: PsiReference): Collection<PsiReference>? {
val refExpr = reference.getElement() as? PsiReferenceExpression ?: return null
val qualifier = refExpr.getQualifierExpression()
val factory = PsiElementFactory.SERVICE.getInstance(method.getProject())
if (qualifier != null) {
val newQualifier = factory.createExpressionFromText(qualifier.getText() + "." + objectName, null)
qualifier.replace(newQualifier)
return listOf(reference)
}
else {
var qualifiedExpr = factory.createExpressionFromText(objectName + "." + refExpr.getText(), null) as PsiReferenceExpression
qualifiedExpr = refExpr.replace(qualifiedExpr) as PsiReferenceExpression
return listOf(qualifiedExpr.getReference())
}
}
}
override val kotlinCodeProcessor: ExternalCodeProcessor? get() = null
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.usageProcessing
import com.intellij.psi.*
import org.jetbrains.kotlin.load.java.JvmAbi
class ToObjectWithOnlyMethodsProcessing(private val psiClass: PsiClass) : UsageProcessing {
override val targetElement: PsiElement get() = psiClass
override val convertedCodeProcessor: ConvertedCodeProcessor? get() = null
override val javaCodeProcessor = object: ExternalCodeProcessor {
override fun processUsage(reference: PsiReference): Collection<PsiReference>? {
val refExpr = reference.getElement() as? PsiReferenceExpression ?: return null
val factory = PsiElementFactory.SERVICE.getInstance(psiClass.getProject())
var qualifiedExpr = factory.createExpressionFromText(refExpr.getText() + "." + JvmAbi.INSTANCE_FIELD, null) as PsiReferenceExpression
qualifiedExpr = refExpr.replace(qualifiedExpr) as PsiReferenceExpression
return listOf(qualifiedExpr.getReference())
}
}
override val kotlinCodeProcessor: ExternalCodeProcessor? get() = null
}
@@ -16,10 +16,11 @@
package org.jetbrains.kotlin.j2k.usageProcessing
import org.jetbrains.kotlin.j2k.ast.Expression
import com.google.common.collect.Multimap
import com.intellij.psi.*
import org.jetbrains.kotlin.j2k.CodeConverter
import org.jetbrains.kotlin.j2k.SpecialExpressionConverter
import org.jetbrains.kotlin.j2k.ast.Expression
trait UsageProcessing {
val targetElement: PsiElement
@@ -35,24 +36,32 @@ trait ConvertedCodeProcessor {
}
trait ExternalCodeProcessor {
fun processUsage(reference: PsiReference)
fun processUsage(reference: PsiReference): Collection<PsiReference>?
}
class UsageProcessingExpressionConverter(val processings: Map<PsiElement, UsageProcessing>) : SpecialExpressionConverter {
class UsageProcessingExpressionConverter(val processings: Map<PsiElement, Collection<UsageProcessing>>) : SpecialExpressionConverter {
override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
if (processings.isEmpty()) return null
when (expression) {
is PsiReferenceExpression -> {
val target = expression.resolve() as? PsiVariable ?: return null
val processor = processings[target]?.convertedCodeProcessor ?: return null
return processor.convertVariableUsage(expression, codeConverter)
val forTarget = processings[target] ?: return null
for (processing in forTarget) {
val converted = processing.convertedCodeProcessor?.convertVariableUsage(expression, codeConverter)
if (converted != null) return converted
}
return null
}
is PsiMethodCallExpression -> {
val target = expression.getMethodExpression().resolve() as? PsiMethod ?: return null
val processor = processings[target]?.convertedCodeProcessor ?: return null
return processor.convertMethodUsage(expression, codeConverter)
val forTarget = processings[target] ?: return null
for (processing in forTarget) {
val converted = processing.convertedCodeProcessor?.convertMethodUsage(expression, codeConverter)
if (converted != null) return converted
}
return null
}
else -> return null
@@ -0,0 +1,15 @@
public class AAA {
public void foo() {
setX(getX() + 1);
}
private static int ourX = 42;
public static int getX() {
return ourX;
}
public static void setX(int x) {
ourX = x;
}
}
@@ -0,0 +1,10 @@
public class AAA {
public fun foo() {
x = x + 1
}
companion object {
public var x: Int = 42
}
}
@@ -0,0 +1,33 @@
public class AAA {
private static int ourX = 42;
private static int y = 0;
private static int z = 0;
public static int getX() {
return ourX;
}
public static void setX(int x) {
ourX = x;
}
public static int getY() {
return y;
}
public static void setY(int y) {
AAA.y = y;
}
public static int getZ() {
return z;
}
public static void setZ(int z) {
Other.z = z;
}
}
class Other {
public static int z = 0;
}
@@ -0,0 +1,13 @@
public object AAA {
public var x: Int = 42
public var y: Int = 0
public val z: Int = 0
public fun setZ(z: Int) {
Other.z = z
}
}
object Other {
public var z: Int = 0
}
@@ -0,0 +1,11 @@
package test;
class JavaClass {
public int field = 0;
protected int myProperty = 0;
public int getProperty() {
return myProperty;
}
}
@@ -0,0 +1,8 @@
package test
open class JavaClass {
public var field: Int = 0
public var property: Int = 0
protected set
}
@@ -0,0 +1,12 @@
package test;
class C extends JavaClass {
public void foo(JavaClass javaClass) {
javaClass.field++;
--javaClass.field;
myProperty = javaClass.field;
javaClass.field -= field;
field = myProperty;
field *= 2;
}
}
@@ -0,0 +1,12 @@
package test;
class C extends JavaClass {
public void foo(JavaClass javaClass) {
javaClass.setField(javaClass.getField() + 1);
javaClass.setField(javaClass.getField() - 1);
setProperty(javaClass.getField());
javaClass.setField(javaClass.getField() - getField());
setField(getProperty());
setField(getField() * 2);
}
}
@@ -0,0 +1,10 @@
package test
class C : JavaClass() {
public fun foo(javaClass: JavaClass) {
javaClass.field++
myProperty = javaClass.field
field = myProperty
field *= 2
}
}
@@ -0,0 +1,10 @@
package test
class C : JavaClass() {
public fun foo(javaClass: JavaClass) {
javaClass.field++
property = javaClass.field
field = property
field *= 2
}
}
@@ -0,0 +1,11 @@
fun foo1(a: AAA) {
a.setX(a.getX() + 1)
}
fun foo2(a: AAA?) {
a?.setX((a?.getX() ?: 0) + 1)
}
fun AAA.foo() {
setX(getX() + 1)
}
@@ -0,0 +1,11 @@
fun foo1(a: AAA) {
a.x = a.x + 1
}
fun foo2(a: AAA?) {
a?.x = (a?.x ?: 0) + 1
}
fun AAA.foo() {
x = x + 1
}
@@ -0,0 +1,3 @@
void foo(AAA a) {
a.setX(a.getX() + 1)
}
@@ -0,0 +1,3 @@
void foo(AAA a) {
a.setX(a.getX() + 1)
}
@@ -0,0 +1,14 @@
package test;
class ClassWithStatics {
public void instanceMethod(){}
public static void staticMethod(int p) {}
public static final int staticField = 1;
protected static int ourValue = 0;
public static int getValue() { return ourValue; }
public static void setValue(int value) { ourValue = value; }
}
@@ -0,0 +1,16 @@
package test
open class ClassWithStatics {
public fun instanceMethod() {
}
companion object {
public fun staticMethod(p: Int) {
}
public val staticField: Int = 1
public var value: Int = 0
}
}
@@ -0,0 +1,16 @@
package test;
class C {
void foo(ClassWithStatics c) {
ClassWithStatics.staticMethod(ClassWithStatics.staticField);
c.instanceMethod();
ClassWithStatics.staticField += 2;
}
}
class D extends ClassWithStatics {
void foo() {
staticMethod(staticField);
ourValue *= 2;
}
}
@@ -0,0 +1,16 @@
package test;
class C {
void foo(ClassWithStatics c) {
ClassWithStatics.Companion.staticMethod(ClassWithStatics.staticField);
c.instanceMethod();
ClassWithStatics.staticField += 2;
}
}
class D extends ClassWithStatics {
void foo() {
Companion.staticMethod(staticField);
value *= 2;
}
}
@@ -0,0 +1,5 @@
package test
fun foo() {
ClassWithStatics.staticMethod(ClassWithStatics.staticField)
}
@@ -0,0 +1,5 @@
package test
fun foo() {
ClassWithStatics.staticMethod(ClassWithStatics.staticField)
}
@@ -0,0 +1,6 @@
package test;
class PureUtils {
public static void foo1(int p) {}
public static int foo2() { return 1; }
}
@@ -0,0 +1,10 @@
package test
object PureUtils {
public fun foo1(p: Int) {
}
public fun foo2(): Int {
return 1
}
}
@@ -0,0 +1,8 @@
package test;
class Utils {
public static void foo1(int p) {}
public static int foo2() { return 1; }
public static final int staticField = 1;
}
+12
View File
@@ -0,0 +1,12 @@
package test
object Utils {
public fun foo1(p: Int) {
}
public fun foo2(): Int {
return 1
}
public val staticField: Int = 1
}
@@ -0,0 +1,9 @@
package test;
class C {
void foo() {
Utils.foo1(Utils.staticField);
Utils.staticField += Utils.foo2();
PureUtils.foo1(PureUtils.foo2())
}
}
@@ -0,0 +1,9 @@
package test;
class C {
void foo() {
Utils.INSTANCE$.foo1(Utils.staticField);
Utils.staticField += Utils.INSTANCE$.foo2();
PureUtils.INSTANCE$.foo1(PureUtils.INSTANCE$.foo2())
}
}
@@ -0,0 +1,6 @@
package test
fun foo() {
Utils.foo1(Utils.staticField)
PureUtils.foo1(PureUtils.foo2())
}
@@ -0,0 +1,6 @@
package test
fun foo() {
Utils.foo1(Utils.staticField)
PureUtils.foo1(PureUtils.foo2())
}
@@ -16,49 +16,74 @@
package org.jetbrains.kotlin.j2k
import java.io.File
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.test.JetTestUtils
import com.intellij.openapi.project.Project
import com.intellij.openapi.command.WriteCommandAction
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.JetWithJdkAndRuntimeLightProjectDescriptor
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import java.util.ArrayList
import org.jetbrains.kotlin.psi.JetFile
import com.intellij.testFramework.LightPlatformTestCase
import org.jetbrains.kotlin.idea.JetWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.test.JetTestUtils
import java.io.File
import java.util.ArrayList
public abstract class AbstractJavaToKotlinConverterMultiFileTest : AbstractJavaToKotlinConverterTest() {
public fun doTest(dirPath: String) {
val project = LightPlatformTestCase.getProject()!!
val psiManager = PsiManager.getInstance(project)
val javaFiles = File(dirPath).listFiles { file, name -> name.endsWith(".java") }
val psiFiles = ArrayList<PsiJavaFile>()
for (javaFile: File in javaFiles) {
val filesToConvert = File(dirPath).listFiles { file, name -> name.endsWith(".java") }
val psiFilesToConvert = ArrayList<PsiJavaFile>()
for (javaFile in filesToConvert) {
val virtualFile = addFile(javaFile, "test")
val psiFile = psiManager.findFile(virtualFile) as PsiJavaFile
psiFiles.add(psiFile)
psiFilesToConvert.add(psiFile)
}
val externalFiles = File(dirPath + File.separator + "external").listFiles { file, name -> name.endsWith(".java") || name.endsWith(".kt") }
val externalPsiFiles = ArrayList<PsiFile>()
for (file in externalFiles) {
val virtualFile = addFile(file, "test")
val psiFile = psiManager.findFile(virtualFile)!!
externalPsiFiles.add(psiFile)
assert(psiFile is PsiJavaFile || psiFile is JetFile)
}
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings,
IdeaReferenceSearcher, IdeaResolverForConverter, J2kPostProcessor(formatCode = true))
val inputElements = psiFiles.map { JavaToKotlinConverter.InputElement(it, it) }
val results: List<String> = converter.elementsToKotlin(inputElements).map { it!!.text }
val inputElements = psiFilesToConvert.map { JavaToKotlinConverter.InputElement(it, it) }
val (results, externalCodeProcessor) = converter.elementsToKotlin(inputElements)
fun expectedFile(i: Int) = File(javaFiles[i].getPath().replace(".java", ".kt"))
val process = externalCodeProcessor?.invoke(EmptyProgressIndicator())
project.executeWriteCommand("") { process?.invoke() }
val jetFiles = ArrayList<JetFile>()
for (i in javaFiles.indices) {
deleteFile(psiFiles[i].getVirtualFile())
val virtualFile = addFile(results[i], expectedFile(i).getName(), "test")
jetFiles.add(psiManager.findFile(virtualFile) as JetFile)
fun expectedResultFile(i: Int) = File(filesToConvert[i].getPath().replace(".java", ".kt"))
val resultFiles = ArrayList<JetFile>()
for ((i, javaFile) in psiFilesToConvert.withIndex()) {
deleteFile(javaFile.getVirtualFile())
val virtualFile = addFile(results.map { it!!.text }[i], expectedResultFile(i).getName(), "test")
resultFiles.add(psiManager.findFile(virtualFile) as JetFile)
}
for ((i, jetFile) in jetFiles.withIndex()) {
JetTestUtils.assertEqualsToFile(expectedFile(i), addErrorsDump(jetFile))
for ((i, kotlinFile) in resultFiles.withIndex()) {
JetTestUtils.assertEqualsToFile(expectedResultFile(i), addErrorsDump(kotlinFile))
}
for ((externalFile, externalPsiFile) in externalFiles.zip(externalPsiFiles)) {
val expectedFile = File(externalFile.getPath() + ".expected")
var resultText = if (externalPsiFile is JetFile) {
addErrorsDump(externalPsiFile)
}
else {
//TODO: errors dump for java files too
externalPsiFile.getText()
}
JetTestUtils.assertEqualsToFile(expectedFile, resultText)
}
}
@@ -109,7 +109,7 @@ public abstract class AbstractJavaToKotlinConverterSingleFileTest : AbstractJava
val converter = JavaToKotlinConverter(project, settings,
IdeaReferenceSearcher, IdeaResolverForConverter, J2kPostProcessor(formatCode = false))
val inputElements = listOf(JavaToKotlinConverter.InputElement(file, file))
return converter.elementsToKotlin(inputElements).single()!!.text
return converter.elementsToKotlin(inputElements).results.single()!!.text
}
private fun methodToKotlin(text: String, settings: ConverterSettings, project: Project): String {
@@ -45,8 +45,8 @@ public abstract class AbstractJavaToKotlinConverterTest : LightCodeInsightFixtur
super.tearDown()
}
private fun addFile(fileName: String, packageName: String) {
addFile(File("j2k/testData/$fileName"), packageName)
private fun addFile(fileName: String, dirName: String) {
addFile(File("j2k/testData/$fileName"), dirName)
}
protected fun addFile(file: File, dirName: String): VirtualFile {
@@ -58,7 +58,7 @@ public abstract class AbstractJavaToKotlinConverterTest : LightCodeInsightFixtur
override fun compute(): VirtualFile? {
val root = LightPlatformTestCase.getSourceRoot()!!
val virtualDir = root.findChild(dirName) ?: root.createChildDirectory(null, dirName)
val virtualFile = virtualDir.createChildData(null, fileName)!!
val virtualFile = virtualDir.createChildData(null, fileName)
virtualFile.getOutputStream(null)!!.writer().use { it.write(text) }
return virtualFile
}
@@ -1616,6 +1616,18 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
doTest(fileName);
}
@TestMetadata("InCompanionObject.java")
public void testInCompanionObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/dropAccessors/InCompanionObject.java");
doTest(fileName);
}
@TestMetadata("InObject.java")
public void testInObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/dropAccessors/InObject.java");
doTest(fileName);
}
@TestMetadata("JavaKeywordPropertyName.java")
public void testJavaKeywordPropertyName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/dropAccessors/JavaKeywordPropertyName.java");
@@ -30,12 +30,16 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@TestMetadata("j2k/testData/multiFile")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({
})
@RunWith(JUnit3RunnerWithInners.class)
public class JavaToKotlinConverterMultiFileTestGenerated extends AbstractJavaToKotlinConverterMultiFileTest {
public void testAllFilesPresentInMultiFile() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/multiFile"), Pattern.compile("^([^\\.]+)$"), true);
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/multiFile"), Pattern.compile("^([^\\.]+)$"), false);
}
@TestMetadata("FieldToProperty")
public void testFieldToProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/multiFile/FieldToProperty/");
doTest(fileName);
}
@TestMetadata("GetterAndSetterUsages")
@@ -44,4 +48,15 @@ public class JavaToKotlinConverterMultiFileTestGenerated extends AbstractJavaToK
doTest(fileName);
}
@TestMetadata("ToCompanionObject")
public void testToCompanionObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/multiFile/ToCompanionObject/");
doTest(fileName);
}
@TestMetadata("ToObject")
public void testToObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/multiFile/ToObject/");
doTest(fileName);
}
}
@@ -1616,6 +1616,18 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
doTest(fileName);
}
@TestMetadata("InCompanionObject.java")
public void testInCompanionObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/dropAccessors/InCompanionObject.java");
doTest(fileName);
}
@TestMetadata("InObject.java")
public void testInObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/dropAccessors/InObject.java");
doTest(fileName);
}
@TestMetadata("JavaKeywordPropertyName.java")
public void testJavaKeywordPropertyName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/dropAccessors/JavaKeywordPropertyName.java");