diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index cdb6d1067ed..386199ad579 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -714,7 +714,7 @@ fun main(args: Array) { } testGroup("j2k/tests", "j2k/testData") { testClass(javaClass()) { - model("multiFile", extension = null) + model("multiFile", extension = null, recursive = false) } } testGroup("j2k/tests", "j2k/testData") { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetSimpleNameReference.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetSimpleNameReference.kt index b2318d0c54d..ae48a162cfe 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetSimpleNameReference.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetSimpleNameReference.kt @@ -126,7 +126,8 @@ public class JetSimpleNameReference( ) } - return nameElement.replace(element) + nameElement.replace(element) + return expression } public enum class ShorteningMode { diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt index 3b5f3474fab..bfe06d7bdc6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.idea.actions -import com.intellij.codeInsight.actions.ReformatCodeProcessor import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys @@ -25,6 +24,7 @@ import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.ex.MessagesEx import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.openapi.vfs.VfsUtilCore @@ -32,14 +32,14 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFileVisitor import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager -import com.intellij.psi.codeStyle.CodeStyleManager import org.jetbrains.kotlin.idea.j2k.IdeaResolverForConverter import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor +import org.jetbrains.kotlin.idea.util.application.executeCommand +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.j2k.ConverterSettings import org.jetbrains.kotlin.j2k.IdeaReferenceSearcher import org.jetbrains.kotlin.j2k.JavaToKotlinConverter -import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.utils.addIfNotNull import java.io.IOException import java.util.ArrayList @@ -49,36 +49,53 @@ public class JavaToKotlinAction : AnAction() { val javaFiles = selectedJavaFiles(e).toList() val project = CommonDataKeys.PROJECT.getData(e.getDataContext())!! - var convertedTexts: List? = null + var converterResult: JavaToKotlinConverter.Result? = null fun convert() { val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaReferenceSearcher, IdeaResolverForConverter, J2kPostProcessor(formatCode = true)) val inputElements = javaFiles.map { JavaToKotlinConverter.InputElement(it, it) } - convertedTexts = converter.elementsToKotlin(inputElements, ProgressManager.getInstance().getProgressIndicator()) - .map { it!!.text /*conversion of a file always succeeds*/ } + converterResult = converter.elementsToKotlin(inputElements, ProgressManager.getInstance().getProgressIndicator()) } + val title = "Convert Java to Kotlin" if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( { runReadAction(::convert) }, - "Converting Java to Kotlin", + title, true, project)) return - CommandProcessor.getInstance().executeCommand(project, object : Runnable { - override fun run() { - CommandProcessor.getInstance().markCurrentCommandAsGlobal(project) + var externalCodeUpdate: (() -> Unit)? = null - val newFiles = saveResults(javaFiles, convertedTexts!!) - deleteFiles(javaFiles) - - newFiles.singleOrNull()?.let { - FileEditorManager.getInstance(project).openFile(it, true) - } + if (converterResult!!.externalCodeProcessing != null) { + val question = "Some code in the rest of your project may require corrections after performing this conversion. Do you want to find such code and correct it too?" + if (Messages.showOkCancelDialog(project, question, title, Messages.getQuestionIcon()) == Messages.OK) { + ProgressManager.getInstance().runProcessWithProgressSynchronously( + { + runReadAction { + externalCodeUpdate = converterResult!!.externalCodeProcessing(ProgressManager.getInstance().getProgressIndicator()) + } + }, + title, + true, + project) } - }, "Convert files from Java to Kotlin", null) + } + + project.executeWriteCommand("Convert files from Java to Kotlin") { + CommandProcessor.getInstance().markCurrentCommandAsGlobal(project) + + val newFiles = saveResults(javaFiles, converterResult!!.results.map { it!!.text /*conversion of a file always succeeds*/ }) + deleteFiles(javaFiles) + + externalCodeUpdate?.invoke() + + newFiles.singleOrNull()?.let { + FileEditorManager.getInstance(project).openFile(it, true) + } + } } override fun update(e: AnActionEvent) { @@ -116,9 +133,7 @@ public class JavaToKotlinAction : AnAction() { private fun saveResults(javaFiles: List, convertedTexts: List): List { val result = ArrayList() for ((psiFile, text) in javaFiles.zip(convertedTexts)) { - ApplicationManager.getApplication().runWriteAction { - result.addIfNotNull(saveConversionResult(psiFile.getVirtualFile(), text, psiFile.getProject())) - } + result.addIfNotNull(saveConversionResult(psiFile.getVirtualFile(), text, psiFile.getProject())) } return result } @@ -137,13 +152,11 @@ public class JavaToKotlinAction : AnAction() { private fun deleteFiles(javaFiles: List) { for (psiFile in javaFiles) { - ApplicationManager.getApplication().runWriteAction { - try { - psiFile.getVirtualFile()?.delete(this) - } - catch (e: IOException) { - MessagesEx.error(psiFile.getProject(), e.getMessage()).showLater() - } + try { + psiFile.getVirtualFile()?.delete(this) + } + catch (e: IOException) { + MessagesEx.error(psiFile.getProject(), e.getMessage()).showLater() } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPastePostProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPastePostProcessor.kt index db599b95424..200cedeebc0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPastePostProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPastePostProcessor.kt @@ -161,7 +161,7 @@ public class ConvertJavaCopyPastePostProcessor : CopyPastePostProcessor().map { JavaToKotlinConverter.InputElement(it, null) } - val results = converter.elementsToKotlin(inputElements) + val results = converter.elementsToKotlin(inputElements).results var resultIndex = 0 val convertedCodeBuilder = StringBuilder() diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt index c2cc238493f..9650fd3ba31 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt @@ -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 } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt index 1464abab967..817b26ec1a2 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt @@ -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) -> String, + val codeGenerator: (Map>) -> String, val parseContext: ParseContext ) @@ -108,7 +109,7 @@ class Converter private( else -> null } - private fun unfoldDeferredElements(usageProcessings: Map) { + private fun unfoldDeferredElements(usageProcessings: Map>) { val codeConverter = createDefaultCodeConverter().withSpecialExpressionConverter(UsageProcessingExpressionConverter(usageProcessings)) // we use loop with index because new deferred elements can be added during unfolding diff --git a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt index 9bce8fd8c1d..8660f09a5ae 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinConverter.kt @@ -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, val externalCodeProcessing: ((ProgressIndicator) -> (() -> Unit)?)?) //TODO: change interface to not perform write-actions under progress public fun elementsToKotlin( inputElements: List, progress: ProgressIndicator = EmptyProgressIndicator() - ): List { + ): Result { try { val elementCount = inputElements.size() val intermediateResults = ArrayList<(Converter.IntermediateResult)?>(elementCount) - val usageProcessings = HashMap() - 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>() + 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(elementCount) + val results = ArrayList(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(elementCount) + val finalResults = ArrayList(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 + ) + + private fun buildExternalCodeProcessing( + usageProcessings: Map>, + inConversionScope: (PsiElement) -> Boolean + ): ((ProgressIndicator) -> (() -> Unit)?)? { + if (usageProcessings.isEmpty()) return null + + + val map: Map> = 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() + + 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) { + @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 { + 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?) { + } + } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinTranslator.kt index 6d12bcc98c4..f2bf6fa33be 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/JavaToKotlinTranslator.kt @@ -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 "" } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ReferenceSearcher.kt b/j2k/src/org/jetbrains/kotlin/j2k/ReferenceSearcher.kt index 17a24e12814..400d1d3179c 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ReferenceSearcher.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ReferenceSearcher.kt @@ -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 - fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection + fun findLocalUsages(element: PsiElement, scope: PsiElement): Collection fun hasInheritors(`class`: PsiClass): Boolean fun hasOverrides(method: PsiMethod): Boolean + + fun findExternalCodeProcessingUsages(element: PsiElement, searchJava: Boolean, searchKotlin: Boolean): Collection +} + +public fun ReferenceSearcher.findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection + = findLocalUsages(variable, scope).filterIsInstance() + +public fun ReferenceSearcher.findMethodCalls(method: PsiMethod, scope: PsiElement): Collection { + 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() - override fun findMethodCalls(method: PsiMethod, scope: PsiElement) = listOf() + override fun findLocalUsages(element: PsiElement, scope: PsiElement): Collection = emptyList() override fun hasInheritors(`class`: PsiClass) = false override fun hasOverrides(method: PsiMethod) = false + override fun findExternalCodeProcessingUsages(element: PsiElement, searchJava: Boolean, searchKotlin: Boolean): Collection + = throw UnsupportedOperationException() } -public object IdeaReferenceSearcher : ReferenceSearcher { - override fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection { - return ReferencesSearch.search(variable, LocalSearchScope(scope)).findAll().filterIsInstance() - } - - override fun findMethodCalls(method: PsiMethod, scope: PsiElement): Collection { - 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 { + 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() + } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt b/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt index 05d9c8f3550..fd31134d0c6 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt @@ -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()!! diff --git a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/AccessorToPropertyProcessing.kt b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/AccessorToPropertyProcessing.kt index 76f8b7da3c1..dde1798069d 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/AccessorToPropertyProcessing.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/AccessorToPropertyProcessing.kt @@ -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? { + 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()) + } + } + + } } - } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/ElementRenamedCodeProcessor.kt b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/ElementRenamedCodeProcessor.kt new file mode 100644 index 00000000000..1a3927fa929 --- /dev/null +++ b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/ElementRenamedCodeProcessor.kt @@ -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? { + val newReference = reference.handleElementRename(newName).getReference()!! + return listOf(newReference) + } +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/FieldToPropertyProcessing.kt b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/FieldToPropertyProcessing.kt index fa05dbfb6c3..4f968b900c8 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/FieldToPropertyProcessing.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/FieldToPropertyProcessing.kt @@ -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? { + 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 { + 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() } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/MethodIntoObjectProcessing.kt b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/MethodIntoObjectProcessing.kt new file mode 100644 index 00000000000..d124bc48c23 --- /dev/null +++ b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/MethodIntoObjectProcessing.kt @@ -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? { + 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 +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/ToObjectWithOnlyMethodsProcessing.kt b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/ToObjectWithOnlyMethodsProcessing.kt new file mode 100644 index 00000000000..768f5e6c916 --- /dev/null +++ b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/ToObjectWithOnlyMethodsProcessing.kt @@ -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? { + 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 +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/UsageProcessing.kt b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/UsageProcessing.kt index d42c6747a26..a08e907e41d 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/UsageProcessing.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/usageProcessing/UsageProcessing.kt @@ -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? } -class UsageProcessingExpressionConverter(val processings: Map) : SpecialExpressionConverter { +class UsageProcessingExpressionConverter(val processings: Map>) : 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 diff --git a/j2k/testData/fileOrElement/dropAccessors/InCompanionObject.java b/j2k/testData/fileOrElement/dropAccessors/InCompanionObject.java new file mode 100644 index 00000000000..104b65ef89a --- /dev/null +++ b/j2k/testData/fileOrElement/dropAccessors/InCompanionObject.java @@ -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; + } +} diff --git a/j2k/testData/fileOrElement/dropAccessors/InCompanionObject.kt b/j2k/testData/fileOrElement/dropAccessors/InCompanionObject.kt new file mode 100644 index 00000000000..e3b114106b7 --- /dev/null +++ b/j2k/testData/fileOrElement/dropAccessors/InCompanionObject.kt @@ -0,0 +1,10 @@ +public class AAA { + public fun foo() { + x = x + 1 + } + + companion object { + + public var x: Int = 42 + } +} diff --git a/j2k/testData/fileOrElement/dropAccessors/InObject.java b/j2k/testData/fileOrElement/dropAccessors/InObject.java new file mode 100644 index 00000000000..1678bad8de9 --- /dev/null +++ b/j2k/testData/fileOrElement/dropAccessors/InObject.java @@ -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; +} diff --git a/j2k/testData/fileOrElement/dropAccessors/InObject.kt b/j2k/testData/fileOrElement/dropAccessors/InObject.kt new file mode 100644 index 00000000000..6678b7a8b60 --- /dev/null +++ b/j2k/testData/fileOrElement/dropAccessors/InObject.kt @@ -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 +} diff --git a/j2k/testData/multiFile/FieldToProperty/JavaClass.java b/j2k/testData/multiFile/FieldToProperty/JavaClass.java new file mode 100644 index 00000000000..5ad68dbf6a1 --- /dev/null +++ b/j2k/testData/multiFile/FieldToProperty/JavaClass.java @@ -0,0 +1,11 @@ +package test; + +class JavaClass { + public int field = 0; + + protected int myProperty = 0; + + public int getProperty() { + return myProperty; + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/FieldToProperty/JavaClass.kt b/j2k/testData/multiFile/FieldToProperty/JavaClass.kt new file mode 100644 index 00000000000..e2cc5d3e9a6 --- /dev/null +++ b/j2k/testData/multiFile/FieldToProperty/JavaClass.kt @@ -0,0 +1,8 @@ +package test + +open class JavaClass { + public var field: Int = 0 + + public var property: Int = 0 + protected set +} \ No newline at end of file diff --git a/j2k/testData/multiFile/FieldToProperty/external/JavaFile.java b/j2k/testData/multiFile/FieldToProperty/external/JavaFile.java new file mode 100644 index 00000000000..6cd46c4bd9f --- /dev/null +++ b/j2k/testData/multiFile/FieldToProperty/external/JavaFile.java @@ -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; + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/FieldToProperty/external/JavaFile.java.expected b/j2k/testData/multiFile/FieldToProperty/external/JavaFile.java.expected new file mode 100644 index 00000000000..e91fbe56e9d --- /dev/null +++ b/j2k/testData/multiFile/FieldToProperty/external/JavaFile.java.expected @@ -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); + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/FieldToProperty/external/KotlinFile.kt b/j2k/testData/multiFile/FieldToProperty/external/KotlinFile.kt new file mode 100644 index 00000000000..560fb767c87 --- /dev/null +++ b/j2k/testData/multiFile/FieldToProperty/external/KotlinFile.kt @@ -0,0 +1,10 @@ +package test + +class C : JavaClass() { + public fun foo(javaClass: JavaClass) { + javaClass.field++ + myProperty = javaClass.field + field = myProperty + field *= 2 + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/FieldToProperty/external/KotlinFile.kt.expected b/j2k/testData/multiFile/FieldToProperty/external/KotlinFile.kt.expected new file mode 100644 index 00000000000..0618eaae086 --- /dev/null +++ b/j2k/testData/multiFile/FieldToProperty/external/KotlinFile.kt.expected @@ -0,0 +1,10 @@ +package test + +class C : JavaClass() { + public fun foo(javaClass: JavaClass) { + javaClass.field++ + property = javaClass.field + field = property + field *= 2 + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/GetterAndSetterUsages/external/3.kt b/j2k/testData/multiFile/GetterAndSetterUsages/external/3.kt new file mode 100644 index 00000000000..3c32d29e2b9 --- /dev/null +++ b/j2k/testData/multiFile/GetterAndSetterUsages/external/3.kt @@ -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) +} \ No newline at end of file diff --git a/j2k/testData/multiFile/GetterAndSetterUsages/external/3.kt.expected b/j2k/testData/multiFile/GetterAndSetterUsages/external/3.kt.expected new file mode 100644 index 00000000000..968ab5c32cd --- /dev/null +++ b/j2k/testData/multiFile/GetterAndSetterUsages/external/3.kt.expected @@ -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 +} \ No newline at end of file diff --git a/j2k/testData/multiFile/GetterAndSetterUsages/external/4.java b/j2k/testData/multiFile/GetterAndSetterUsages/external/4.java new file mode 100644 index 00000000000..351a599ba83 --- /dev/null +++ b/j2k/testData/multiFile/GetterAndSetterUsages/external/4.java @@ -0,0 +1,3 @@ +void foo(AAA a) { + a.setX(a.getX() + 1) +} diff --git a/j2k/testData/multiFile/GetterAndSetterUsages/external/4.java.expected b/j2k/testData/multiFile/GetterAndSetterUsages/external/4.java.expected new file mode 100644 index 00000000000..351a599ba83 --- /dev/null +++ b/j2k/testData/multiFile/GetterAndSetterUsages/external/4.java.expected @@ -0,0 +1,3 @@ +void foo(AAA a) { + a.setX(a.getX() + 1) +} diff --git a/j2k/testData/multiFile/ToCompanionObject/ClassWithStatics.java b/j2k/testData/multiFile/ToCompanionObject/ClassWithStatics.java new file mode 100644 index 00000000000..2ab98a31eb4 --- /dev/null +++ b/j2k/testData/multiFile/ToCompanionObject/ClassWithStatics.java @@ -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; } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/ToCompanionObject/ClassWithStatics.kt b/j2k/testData/multiFile/ToCompanionObject/ClassWithStatics.kt new file mode 100644 index 00000000000..9aff89443de --- /dev/null +++ b/j2k/testData/multiFile/ToCompanionObject/ClassWithStatics.kt @@ -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 + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/ToCompanionObject/external/JavaFile.java b/j2k/testData/multiFile/ToCompanionObject/external/JavaFile.java new file mode 100644 index 00000000000..98daf29184d --- /dev/null +++ b/j2k/testData/multiFile/ToCompanionObject/external/JavaFile.java @@ -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; + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/ToCompanionObject/external/JavaFile.java.expected b/j2k/testData/multiFile/ToCompanionObject/external/JavaFile.java.expected new file mode 100644 index 00000000000..c720bdcf270 --- /dev/null +++ b/j2k/testData/multiFile/ToCompanionObject/external/JavaFile.java.expected @@ -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; + } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/ToCompanionObject/external/KotlinFile.kt b/j2k/testData/multiFile/ToCompanionObject/external/KotlinFile.kt new file mode 100644 index 00000000000..f69e592144a --- /dev/null +++ b/j2k/testData/multiFile/ToCompanionObject/external/KotlinFile.kt @@ -0,0 +1,5 @@ +package test + +fun foo() { + ClassWithStatics.staticMethod(ClassWithStatics.staticField) +} diff --git a/j2k/testData/multiFile/ToCompanionObject/external/KotlinFile.kt.expected b/j2k/testData/multiFile/ToCompanionObject/external/KotlinFile.kt.expected new file mode 100644 index 00000000000..f69e592144a --- /dev/null +++ b/j2k/testData/multiFile/ToCompanionObject/external/KotlinFile.kt.expected @@ -0,0 +1,5 @@ +package test + +fun foo() { + ClassWithStatics.staticMethod(ClassWithStatics.staticField) +} diff --git a/j2k/testData/multiFile/ToObject/PureUtils.java b/j2k/testData/multiFile/ToObject/PureUtils.java new file mode 100644 index 00000000000..864979a516d --- /dev/null +++ b/j2k/testData/multiFile/ToObject/PureUtils.java @@ -0,0 +1,6 @@ +package test; + +class PureUtils { + public static void foo1(int p) {} + public static int foo2() { return 1; } +} \ No newline at end of file diff --git a/j2k/testData/multiFile/ToObject/PureUtils.kt b/j2k/testData/multiFile/ToObject/PureUtils.kt new file mode 100644 index 00000000000..8cd2567e511 --- /dev/null +++ b/j2k/testData/multiFile/ToObject/PureUtils.kt @@ -0,0 +1,10 @@ +package test + +object PureUtils { + public fun foo1(p: Int) { + } + + public fun foo2(): Int { + return 1 + } +} diff --git a/j2k/testData/multiFile/ToObject/Utils.java b/j2k/testData/multiFile/ToObject/Utils.java new file mode 100644 index 00000000000..0d05404dcfc --- /dev/null +++ b/j2k/testData/multiFile/ToObject/Utils.java @@ -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; +} \ No newline at end of file diff --git a/j2k/testData/multiFile/ToObject/Utils.kt b/j2k/testData/multiFile/ToObject/Utils.kt new file mode 100644 index 00000000000..093770f5316 --- /dev/null +++ b/j2k/testData/multiFile/ToObject/Utils.kt @@ -0,0 +1,12 @@ +package test + +object Utils { + public fun foo1(p: Int) { + } + + public fun foo2(): Int { + return 1 + } + + public val staticField: Int = 1 +} diff --git a/j2k/testData/multiFile/ToObject/external/JavaFile.java b/j2k/testData/multiFile/ToObject/external/JavaFile.java new file mode 100644 index 00000000000..599ed97316f --- /dev/null +++ b/j2k/testData/multiFile/ToObject/external/JavaFile.java @@ -0,0 +1,9 @@ +package test; + +class C { + void foo() { + Utils.foo1(Utils.staticField); + Utils.staticField += Utils.foo2(); + PureUtils.foo1(PureUtils.foo2()) + } +} diff --git a/j2k/testData/multiFile/ToObject/external/JavaFile.java.expected b/j2k/testData/multiFile/ToObject/external/JavaFile.java.expected new file mode 100644 index 00000000000..3c79314c7f2 --- /dev/null +++ b/j2k/testData/multiFile/ToObject/external/JavaFile.java.expected @@ -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()) + } +} diff --git a/j2k/testData/multiFile/ToObject/external/KotlinFile.kt b/j2k/testData/multiFile/ToObject/external/KotlinFile.kt new file mode 100644 index 00000000000..b8a693409c2 --- /dev/null +++ b/j2k/testData/multiFile/ToObject/external/KotlinFile.kt @@ -0,0 +1,6 @@ +package test + +fun foo() { + Utils.foo1(Utils.staticField) + PureUtils.foo1(PureUtils.foo2()) +} diff --git a/j2k/testData/multiFile/ToObject/external/KotlinFile.kt.expected b/j2k/testData/multiFile/ToObject/external/KotlinFile.kt.expected new file mode 100644 index 00000000000..b8a693409c2 --- /dev/null +++ b/j2k/testData/multiFile/ToObject/external/KotlinFile.kt.expected @@ -0,0 +1,6 @@ +package test + +fun foo() { + Utils.foo1(Utils.staticField) + PureUtils.foo1(PureUtils.foo2()) +} diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterMultiFileTest.kt b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterMultiFileTest.kt index 2483d922446..fef421acdc5 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterMultiFileTest.kt +++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterMultiFileTest.kt @@ -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() - for (javaFile: File in javaFiles) { + val filesToConvert = File(dirPath).listFiles { file, name -> name.endsWith(".java") } + val psiFilesToConvert = ArrayList() + 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() + 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 = 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() - 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() + 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) } } diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterSingleFileTest.kt b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterSingleFileTest.kt index f88531a8d79..51b5febb587 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterSingleFileTest.kt +++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterSingleFileTest.kt @@ -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 { diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt index fd2aa244c27..9ad1c855caf 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterTest.kt @@ -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 } diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index e31920fcca7..8c69d5d9804 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -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"); diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterMultiFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterMultiFileTestGenerated.java index 01ae6db2cd4..df7e094b464 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterMultiFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterMultiFileTestGenerated.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); + } } diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index 8523e3ed6f9..8c043657032 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -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");