From 957ffb0313d1a089d58f1c451b8e9e44296d3512 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 15 Jul 2014 20:43:38 +0400 Subject: [PATCH] J2K: adding type arguments where they are needed and removing them where they are redundant --- .../src/org/jetbrains/jet/lang/psi/Call.java | 4 ++ .../plugin/actions/JavaToKotlinAction.java | 6 ++- .../copy/ConvertJavaCopyPastePostProcessor.kt | 7 ++- .../intentions/RemoveExplicitTypeArguments.kt | 9 +--- .../jet/plugin/j2k/J2kPostProcessor.kt | 48 +++++++++++++++++++ .../jetbrains/jet/j2k/AfterConversionPass.kt | 27 ++++------- j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt | 2 + j2k/src/org/jetbrains/jet/j2k/Converter.kt | 36 ++++++++++---- .../jet/j2k/JavaToKotlinTranslator.kt | 2 +- .../jet/j2k/visitors/ExpressionVisitor.kt | 26 ++++++++-- .../jet/j2k/visitors/SpecialMethod.kt | 28 +++++------ .../test/AbstractJavaToKotlinConverterTest.kt | 18 +++---- .../JavaToKotlinConverterTestGenerated.java | 12 +++-- .../javaLangDoubleArray.kt | 2 +- .../ast/arrayInitializerExpression/twoDim.kt | 2 +- ...alizationStatementWithDimensionExplicit.kt | 2 +- .../ast/arrayType/d3StringEmptyArray.kt | 2 +- .../testData/ast/arrayType/newStringArray.kt | 2 +- .../ast/constructors/genericIdentifier.kt | 4 +- j2k/tests/testData/ast/field/specifyType.kt | 6 +-- j2k/tests/testData/ast/function/varVararg.kt | 2 +- j2k/tests/testData/ast/issues/kt-1048.kt | 2 +- j2k/tests/testData/ast/issues/kt-638.kt | 4 +- .../ast/issues/spaceBeforeAssignment.kt | 2 +- .../kotlinApiAccess/GlobalGenericFunction.kt | 2 +- .../collectionsMethods.kt | 4 +- .../ast/rawGenerics/kt-540-rawGenericClass.kt | 4 +- .../ast/rawGenerics/rawGenericMethod.kt | 2 +- .../ast/settings/specifyFieldTypeByDefault.kt | 4 +- .../ast/typeParameters/needTypeArgs.java | 19 ++++++++ .../ast/typeParameters/needTypeArgs.kt | 18 +++++++ 31 files changed, 213 insertions(+), 95 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/j2k/J2kPostProcessor.kt create mode 100644 j2k/tests/testData/ast/typeParameters/needTypeArgs.java create mode 100644 j2k/tests/testData/ast/typeParameters/needTypeArgs.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java index 5baafb5720e..8a25060654e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import kotlin.jvm.KotlinSignature; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; @@ -41,12 +42,15 @@ public interface Call { @Nullable JetValueArgumentList getValueArgumentList(); + @KotlinSignature("fun getValueArguments(): List") @NotNull List getValueArguments(); + @KotlinSignature("fun getFunctionLiteralArguments(): List") @NotNull List getFunctionLiteralArguments(); + @KotlinSignature("fun getTypeArguments(): List") @NotNull List getTypeArguments(); diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java index a8250c61b51..67573acee62 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.j2k.Converter; import org.jetbrains.jet.j2k.ConverterSettings; import org.jetbrains.jet.j2k.FilesConversionScope; +import org.jetbrains.jet.plugin.j2k.J2kPostProcessor; import java.util.List; @@ -52,7 +53,10 @@ public class JavaToKotlinAction extends AnAction { return; } - final Converter converter = Converter.object$.create(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); + final Converter converter = Converter.object$.create(project, + ConverterSettings.defaultSettings, + new FilesConversionScope(selectedJavaFiles), + J2kPostProcessor.instance$); CommandProcessor.getInstance().executeCommand( project, new Runnable() { diff --git a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt index 6cfe4e88350..213f7c2a7ad 100644 --- a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt @@ -32,7 +32,7 @@ import org.jetbrains.jet.plugin.editor.JetEditorOptions import java.awt.datatransfer.Transferable import com.intellij.openapi.util.TextRange import com.intellij.psi.codeStyle.CodeStyleManager -import com.intellij.codeInsight.editorActions.ReferenceTransferableData +import org.jetbrains.jet.plugin.j2k.J2kPostProcessor; public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor() { @@ -85,7 +85,10 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor { - return ArrayList() - } - + private class CallWithoutTypeArgs(call: Call) : DelegatingCall(call) { + override fun getTypeArguments(): List = listOf() override fun getTypeArgumentList() = null - } override fun applyTo(element: JetTypeArgumentList, editor: Editor) { diff --git a/idea/src/org/jetbrains/jet/plugin/j2k/J2kPostProcessor.kt b/idea/src/org/jetbrains/jet/plugin/j2k/J2kPostProcessor.kt new file mode 100644 index 00000000000..2fb3090dd8a --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/j2k/J2kPostProcessor.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2014 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.jet.plugin.j2k + +import org.jetbrains.jet.j2k.PostProcessor +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.plugin.intentions.RemoveExplicitTypeArguments +import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults +import java.util.ArrayList + +public object J2kPostProcessor : PostProcessor { + override fun analyzeFile(file: JetFile): BindingContext { + return file.getAnalysisResults().getBindingContext() + } + + override fun doAdditionalProcessing(file: JetFile) { + val redundantTypeArgs = ArrayList() + file.accept(object : JetTreeVisitorVoid(){ + override fun visitTypeArgumentList(typeArgumentList: JetTypeArgumentList) { + if (RemoveExplicitTypeArguments().isApplicableTo(typeArgumentList)) { + redundantTypeArgs.add(typeArgumentList) + return + } + + super.visitTypeArgumentList(typeArgumentList) + } + }) + + for (typeArgs in redundantTypeArgs) { + typeArgs.delete() + } + } +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/AfterConversionPass.kt b/j2k/src/org/jetbrains/jet/j2k/AfterConversionPass.kt index bba3de3f81a..4cb735cca70 100644 --- a/j2k/src/org/jetbrains/jet/j2k/AfterConversionPass.kt +++ b/j2k/src/org/jetbrains/jet/j2k/AfterConversionPass.kt @@ -17,44 +17,33 @@ package org.jetbrains.jet.j2k import org.jetbrains.jet.lang.psi.JetPsiFactory -import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM -import org.jetbrains.jet.lang.resolve.BindingTraceContext -import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.jet.lang.resolve.name.Name -import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap import com.intellij.openapi.project.Project import org.jetbrains.jet.lang.diagnostics.Diagnostic import org.jetbrains.jet.lang.diagnostics.Errors import org.jetbrains.jet.lang.psi.JetSimpleNameExpression import org.jetbrains.jet.lang.psi.JetUnaryExpression import org.jetbrains.jet.lang.psi.JetProperty +import com.intellij.psi.PsiFile +import org.jetbrains.jet.lang.resolve.BindingContext -class AfterConversionPass(val project: Project) { +class AfterConversionPass(val project: Project, val postProcessor: PostProcessor) { public fun run(kotlinCode: String): String { val kotlinFile = JetPsiFactory(project).createFile(kotlinCode) - val analyzeExhaust = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( - project, - listOf(kotlinFile), - BindingTraceContext(), - { true }, - ModuleDescriptorImpl(Name.special(""), AnalyzerFacadeForJVM.DEFAULT_IMPORTS, JavaToKotlinClassMap.getInstance()), - null, - null - ) + val bindingContext = postProcessor.analyzeFile(kotlinFile) - val problems = analyzeExhaust.getBindingContext().getDiagnostics() - val fixes = problems.map { + val fixes = bindingContext.getDiagnostics().map { val fix = fixForProblem(it) if (fix != null) it.getPsiElement() to fix else null }.filterNotNull() - if (fixes.isEmpty()) return kotlinCode - for ((psiElement, fix) in fixes) { if (psiElement.isValid()) { fix() } } + + postProcessor.doAdditionalProcessing(kotlinFile) + return kotlinFile.getText()!! } diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt index 74512765d6d..902ea2148fa 100644 --- a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt +++ b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt @@ -23,6 +23,7 @@ import java.util.ArrayList import org.jetbrains.jet.j2k.ast.Element import kotlin.platform.platformName import org.jetbrains.jet.j2k.ast.CommentsAndSpacesInheritance +import com.intellij.psi.impl.light.LightElement fun CodeBuilder.append(generators: Collection<() -> T>, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder { if (generators.isNotEmpty()) { @@ -95,6 +96,7 @@ class CodeBuilder(private val topElement: PsiElement?) { val prefixElements = ArrayList(1) val postfixElements = ArrayList(1) for ((prototype, inheritance) in element.prototypes!!) { + if (prototype is LightElement) continue assert(prototype !is PsiComment) assert(prototype !is PsiWhiteSpace) assert(topElement.isAncestor(prototype)) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 0c9a9f186bc..e49ae4a48cc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -25,6 +25,8 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions.* import com.intellij.openapi.project.Project import com.intellij.psi.util.PsiMethodUtil import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.resolve.BindingContext public trait ConversionScope { public fun contains(element: PsiElement): Boolean @@ -34,7 +36,16 @@ public class FilesConversionScope(val files: Collection) : Conversi override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it } } -public class Converter private(val project: Project, val settings: ConverterSettings, val conversionScope: ConversionScope, val state: Converter.State) { +public trait PostProcessor { + public fun analyzeFile(file: JetFile): BindingContext + public fun doAdditionalProcessing(file: JetFile) +} + +public class Converter private(val project: Project, + val settings: ConverterSettings, + val conversionScope: ConversionScope, + private val postProcessor: PostProcessor?, + private val state: Converter.State) { private class State(val methodReturnType: PsiType?, val expressionVisitorFactory: (Converter) -> ExpressionVisitor, val statementVisitorFactory: (Converter) -> StatementVisitor, @@ -55,41 +66,46 @@ public class Converter private(val project: Project, val settings: ConverterSett val annotationConverter = AnnotationConverter(this) class object { - public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope): Converter { + public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope, postProcessor: PostProcessor?): Converter { val state = State(null, { ExpressionVisitor(it) }, { StatementVisitor(it) }, null, null, null) - return Converter(project, settings, conversionScope, state) + return Converter(project, settings, conversionScope, postProcessor, state) } } fun withMethodReturnType(methodReturnType: PsiType?): Converter - = Converter(project, settings, conversionScope, + = Converter(project, settings, conversionScope, postProcessor, State(methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd)) fun withExpressionVisitor(factory: (Converter) -> ExpressionVisitor): Converter - = Converter(project, settings, conversionScope, + = Converter(project, settings, conversionScope, postProcessor, State(state.methodReturnType, factory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd)) fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter - = Converter(project, settings, conversionScope, + = Converter(project, settings, conversionScope, postProcessor, State(state.methodReturnType, state.expressionVisitorFactory, factory, state.specialContext, state.importList, state.importsToAdd)) fun withSpecialContext(context: PsiElement): Converter - = Converter(project, settings, conversionScope, + = Converter(project, settings, conversionScope, postProcessor, State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, context, state.importList, state.importsToAdd)) private fun withImportList(importList: ImportList): Converter - = Converter(project, settings, conversionScope, + = Converter(project, settings, conversionScope, postProcessor, State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, importList, state.importsToAdd)) private fun withImportsToAdd(importsToAdd: MutableCollection): Converter - = Converter(project, settings, conversionScope, + = Converter(project, settings, conversionScope, postProcessor, State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd)) public fun elementToKotlin(element: PsiElement): String { val converted = convertTopElement(element) ?: return "" val builder = CodeBuilder(element) builder.append(converted) - return AfterConversionPass(project).run(builder.result) + if (postProcessor != null) { + return AfterConversionPass(project, postProcessor).run(builder.result) + } + else { + return builder.result + } } private fun convertTopElement(element: PsiElement?): Element? = when (element) { diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index c1b7cb7b2b6..758e254d95d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -87,7 +87,7 @@ public object JavaToKotlinTranslator { fun generateKotlinCode(javaCode: String): String { val file = createFile(javaCode) if (file is PsiJavaFile) { - val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) + val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), null) return prettify(converter.elementToKotlin(file)) } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 9e3b5efea90..bd1a231eab5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -17,7 +17,6 @@ package org.jetbrains.jet.j2k.visitors import com.intellij.psi.* -import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.tree.IElementType import org.jetbrains.jet.j2k.ast.* import org.jetbrains.jet.lang.types.expressions.OperatorConventions @@ -187,7 +186,7 @@ open class ExpressionVisitor(private val converter: Converter) : JavaElementVisi val arguments = expression.getArgumentList().getExpressions() val target = methodExpr.resolve() val isNullable = if (target is PsiMethod) typeConverter.methodNullability(target).isNullable(converter.settings) else false - val typeArguments = typeConverter.convertTypes(expression.getTypeArguments()) + val typeArguments = convertTypeArguments(expression) if (target is KotlinLightMethod) { val origin = target.origin @@ -250,7 +249,7 @@ open class ExpressionVisitor(private val converter: Converter) : JavaElementVisi if (target is PsiMethod) { val specialMethod = SpecialMethod.values().firstOrNull { it.matches(target) } if (specialMethod != null && arguments.size == specialMethod.parameterCount) { - val converted = specialMethod.convertCall(methodExpr.getQualifierExpression(), arguments, converter) + val converted = specialMethod.convertCall(methodExpr.getQualifierExpression(), arguments, typeArguments, converter) if (converted != null) { result = converted return @@ -264,6 +263,27 @@ open class ExpressionVisitor(private val converter: Converter) : JavaElementVisi isNullable) } + private fun convertTypeArguments(call: PsiCallExpression): List { + var typeArgs = call.getTypeArguments().toList() + + // always add explicit type arguments and remove them if they are redundant later + if (typeArgs.size == 0) { + val resolve = call.resolveMethodGenerics() + if (resolve.isValidResult()) { + val method = resolve.getElement() as? PsiMethod + if (method != null) { + val typeParameters = method.getTypeParameters() + if (typeParameters.isNotEmpty()) { + val map = resolve.getSubstitutor().getSubstitutionMap() + typeArgs = typeParameters.map { map[it] ?: return listOf() } + } + } + } + } + + return typeArgs.map { typeConverter.convertType(it).assignNoPrototype() } + } + override fun visitNewExpression(expression: PsiNewExpression) { if (expression.getArrayInitializer() != null) { result = converter.convertExpression(expression.getArrayInitializer()) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/SpecialMethod.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/SpecialMethod.kt index a206d66562e..4db3613c335 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/SpecialMethod.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/SpecialMethod.kt @@ -27,55 +27,53 @@ import com.intellij.psi.PsiSuperExpression import org.jetbrains.jet.j2k.ast.QualifiedExpression import org.jetbrains.jet.j2k.ast.Identifier import org.jetbrains.jet.j2k.ast.assignNoPrototype +import org.jetbrains.jet.j2k.ast.Type enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String, val parameterCount: Int) { OBJECT_EQUALS: SpecialMethod(null, "equals", 1) { override fun matches(method: PsiMethod) = super.matches(method) && method.getParameterList().getParameters().single().getType().getCanonicalText() == JAVA_LANG_OBJECT - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter): Expression? { + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter): Expression? { if (qualifier == null || qualifier is PsiSuperExpression) return null return BinaryExpression(converter.convertExpression(qualifier), converter.convertExpression(arguments.single()), "==") } } OBJECT_GET_CLASS: SpecialMethod("java.lang.Object", "getClass", 0) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter): Expression { + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter): Expression { val identifier = Identifier("javaClass", false).assignNoPrototype() return if (qualifier != null) QualifiedExpression(converter.convertExpression(qualifier), identifier) else identifier } } OBJECTS_EQUALS: SpecialMethod("java.util.Objects", "equals", 2) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter) = BinaryExpression(converter.convertExpression(arguments[0]), converter.convertExpression(arguments[1]), "==") } - //TODO: type arguments maybe required if we are in initializer of variable with no explicit type COLLECTIONS_EMPTY_LIST: SpecialMethod("java.util.Collections", "emptyList", 0) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter) - = MethodCallExpression.build(null, "listOf", listOf(), listOf(), false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter) + = MethodCallExpression.build(null, "listOf", listOf(), typeArgumentsConverted, false) } - //TODO: type arguments maybe required if we are in initializer of variable with no explicit type COLLECTIONS_EMPTY_SET: SpecialMethod("java.util.Collections", "emptySet", 0) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter) - = MethodCallExpression.build(null, "setOf", listOf(), listOf(), false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter) + = MethodCallExpression.build(null, "setOf", listOf(), typeArgumentsConverted, false) } - //TODO: type arguments maybe required if we are in initializer of variable with no explicit type COLLECTIONS_EMPTY_MAP: SpecialMethod("java.util.Collections", "emptyMap", 0) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter) - = MethodCallExpression.build(null, "mapOf", listOf(), listOf(), false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter) + = MethodCallExpression.build(null, "mapOf", listOf(), typeArgumentsConverted, false) } COLLECTIONS_SINGLETON_LIST: SpecialMethod("java.util.Collections", "singletonList", 1) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter) = MethodCallExpression.build(null, "listOf", listOf(converter.convertExpression(arguments.single())), listOf(), false) } COLLECTIONS_SINGLETON: SpecialMethod("java.util.Collections", "singleton", 1) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter) = MethodCallExpression.build(null, "setOf", listOf(converter.convertExpression(arguments.single())), listOf(), false) } @@ -85,5 +83,5 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String return method.getParameterList().getParametersCount() == parameterCount } - abstract fun convertCall(qualifier: PsiExpression?, arguments: Array, converter: Converter): Expression? + abstract fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter): Expression? } \ No newline at end of file diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index 4ae6cbc0edb..08d87dab40e 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -23,9 +23,6 @@ import org.jetbrains.jet.j2k.JavaToKotlinTranslator import org.jetbrains.jet.j2k.ConverterSettings import java.util.regex.Pattern import com.intellij.testFramework.LightPlatformTestCase -import com.intellij.testFramework.LightIdeaTestCase -import com.intellij.openapi.projectRoots.Sdk -import org.jetbrains.jet.plugin.PluginTestCaseBase import com.intellij.psi.codeStyle.CodeStyleManager import org.jetbrains.jet.JetTestUtils import com.intellij.openapi.project.Project @@ -33,8 +30,12 @@ import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.application.ApplicationManager import org.jetbrains.jet.test.util.trimIndent import org.jetbrains.jet.j2k.FilesConversionScope +import org.jetbrains.jet.plugin.j2k.J2kPostProcessor +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor -abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { +abstract class AbstractJavaToKotlinConverterTest() : LightCodeInsightFixtureTestCase() { val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n") override fun setUp() { @@ -122,14 +123,14 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String { val fileWithText = JavaToKotlinTranslator.createFile(project, text) - val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText))) + val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText)), J2kPostProcessor) val element = fileWithText.getFirstChild()!! return converter.elementToKotlin(element) } private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { val file = JavaToKotlinTranslator.createFile(project, text) - val converter = Converter.create(project, settings, FilesConversionScope(listOf(file))) + val converter = Converter.create(project, settings, FilesConversionScope(listOf(file)), J2kPostProcessor) return converter.elementToKotlin(file) } @@ -148,9 +149,8 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { return result.replaceFirst("val o:Any\\? = ", "").replaceFirst("val o:Any = ", "").replaceFirst("val o = ", "").trim() } - override fun getProjectJDK(): Sdk? { - return PluginTestCaseBase.jdkFromIdeaHome() - } + override fun getProjectDescriptor() + = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE private fun String.removeFirstLine(): String { val lastNewLine = indexOf('\n') diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 3ef6819568d..83db77e133a 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -16,17 +16,14 @@ package org.jetbrains.jet.j2k.test; -import junit.framework.Assert; import junit.framework.Test; import junit.framework.TestSuite; - -import java.io.File; -import java.util.regex.Pattern; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; -import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; +import java.io.File; +import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @@ -3128,6 +3125,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/typeParameters/methodDoubleParametrizationWithTwoBounds.java"); } + @TestMetadata("needTypeArgs.java") + public void testNeedTypeArgs() throws Exception { + doTest("j2k/tests/testData/ast/typeParameters/needTypeArgs.java"); + } + @TestMetadata("traitDoubleParametrizationWithTwoBoundsWithExtending.java") public void testTraitDoubleParametrizationWithTwoBoundsWithExtending() throws Exception { doTest("j2k/tests/testData/ast/typeParameters/traitDoubleParametrizationWithTwoBoundsWithExtending.java"); diff --git a/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt b/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt index d2060c45afe..1c4d664e552 100644 --- a/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt +++ b/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt @@ -1 +1 @@ -val a = array(1.0, 2.0, 3.0) \ No newline at end of file +val a = array(1.0, 2.0, 3.0) \ No newline at end of file diff --git a/j2k/tests/testData/ast/arrayInitializerExpression/twoDim.kt b/j2k/tests/testData/ast/arrayInitializerExpression/twoDim.kt index 13f4c0fc540..254d325b9aa 100644 --- a/j2k/tests/testData/ast/arrayInitializerExpression/twoDim.kt +++ b/j2k/tests/testData/ast/arrayInitializerExpression/twoDim.kt @@ -1 +1 @@ -val a = array(intArray(1, 2, 3), intArray(4, 5, 6), intArray(7, 8, 9)) \ No newline at end of file +val a = array(intArray(1, 2, 3), intArray(4, 5, 6), intArray(7, 8, 9)) \ No newline at end of file diff --git a/j2k/tests/testData/ast/arrayType/arrayInitializationStatementWithDimensionExplicit.kt b/j2k/tests/testData/ast/arrayType/arrayInitializationStatementWithDimensionExplicit.kt index 53aa946565f..8bfd2228d30 100644 --- a/j2k/tests/testData/ast/arrayType/arrayInitializationStatementWithDimensionExplicit.kt +++ b/j2k/tests/testData/ast/arrayType/arrayInitializationStatementWithDimensionExplicit.kt @@ -1 +1 @@ -val d2 = Array(5, { IntArray(5) }) \ No newline at end of file +val d2 = Array(5, { IntArray(5) }) \ No newline at end of file diff --git a/j2k/tests/testData/ast/arrayType/d3StringEmptyArray.kt b/j2k/tests/testData/ast/arrayType/d3StringEmptyArray.kt index b0691fa416a..7f2164c3d1f 100644 --- a/j2k/tests/testData/ast/arrayType/d3StringEmptyArray.kt +++ b/j2k/tests/testData/ast/arrayType/d3StringEmptyArray.kt @@ -1 +1 @@ -val sss = Array>>(5, { Array>(5, { arrayOfNulls(5) }) }) \ No newline at end of file +val sss = Array(5, { Array>(5, { arrayOfNulls(5) }) }) \ No newline at end of file diff --git a/j2k/tests/testData/ast/arrayType/newStringArray.kt b/j2k/tests/testData/ast/arrayType/newStringArray.kt index c1803c10649..35e46b3293f 100644 --- a/j2k/tests/testData/ast/arrayType/newStringArray.kt +++ b/j2k/tests/testData/ast/arrayType/newStringArray.kt @@ -1 +1 @@ -val a = array("abc") \ No newline at end of file +val a = array("abc") \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/genericIdentifier.kt b/j2k/tests/testData/ast/constructors/genericIdentifier.kt index efc865c8815..6213f71e780 100644 --- a/j2k/tests/testData/ast/constructors/genericIdentifier.kt +++ b/j2k/tests/testData/ast/constructors/genericIdentifier.kt @@ -25,9 +25,9 @@ public class Identifier(private val myName: T, private val myHasDollar: Boole public class User { class object { public fun main() { - val i1 = Identifier("name", false, true) + val i1 = Identifier("name", false, true) val i2 = Identifier("name", false) - val i3 = Identifier("name") + val i3 = Identifier("name") } } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/specifyType.kt b/j2k/tests/testData/ast/field/specifyType.kt index d9610a1301b..553e49ce653 100644 --- a/j2k/tests/testData/ast/field/specifyType.kt +++ b/j2k/tests/testData/ast/field/specifyType.kt @@ -3,12 +3,12 @@ import kotlin.List class A { private val field1 = ArrayList() - val field2: List = ArrayList() + val field2: List = ArrayList() public val field3: Int = 0 protected val field4: Int = 0 - private var field5: List = ArrayList() - var field6: List = ArrayList() + private var field5: List = ArrayList() + var field6: List = ArrayList() private var field7 = 0 var field8 = 0 diff --git a/j2k/tests/testData/ast/function/varVararg.kt b/j2k/tests/testData/ast/function/varVararg.kt index 59f72dae8e9..af85a42a501 100644 --- a/j2k/tests/testData/ast/function/varVararg.kt +++ b/j2k/tests/testData/ast/function/varVararg.kt @@ -3,6 +3,6 @@ package demo class Test { fun test(vararg args: Any) { var args = args - args = array(1, 2, 3) + args = array(1, 2, 3) } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-1048.kt b/j2k/tests/testData/ast/issues/kt-1048.kt index 64ddaf7071d..232c02f5b8f 100644 --- a/j2k/tests/testData/ast/issues/kt-1048.kt +++ b/j2k/tests/testData/ast/issues/kt-1048.kt @@ -10,6 +10,6 @@ public class Java { fun test2() { val m = HashMap() val g = G("") - val g2 = G("") + val g2 = G("") } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-638.kt b/j2k/tests/testData/ast/issues/kt-638.kt index d89c6c6a2a1..7d46a242a2f 100644 --- a/j2k/tests/testData/ast/issues/kt-638.kt +++ b/j2k/tests/testData/ast/issues/kt-638.kt @@ -25,9 +25,9 @@ public class Identifier(private val myName: T, private val myHasDollar: Boole public class User { class object { public fun main(args: Array) { - val i1 = Identifier("name", false, true) + val i1 = Identifier("name", false, true) val i2 = Identifier("name", false) - val i3 = Identifier("name") + val i3 = Identifier("name") } } } diff --git a/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt b/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt index 292890fd19e..37b3b9f9138 100644 --- a/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt +++ b/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt @@ -2,5 +2,5 @@ import java.util.* import kotlin.List class A { - var list: List = ArrayList() + var list: List = ArrayList() } \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinApiAccess/GlobalGenericFunction.kt b/j2k/tests/testData/ast/kotlinApiAccess/GlobalGenericFunction.kt index 9830346c6e2..25445a074d4 100644 --- a/j2k/tests/testData/ast/kotlinApiAccess/GlobalGenericFunction.kt +++ b/j2k/tests/testData/ast/kotlinApiAccess/GlobalGenericFunction.kt @@ -2,6 +2,6 @@ import kotlinApi.* class C { fun foo() { - val v = globalGenericFunction(1) + val v = globalGenericFunction(1) } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/methodCallExpression/collectionsMethods.kt b/j2k/tests/testData/ast/methodCallExpression/collectionsMethods.kt index e987bf3e9e7..12b65cfaa5e 100644 --- a/j2k/tests/testData/ast/methodCallExpression/collectionsMethods.kt +++ b/j2k/tests/testData/ast/methodCallExpression/collectionsMethods.kt @@ -3,9 +3,9 @@ import kotlin.Map class A { fun foo(): Map { - val list1 = listOf() + val list1 = listOf() val list2 = listOf(1) - val set1 = setOf() + val set1 = setOf() val set2 = setOf("a") return mapOf() } diff --git a/j2k/tests/testData/ast/rawGenerics/kt-540-rawGenericClass.kt b/j2k/tests/testData/ast/rawGenerics/kt-540-rawGenericClass.kt index 119a2792c5c..5d797cb6420 100644 --- a/j2k/tests/testData/ast/rawGenerics/kt-540-rawGenericClass.kt +++ b/j2k/tests/testData/ast/rawGenerics/kt-540-rawGenericClass.kt @@ -9,7 +9,7 @@ class Collection(e: E) { class Test { fun main() { val raw1 = Collection(1) - val raw2 = Collection(1) - val raw3 = Collection("1") + val raw2 = Collection(1) + val raw3 = Collection("1") } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/rawGenerics/rawGenericMethod.kt b/j2k/tests/testData/ast/rawGenerics/rawGenericMethod.kt index c20349f17d4..959f5048737 100644 --- a/j2k/tests/testData/ast/rawGenerics/rawGenericMethod.kt +++ b/j2k/tests/testData/ast/rawGenerics/rawGenericMethod.kt @@ -10,6 +10,6 @@ class U { val t = TestT() t.getT() t.getT() - t.getT() + t.getT() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt index 7ed0f8f39f2..c133fbc7b65 100644 --- a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt +++ b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt @@ -3,8 +3,8 @@ import java.util.* import kotlin.List class A { - private val field1: List = ArrayList() - val field2: List = ArrayList() + private val field1: List = ArrayList() + val field2: List = ArrayList() public val field3: Int = 0 protected val field4: Int = 0 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/typeParameters/needTypeArgs.java b/j2k/tests/testData/ast/typeParameters/needTypeArgs.java new file mode 100644 index 00000000000..bea27442adc --- /dev/null +++ b/j2k/tests/testData/ast/typeParameters/needTypeArgs.java @@ -0,0 +1,19 @@ +import java.util.HashMap; +import java.util.Map; + +class A { + void foo() { + Map map1 = getMap1(); + Map map2 = getMap2("a", 1); + } + + Map getMap1() { + return new HashMap<>(); + } + + Map getMap2(K k, V v) { + HashMap map = new HashMap<>(); + map.put(k, v); + return map; + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/typeParameters/needTypeArgs.kt b/j2k/tests/testData/ast/typeParameters/needTypeArgs.kt new file mode 100644 index 00000000000..ed704f37ec4 --- /dev/null +++ b/j2k/tests/testData/ast/typeParameters/needTypeArgs.kt @@ -0,0 +1,18 @@ +import java.util.HashMap + +class A { + fun foo() { + val map1 = getMap1() + val map2 = getMap2("a", 1) + } + + fun getMap1(): Map { + return HashMap() + } + + fun getMap2(k: K, v: V): Map { + val map = HashMap() + map.put(k, v) + return map + } +} \ No newline at end of file