J2K: adding type arguments where they are needed and removing them where they are redundant

This commit is contained in:
Valentin Kipyatkov
2014-07-15 20:43:38 +04:00
parent f836278acc
commit 957ffb0313
31 changed files with 213 additions and 95 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import kotlin.jvm.KotlinSignature;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
@@ -41,12 +42,15 @@ public interface Call {
@Nullable @Nullable
JetValueArgumentList getValueArgumentList(); JetValueArgumentList getValueArgumentList();
@KotlinSignature("fun getValueArguments(): List<out ValueArgument?>")
@NotNull @NotNull
List<? extends ValueArgument> getValueArguments(); List<? extends ValueArgument> getValueArguments();
@KotlinSignature("fun getFunctionLiteralArguments(): List<JetExpression>")
@NotNull @NotNull
List<JetExpression> getFunctionLiteralArguments(); List<JetExpression> getFunctionLiteralArguments();
@KotlinSignature("fun getTypeArguments(): List<JetTypeProjection>")
@NotNull @NotNull
List<JetTypeProjection> getTypeArguments(); List<JetTypeProjection> getTypeArguments();
@@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.j2k.Converter; import org.jetbrains.jet.j2k.Converter;
import org.jetbrains.jet.j2k.ConverterSettings; import org.jetbrains.jet.j2k.ConverterSettings;
import org.jetbrains.jet.j2k.FilesConversionScope; import org.jetbrains.jet.j2k.FilesConversionScope;
import org.jetbrains.jet.plugin.j2k.J2kPostProcessor;
import java.util.List; import java.util.List;
@@ -52,7 +53,10 @@ public class JavaToKotlinAction extends AnAction {
return; 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( CommandProcessor.getInstance().executeCommand(
project, project,
new Runnable() { new Runnable() {
@@ -32,7 +32,7 @@ import org.jetbrains.jet.plugin.editor.JetEditorOptions
import java.awt.datatransfer.Transferable import java.awt.datatransfer.Transferable
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.codeInsight.editorActions.ReferenceTransferableData import org.jetbrains.jet.plugin.j2k.J2kPostProcessor;
public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTransferableData>() { public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTransferableData>() {
@@ -85,7 +85,10 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
} }
private fun convertCopiedCodeToKotlin(code: CopiedCode, file: PsiJavaFile): String { private fun convertCopiedCodeToKotlin(code: CopiedCode, file: PsiJavaFile): String {
val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) val converter = Converter.create(file.getProject(),
ConverterSettings.defaultSettings,
FilesConversionScope(listOf(file)),
J2kPostProcessor)
val startOffsets = code.getStartOffsets() val startOffsets = code.getStartOffsets()
val endOffsets = code.getEndOffsets() val endOffsets = code.getEndOffsets()
assert(startOffsets.size == endOffsets.size) { "Must have the same size" } assert(startOffsets.size == endOffsets.size) { "Must have the same size" }
@@ -84,14 +84,9 @@ public class RemoveExplicitTypeArguments : JetSelfTargetingIntention<JetTypeArgu
return args == newArgs return args == newArgs
} }
class CallWithoutTypeArgs(call: Call) : DelegatingCall(call) { private class CallWithoutTypeArgs(call: Call) : DelegatingCall(call) {
override fun getTypeArguments(): List<JetTypeProjection> = listOf()
override fun getTypeArguments(): MutableList<JetTypeProjection> {
return ArrayList<JetTypeProjection>()
}
override fun getTypeArgumentList() = null override fun getTypeArgumentList() = null
} }
override fun applyTo(element: JetTypeArgumentList, editor: Editor) { override fun applyTo(element: JetTypeArgumentList, editor: Editor) {
@@ -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<JetTypeArgumentList>()
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()
}
}
}
@@ -17,44 +17,33 @@
package org.jetbrains.jet.j2k package org.jetbrains.jet.j2k
import org.jetbrains.jet.lang.psi.JetPsiFactory 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 com.intellij.openapi.project.Project
import org.jetbrains.jet.lang.diagnostics.Diagnostic import org.jetbrains.jet.lang.diagnostics.Diagnostic
import org.jetbrains.jet.lang.diagnostics.Errors import org.jetbrains.jet.lang.diagnostics.Errors
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import org.jetbrains.jet.lang.psi.JetUnaryExpression import org.jetbrains.jet.lang.psi.JetUnaryExpression
import org.jetbrains.jet.lang.psi.JetProperty 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 { public fun run(kotlinCode: String): String {
val kotlinFile = JetPsiFactory(project).createFile(kotlinCode) val kotlinFile = JetPsiFactory(project).createFile(kotlinCode)
val analyzeExhaust = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( val bindingContext = postProcessor.analyzeFile(kotlinFile)
project,
listOf(kotlinFile),
BindingTraceContext(),
{ true },
ModuleDescriptorImpl(Name.special("<module>"), AnalyzerFacadeForJVM.DEFAULT_IMPORTS, JavaToKotlinClassMap.getInstance()),
null,
null
)
val problems = analyzeExhaust.getBindingContext().getDiagnostics() val fixes = bindingContext.getDiagnostics().map {
val fixes = problems.map {
val fix = fixForProblem(it) val fix = fixForProblem(it)
if (fix != null) it.getPsiElement() to fix else null if (fix != null) it.getPsiElement() to fix else null
}.filterNotNull() }.filterNotNull()
if (fixes.isEmpty()) return kotlinCode
for ((psiElement, fix) in fixes) { for ((psiElement, fix) in fixes) {
if (psiElement.isValid()) { if (psiElement.isValid()) {
fix() fix()
} }
} }
postProcessor.doAdditionalProcessing(kotlinFile)
return kotlinFile.getText()!! return kotlinFile.getText()!!
} }
@@ -23,6 +23,7 @@ import java.util.ArrayList
import org.jetbrains.jet.j2k.ast.Element import org.jetbrains.jet.j2k.ast.Element
import kotlin.platform.platformName import kotlin.platform.platformName
import org.jetbrains.jet.j2k.ast.CommentsAndSpacesInheritance import org.jetbrains.jet.j2k.ast.CommentsAndSpacesInheritance
import com.intellij.psi.impl.light.LightElement
fun<T> CodeBuilder.append(generators: Collection<() -> T>, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder { fun<T> CodeBuilder.append(generators: Collection<() -> T>, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder {
if (generators.isNotEmpty()) { if (generators.isNotEmpty()) {
@@ -95,6 +96,7 @@ class CodeBuilder(private val topElement: PsiElement?) {
val prefixElements = ArrayList<PsiElement>(1) val prefixElements = ArrayList<PsiElement>(1)
val postfixElements = ArrayList<PsiElement>(1) val postfixElements = ArrayList<PsiElement>(1)
for ((prototype, inheritance) in element.prototypes!!) { for ((prototype, inheritance) in element.prototypes!!) {
if (prototype is LightElement) continue
assert(prototype !is PsiComment) assert(prototype !is PsiComment)
assert(prototype !is PsiWhiteSpace) assert(prototype !is PsiWhiteSpace)
assert(topElement.isAncestor(prototype)) assert(topElement.isAncestor(prototype))
+26 -10
View File
@@ -25,6 +25,8 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions.*
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.util.PsiMethodUtil import com.intellij.psi.util.PsiMethodUtil
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.resolve.BindingContext
public trait ConversionScope { public trait ConversionScope {
public fun contains(element: PsiElement): Boolean public fun contains(element: PsiElement): Boolean
@@ -34,7 +36,16 @@ public class FilesConversionScope(val files: Collection<PsiJavaFile>) : Conversi
override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it } 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?, private class State(val methodReturnType: PsiType?,
val expressionVisitorFactory: (Converter) -> ExpressionVisitor, val expressionVisitorFactory: (Converter) -> ExpressionVisitor,
val statementVisitorFactory: (Converter) -> StatementVisitor, val statementVisitorFactory: (Converter) -> StatementVisitor,
@@ -55,41 +66,46 @@ public class Converter private(val project: Project, val settings: ConverterSett
val annotationConverter = AnnotationConverter(this) val annotationConverter = AnnotationConverter(this)
class object { 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) 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 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)) State(methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd))
fun withExpressionVisitor(factory: (Converter) -> ExpressionVisitor): Converter 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)) State(state.methodReturnType, factory, state.statementVisitorFactory, state.specialContext, state.importList, state.importsToAdd))
fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter 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)) State(state.methodReturnType, state.expressionVisitorFactory, factory, state.specialContext, state.importList, state.importsToAdd))
fun withSpecialContext(context: PsiElement): Converter 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)) State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, context, state.importList, state.importsToAdd))
private fun withImportList(importList: ImportList): Converter 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)) State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, importList, state.importsToAdd))
private fun withImportsToAdd(importsToAdd: MutableCollection<String>): Converter private fun withImportsToAdd(importsToAdd: MutableCollection<String>): Converter
= Converter(project, settings, conversionScope, = Converter(project, settings, conversionScope, postProcessor,
State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd)) State(state.methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory, state.specialContext, state.importList, importsToAdd))
public fun elementToKotlin(element: PsiElement): String { public fun elementToKotlin(element: PsiElement): String {
val converted = convertTopElement(element) ?: return "" val converted = convertTopElement(element) ?: return ""
val builder = CodeBuilder(element) val builder = CodeBuilder(element)
builder.append(converted) 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) { private fun convertTopElement(element: PsiElement?): Element? = when (element) {
@@ -87,7 +87,7 @@ public object JavaToKotlinTranslator {
fun generateKotlinCode(javaCode: String): String { fun generateKotlinCode(javaCode: String): String {
val file = createFile(javaCode) val file = createFile(javaCode)
if (file is PsiJavaFile) { 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 prettify(converter.elementToKotlin(file))
} }
return "" return ""
@@ -17,7 +17,6 @@
package org.jetbrains.jet.j2k.visitors package org.jetbrains.jet.j2k.visitors
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import org.jetbrains.jet.j2k.ast.* import org.jetbrains.jet.j2k.ast.*
import org.jetbrains.jet.lang.types.expressions.OperatorConventions 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 arguments = expression.getArgumentList().getExpressions()
val target = methodExpr.resolve() val target = methodExpr.resolve()
val isNullable = if (target is PsiMethod) typeConverter.methodNullability(target).isNullable(converter.settings) else false 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) { if (target is KotlinLightMethod) {
val origin = target.origin val origin = target.origin
@@ -250,7 +249,7 @@ open class ExpressionVisitor(private val converter: Converter) : JavaElementVisi
if (target is PsiMethod) { if (target is PsiMethod) {
val specialMethod = SpecialMethod.values().firstOrNull { it.matches(target) } val specialMethod = SpecialMethod.values().firstOrNull { it.matches(target) }
if (specialMethod != null && arguments.size == specialMethod.parameterCount) { 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) { if (converted != null) {
result = converted result = converted
return return
@@ -264,6 +263,27 @@ open class ExpressionVisitor(private val converter: Converter) : JavaElementVisi
isNullable) isNullable)
} }
private fun convertTypeArguments(call: PsiCallExpression): List<Type> {
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) { override fun visitNewExpression(expression: PsiNewExpression) {
if (expression.getArrayInitializer() != null) { if (expression.getArrayInitializer() != null) {
result = converter.convertExpression(expression.getArrayInitializer()) result = converter.convertExpression(expression.getArrayInitializer())
@@ -27,55 +27,53 @@ import com.intellij.psi.PsiSuperExpression
import org.jetbrains.jet.j2k.ast.QualifiedExpression import org.jetbrains.jet.j2k.ast.QualifiedExpression
import org.jetbrains.jet.j2k.ast.Identifier import org.jetbrains.jet.j2k.ast.Identifier
import org.jetbrains.jet.j2k.ast.assignNoPrototype 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) { enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String, val parameterCount: Int) {
OBJECT_EQUALS: SpecialMethod(null, "equals", 1) { OBJECT_EQUALS: SpecialMethod(null, "equals", 1) {
override fun matches(method: PsiMethod) override fun matches(method: PsiMethod)
= super.matches(method) && method.getParameterList().getParameters().single().getType().getCanonicalText() == JAVA_LANG_OBJECT = super.matches(method) && method.getParameterList().getParameters().single().getType().getCanonicalText() == JAVA_LANG_OBJECT
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter): Expression? { override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter): Expression? {
if (qualifier == null || qualifier is PsiSuperExpression) return null if (qualifier == null || qualifier is PsiSuperExpression) return null
return BinaryExpression(converter.convertExpression(qualifier), converter.convertExpression(arguments.single()), "==") return BinaryExpression(converter.convertExpression(qualifier), converter.convertExpression(arguments.single()), "==")
} }
} }
OBJECT_GET_CLASS: SpecialMethod("java.lang.Object", "getClass", 0) { OBJECT_GET_CLASS: SpecialMethod("java.lang.Object", "getClass", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter): Expression { override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter): Expression {
val identifier = Identifier("javaClass", false).assignNoPrototype() val identifier = Identifier("javaClass", false).assignNoPrototype()
return if (qualifier != null) QualifiedExpression(converter.convertExpression(qualifier), identifier) else identifier return if (qualifier != null) QualifiedExpression(converter.convertExpression(qualifier), identifier) else identifier
} }
} }
OBJECTS_EQUALS: SpecialMethod("java.util.Objects", "equals", 2) { OBJECTS_EQUALS: SpecialMethod("java.util.Objects", "equals", 2) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
= BinaryExpression(converter.convertExpression(arguments[0]), converter.convertExpression(arguments[1]), "==") = 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) { COLLECTIONS_EMPTY_LIST: SpecialMethod("java.util.Collections", "emptyList", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
= MethodCallExpression.build(null, "listOf", listOf(), listOf(), false) = 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) { COLLECTIONS_EMPTY_SET: SpecialMethod("java.util.Collections", "emptySet", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
= MethodCallExpression.build(null, "setOf", listOf(), listOf(), false) = 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) { COLLECTIONS_EMPTY_MAP: SpecialMethod("java.util.Collections", "emptyMap", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
= MethodCallExpression.build(null, "mapOf", listOf(), listOf(), false) = MethodCallExpression.build(null, "mapOf", listOf(), typeArgumentsConverted, false)
} }
COLLECTIONS_SINGLETON_LIST: SpecialMethod("java.util.Collections", "singletonList", 1) { COLLECTIONS_SINGLETON_LIST: SpecialMethod("java.util.Collections", "singletonList", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
= MethodCallExpression.build(null, "listOf", listOf(converter.convertExpression(arguments.single())), listOf(), false) = MethodCallExpression.build(null, "listOf", listOf(converter.convertExpression(arguments.single())), listOf(), false)
} }
COLLECTIONS_SINGLETON: SpecialMethod("java.util.Collections", "singleton", 1) { COLLECTIONS_SINGLETON: SpecialMethod("java.util.Collections", "singleton", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
= MethodCallExpression.build(null, "setOf", listOf(converter.convertExpression(arguments.single())), listOf(), false) = 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 return method.getParameterList().getParametersCount() == parameterCount
} }
abstract fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, converter: Converter): Expression? abstract fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter): Expression?
} }
@@ -23,9 +23,6 @@ import org.jetbrains.jet.j2k.JavaToKotlinTranslator
import org.jetbrains.jet.j2k.ConverterSettings import org.jetbrains.jet.j2k.ConverterSettings
import java.util.regex.Pattern import java.util.regex.Pattern
import com.intellij.testFramework.LightPlatformTestCase 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 com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.jet.JetTestUtils import org.jetbrains.jet.JetTestUtils
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
@@ -33,8 +30,12 @@ import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.jet.test.util.trimIndent import org.jetbrains.jet.test.util.trimIndent
import org.jetbrains.jet.j2k.FilesConversionScope 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") val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n")
override fun setUp() { override fun setUp() {
@@ -122,14 +123,14 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() {
private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String { private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String {
val fileWithText = JavaToKotlinTranslator.createFile(project, text) 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()!! val element = fileWithText.getFirstChild()!!
return converter.elementToKotlin(element) return converter.elementToKotlin(element)
} }
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
val file = JavaToKotlinTranslator.createFile(project, text) 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) 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() return result.replaceFirst("val o:Any\\? = ", "").replaceFirst("val o:Any = ", "").replaceFirst("val o = ", "").trim()
} }
override fun getProjectJDK(): Sdk? { override fun getProjectDescriptor()
return PluginTestCaseBase.jdkFromIdeaHome() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
}
private fun String.removeFirstLine(): String { private fun String.removeFirstLine(): String {
val lastNewLine = indexOf('\n') val lastNewLine = indexOf('\n')
@@ -16,17 +16,14 @@
package org.jetbrains.jet.j2k.test; package org.jetbrains.jet.j2k.test;
import junit.framework.Assert;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata; 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 */ /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -3128,6 +3125,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
doTest("j2k/tests/testData/ast/typeParameters/methodDoubleParametrizationWithTwoBounds.java"); 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") @TestMetadata("traitDoubleParametrizationWithTwoBoundsWithExtending.java")
public void testTraitDoubleParametrizationWithTwoBoundsWithExtending() throws Exception { public void testTraitDoubleParametrizationWithTwoBoundsWithExtending() throws Exception {
doTest("j2k/tests/testData/ast/typeParameters/traitDoubleParametrizationWithTwoBoundsWithExtending.java"); doTest("j2k/tests/testData/ast/typeParameters/traitDoubleParametrizationWithTwoBoundsWithExtending.java");
@@ -1 +1 @@
val a = array<Double>(1.0, 2.0, 3.0) val a = array(1.0, 2.0, 3.0)
@@ -1 +1 @@
val a = array<IntArray>(intArray(1, 2, 3), intArray(4, 5, 6), intArray(7, 8, 9)) val a = array(intArray(1, 2, 3), intArray(4, 5, 6), intArray(7, 8, 9))
@@ -1 +1 @@
val d2 = Array<IntArray>(5, { IntArray(5) }) val d2 = Array(5, { IntArray(5) })
@@ -1 +1 @@
val sss = Array<Array<Array<String>>>(5, { Array<Array<String>>(5, { arrayOfNulls<String>(5) }) }) val sss = Array(5, { Array<Array<String>>(5, { arrayOfNulls<String>(5) }) })
@@ -1 +1 @@
val a = array<String>("abc") val a = array("abc")
@@ -25,9 +25,9 @@ public class Identifier<T>(private val myName: T, private val myHasDollar: Boole
public class User { public class User {
class object { class object {
public fun main() { public fun main() {
val i1 = Identifier<String>("name", false, true) val i1 = Identifier("name", false, true)
val i2 = Identifier<String>("name", false) val i2 = Identifier<String>("name", false)
val i3 = Identifier<String>("name") val i3 = Identifier("name")
} }
} }
} }
+3 -3
View File
@@ -3,12 +3,12 @@ import kotlin.List
class A { class A {
private val field1 = ArrayList<String>() private val field1 = ArrayList<String>()
val field2: List<String> = ArrayList<String>() val field2: List<String> = ArrayList()
public val field3: Int = 0 public val field3: Int = 0
protected val field4: Int = 0 protected val field4: Int = 0
private var field5: List<String> = ArrayList<String>() private var field5: List<String> = ArrayList()
var field6: List<String> = ArrayList<String>() var field6: List<String> = ArrayList()
private var field7 = 0 private var field7 = 0
var field8 = 0 var field8 = 0
+1 -1
View File
@@ -3,6 +3,6 @@ package demo
class Test { class Test {
fun test(vararg args: Any) { fun test(vararg args: Any) {
var args = args var args = args
args = array<Int>(1, 2, 3) args = array(1, 2, 3)
} }
} }
+1 -1
View File
@@ -10,6 +10,6 @@ public class Java {
fun test2() { fun test2() {
val m = HashMap() val m = HashMap()
val g = G("") val g = G("")
val g2 = G<String>("") val g2 = G("")
} }
} }
+2 -2
View File
@@ -25,9 +25,9 @@ public class Identifier<T>(private val myName: T, private val myHasDollar: Boole
public class User { public class User {
class object { class object {
public fun main(args: Array<String>) { public fun main(args: Array<String>) {
val i1 = Identifier<String>("name", false, true) val i1 = Identifier("name", false, true)
val i2 = Identifier<String>("name", false) val i2 = Identifier<String>("name", false)
val i3 = Identifier<String>("name") val i3 = Identifier("name")
} }
} }
} }
@@ -2,5 +2,5 @@ import java.util.*
import kotlin.List import kotlin.List
class A { class A {
var list: List<String> = ArrayList<String>() var list: List<String> = ArrayList()
} }
@@ -2,6 +2,6 @@ import kotlinApi.*
class C { class C {
fun foo() { fun foo() {
val v = globalGenericFunction<Int>(1) val v = globalGenericFunction(1)
} }
} }
@@ -3,9 +3,9 @@ import kotlin.Map
class A { class A {
fun foo(): Map<String, String> { fun foo(): Map<String, String> {
val list1 = listOf() val list1 = listOf<String>()
val list2 = listOf(1) val list2 = listOf(1)
val set1 = setOf() val set1 = setOf<String>()
val set2 = setOf("a") val set2 = setOf("a")
return mapOf() return mapOf()
} }
@@ -9,7 +9,7 @@ class Collection<E>(e: E) {
class Test { class Test {
fun main() { fun main() {
val raw1 = Collection(1) val raw1 = Collection(1)
val raw2 = Collection<Int>(1) val raw2 = Collection(1)
val raw3 = Collection<String>("1") val raw3 = Collection("1")
} }
} }
@@ -10,6 +10,6 @@ class U {
val t = TestT() val t = TestT()
t.getT<String>() t.getT<String>()
t.getT<Int>() t.getT<Int>()
t.getT() t.getT<Any>()
} }
} }
@@ -3,8 +3,8 @@ import java.util.*
import kotlin.List import kotlin.List
class A { class A {
private val field1: List<String> = ArrayList<String>() private val field1: List<String> = ArrayList()
val field2: List<String> = ArrayList<String>() val field2: List<String> = ArrayList()
public val field3: Int = 0 public val field3: Int = 0
protected val field4: Int = 0 protected val field4: Int = 0
} }
@@ -0,0 +1,19 @@
import java.util.HashMap;
import java.util.Map;
class A {
void foo() {
Map<String, Integer> map1 = getMap1();
Map<String, Integer> map2 = getMap2("a", 1);
}
<K, V> Map<K, V> getMap1() {
return new HashMap<>();
}
<K, V> Map<K, V> getMap2(K k, V v) {
HashMap<K, V> map = new HashMap<>();
map.put(k, v);
return map;
}
}
@@ -0,0 +1,18 @@
import java.util.HashMap
class A {
fun foo() {
val map1 = getMap1<String, Int>()
val map2 = getMap2("a", 1)
}
fun <K, V> getMap1(): Map<K, V> {
return HashMap()
}
fun <K, V> getMap2(k: K, v: V): Map<K, V> {
val map = HashMap<K, V>()
map.put(k, v)
return map
}
}