Converter:

Replace hack used to configure Converter by ConverterSettings class
Minor: remove redundant open modifiers, add override annotations
This commit is contained in:
Pavel Talanov
2013-11-05 18:07:47 +04:00
committed by Pavel V. Talanov
parent 3edefcf598
commit cba8d3b6db
11 changed files with 89 additions and 72 deletions
@@ -27,6 +27,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.jet.j2k.Converter; import org.jetbrains.jet.j2k.Converter;
import org.jetbrains.jet.j2k.J2kPackage;
import java.util.List; import java.util.List;
@@ -39,7 +40,7 @@ public class JavaToKotlinAction extends AnAction {
assert virtualFiles != null; assert virtualFiles != null;
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
assert project != null; assert project != null;
final Converter converter = new Converter(project); final Converter converter = new Converter(project, J2kPackage.getPluginSettings());
int result = Messages.showYesNoCancelDialog(project, int result = Messages.showYesNoCancelDialog(project,
"Would you like to backup Java files?", "Would you like to backup Java files?",
"Backup", "Backup",
@@ -28,6 +28,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*; import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.j2k.Converter; import org.jetbrains.jet.j2k.Converter;
import org.jetbrains.jet.j2k.J2kPackage;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.editor.JetEditorOptions; import org.jetbrains.jet.plugin.editor.JetEditorOptions;
@@ -116,7 +117,7 @@ public class JavaCopyPastePostProcessor implements CopyPastePostProcessor<TextBl
Project project = file.getProject(); Project project = file.getProject();
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (PsiElement e : buffer) { for (PsiElement e : buffer) {
String converted = new Converter(project).elementToKotlin(e); String converted = new Converter(project, J2kPackage.getPluginSettings()).elementToKotlin(e);
if (!converted.isEmpty()) { if (!converted.isEmpty()) {
result.append(converted).append(EOL); result.append(converted).append(EOL);
} }
+29 -29
View File
@@ -37,7 +37,7 @@ import org.jetbrains.jet.util.QualifiedNamesUtil
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
public open class Converter(val project: Project) { public class Converter(val project: Project, val settings: ConverterSettings) {
private var classIdentifiersSet: MutableSet<String> = Sets.newHashSet()!! private var classIdentifiersSet: MutableSet<String> = Sets.newHashSet()!!
@@ -47,35 +47,35 @@ public open class Converter(val project: Project) {
private val javaToKotlinClassMap: JavaToKotlinClassMap = JavaToKotlinClassMap.getInstance() private val javaToKotlinClassMap: JavaToKotlinClassMap = JavaToKotlinClassMap.getInstance()
public open var methodReturnType: PsiType? = null public var methodReturnType: PsiType? = null
private set private set
public open fun addFlag(flag: J2KConverterFlags): Boolean { public fun addFlag(flag: J2KConverterFlags): Boolean {
return flags?.add(flag)!! return flags?.add(flag)!!
} }
public open fun hasFlag(flag: J2KConverterFlags): Boolean { public fun hasFlag(flag: J2KConverterFlags): Boolean {
return flags?.contains(flag)!! return flags?.contains(flag)!!
} }
public open fun setClassIdentifiers(identifiers: MutableSet<String>) { public fun setClassIdentifiers(identifiers: MutableSet<String>) {
classIdentifiersSet = identifiers classIdentifiersSet = identifiers
} }
public open fun getClassIdentifiers(): Set<String> { public fun getClassIdentifiers(): Set<String> {
return Collections.unmodifiableSet(classIdentifiersSet) return Collections.unmodifiableSet(classIdentifiersSet)
} }
public open fun clearClassIdentifiers() { public fun clearClassIdentifiers() {
classIdentifiersSet.clear() classIdentifiersSet.clear()
} }
public open fun elementToKotlin(element: PsiElement): String { public fun elementToKotlin(element: PsiElement): String {
val kElement = topElementToElement(element) val kElement = topElementToElement(element)
return kElement?.toKotlin() ?: "" return kElement?.toKotlin() ?: ""
} }
public open fun topElementToElement(element: PsiElement?): Node? = when(element) { public fun topElementToElement(element: PsiElement?): Node? = when(element) {
is PsiJavaFile -> fileToFile(element) is PsiJavaFile -> fileToFile(element)
is PsiClass -> classToClass(element) is PsiClass -> classToClass(element)
is PsiMethod -> methodToFunction(element) is PsiMethod -> methodToFunction(element)
@@ -86,11 +86,11 @@ public open class Converter(val project: Project) {
else -> null else -> null
} }
public open fun fileToFile(javaFile: PsiJavaFile): File { public fun fileToFile(javaFile: PsiJavaFile): File {
return fileToFile(javaFile, Collections.emptyList<String>()) return fileToFile(javaFile, Collections.emptyList<String>())
} }
public open fun fileToFileWithCompatibilityImport(javaFile: PsiJavaFile): File { public fun fileToFileWithCompatibilityImport(javaFile: PsiJavaFile): File {
return fileToFile(javaFile, Collections.singletonList("kotlin.compatibility.*")) return fileToFile(javaFile, Collections.singletonList("kotlin.compatibility.*"))
} }
@@ -124,7 +124,7 @@ public open class Converter(val project: Project) {
return File(quoteKeywords(javaFile.getPackageName()), imports, body, createMainFunction(javaFile)) return File(quoteKeywords(javaFile.getPackageName()), imports, body, createMainFunction(javaFile))
} }
public open fun anonymousClassToAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass { public fun anonymousClassToAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass {
return AnonymousClass(this, getMembers(anonymousClass)) return AnonymousClass(this, getMembers(anonymousClass))
} }
@@ -352,26 +352,26 @@ public open class Converter(val project: Project) {
return false return false
} }
public open fun blockToBlock(block: PsiCodeBlock?, notEmpty: Boolean): Block { public fun blockToBlock(block: PsiCodeBlock?, notEmpty: Boolean): Block {
if (block == null) if (block == null)
return Block.EMPTY_BLOCK return Block.EMPTY_BLOCK
return Block(removeEmpty(statementsToStatementList(block.getChildren())), notEmpty) return Block(removeEmpty(statementsToStatementList(block.getChildren())), notEmpty)
} }
public open fun blockToBlock(block: PsiCodeBlock?): Block { public fun blockToBlock(block: PsiCodeBlock?): Block {
return blockToBlock(block, true) return blockToBlock(block, true)
} }
public open fun statementsToStatementList(statements: Array<PsiElement>): List<Element> { public fun statementsToStatementList(statements: Array<PsiElement>): List<Element> {
return statements.filterNot { it is PsiWhiteSpace }.map { statementToStatement(it) } return statements.filterNot { it is PsiWhiteSpace }.map { statementToStatement(it) }
} }
public open fun statementsToStatementList(statements: List<PsiElement>): List<Element> { public fun statementsToStatementList(statements: List<PsiElement>): List<Element> {
return statements.filterNot { it is PsiWhiteSpace }.map { statementToStatement(it) } return statements.filterNot { it is PsiWhiteSpace }.map { statementToStatement(it) }
} }
public open fun statementToStatement(s: PsiElement?): Element { public fun statementToStatement(s: PsiElement?): Element {
if (s == null) if (s == null)
return Statement.EMPTY_STATEMENT return Statement.EMPTY_STATEMENT
@@ -380,14 +380,14 @@ public open class Converter(val project: Project) {
return statementVisitor.getResult() return statementVisitor.getResult()
} }
public open fun expressionsToExpressionList(expressions: Array<PsiExpression>): List<Expression> { public fun expressionsToExpressionList(expressions: Array<PsiExpression>): List<Expression> {
val result = ArrayList<Expression>() val result = ArrayList<Expression>()
for (e : PsiExpression? in expressions) for (e : PsiExpression? in expressions)
result.add(expressionToExpression(e)) result.add(expressionToExpression(e))
return result return result
} }
public open fun expressionToExpression(e: PsiExpression?): Expression { public fun expressionToExpression(e: PsiExpression?): Expression {
if (e == null) if (e == null)
return Expression.EMPTY_EXPRESSION return Expression.EMPTY_EXPRESSION
@@ -396,7 +396,7 @@ public open class Converter(val project: Project) {
return expressionVisitor.getResult() return expressionVisitor.getResult()
} }
public open fun elementToElement(e: PsiElement?): Element { public fun elementToElement(e: PsiElement?): Element {
if (e == null) if (e == null)
return Element.EMPTY_ELEMENT return Element.EMPTY_ELEMENT
@@ -405,7 +405,7 @@ public open class Converter(val project: Project) {
return elementVisitor.getResult() return elementVisitor.getResult()
} }
public open fun elementsToElementList(elements: Array<out PsiElement?>): List<Element> { public fun elementsToElementList(elements: Array<out PsiElement?>): List<Element> {
val result = ArrayList<Element>() val result = ArrayList<Element>()
for (element in elements) { for (element in elements) {
result.add(elementToElement(element)) result.add(elementToElement(element))
@@ -413,14 +413,14 @@ public open class Converter(val project: Project) {
return result return result
} }
public open fun typeElementToTypeElement(element: PsiTypeElement?): TypeElement { public fun typeElementToTypeElement(element: PsiTypeElement?): TypeElement {
return TypeElement(if (element == null) return TypeElement(if (element == null)
EmptyType() EmptyType()
else else
typeToType(element.getType())) typeToType(element.getType()))
} }
public open fun typeToType(`type`: PsiType?): Type { public fun typeToType(`type`: PsiType?): Type {
if (`type` == null) if (`type` == null)
return EmptyType() return EmptyType()
@@ -429,11 +429,11 @@ public open class Converter(val project: Project) {
return typeVisitor.getResult() return typeVisitor.getResult()
} }
public open fun typesToTypeList(types: Array<PsiType>): List<Type> { public fun typesToTypeList(types: Array<PsiType>): List<Type> {
return types.map { typeToType(it) } return types.map { typeToType(it) }
} }
public open fun typeToType(`type`: PsiType?, notNull: Boolean): Type { public fun typeToType(`type`: PsiType?, notNull: Boolean): Type {
val result: Type = typeToType(`type`) val result: Type = typeToType(`type`)
if (notNull) { if (notNull) {
return result.convertedToNotNull() return result.convertedToNotNull()
@@ -450,17 +450,17 @@ public open class Converter(val project: Project) {
return result return result
} }
public open fun parametersToParameterList(parameters: Array<PsiParameter>): List<Parameter?> { public fun parametersToParameterList(parameters: Array<PsiParameter>): List<Parameter?> {
return parameters.map { parameterToParameter(it) } return parameters.map { parameterToParameter(it) }
} }
public open fun parameterToParameter(parameter: PsiParameter, forceNotNull: Boolean = false): Parameter { public fun parameterToParameter(parameter: PsiParameter, forceNotNull: Boolean = false): Parameter {
return Parameter(Identifier(parameter.getName()!!), return Parameter(Identifier(parameter.getName()!!),
typeToType(parameter.getType(), typeToType(parameter.getType(),
forceNotNull || isAnnotatedAsNotNull(parameter.getModifierList())), true) forceNotNull || isAnnotatedAsNotNull(parameter.getModifierList())), true)
} }
public open fun argumentsToExpressionList(expression: PsiCallExpression): List<Expression> { public fun argumentsToExpressionList(expression: PsiCallExpression): List<Expression> {
val argumentList: PsiExpressionList? = expression.getArgumentList() val argumentList: PsiExpressionList? = expression.getArgumentList()
val arguments: Array<PsiExpression> = (if (argumentList != null) val arguments: Array<PsiExpression> = (if (argumentList != null)
argumentList.getExpressions() argumentList.getExpressions()
@@ -485,7 +485,7 @@ public open class Converter(val project: Project) {
return result return result
} }
public open fun expressionToExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { public fun expressionToExpression(argument: PsiExpression?, expectedType: PsiType?): Expression {
if (argument == null) if (argument == null)
return Identifier.EMPTY_IDENTIFIER return Identifier.EMPTY_IDENTIFIER
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2013 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.j2k
public class ConverterSettings(
val forceNotNullTypes: Boolean,
val forceLocalVariableImmutability: Boolean,
val specifyLocalVariableTypeByDefault: Boolean
) {}
public val PluginSettings: ConverterSettings = ConverterSettings(
forceNotNullTypes = true,
forceLocalVariableImmutability = true,
specifyLocalVariableTypeByDefault = false
)
public val TestSettings: ConverterSettings = ConverterSettings(
forceNotNullTypes = false,
forceLocalVariableImmutability = false,
specifyLocalVariableTypeByDefault = true
)
@@ -96,7 +96,7 @@ 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(file.getProject()) val converter = Converter(file.getProject(), TestSettings)
setClassIdentifiers(converter, file) setClassIdentifiers(converter, file)
return prettify(converter.fileToFile(file).toKotlin()) return prettify(converter.fileToFile(file).toKotlin())
} }
@@ -106,7 +106,7 @@ object JavaToKotlinTranslator {
fun generateKotlinCodeWithCompatibilityImport(javaCode: String): String { fun generateKotlinCodeWithCompatibilityImport(javaCode: String): String {
val file = createFile(javaCode) val file = createFile(javaCode)
if (file is PsiJavaFile) { if (file is PsiJavaFile) {
val converter = Converter(file.getProject()) val converter = Converter(file.getProject(), TestSettings)
setClassIdentifiers(converter, file) setClassIdentifiers(converter, file)
return prettify(converter.fileToFileWithCompatibilityImport(file).toKotlin()) return prettify(converter.fileToFileWithCompatibilityImport(file).toKotlin())
} }
@@ -24,13 +24,9 @@ public class CallChainExpression(val expression: Expression, val identifier: Exp
public override fun toKotlin(): String { public override fun toKotlin(): String {
if (!expression.isEmpty()) { if (!expression.isEmpty()) {
return expression.toKotlin() + (if (expression.isNullable() && !forceDotCall) "?." else ".") + identifier.toKotlin() return expression.toKotlin() + (if (expression.isNullable()) "?." else ".") + identifier.toKotlin()
} }
return identifier.toKotlin() return identifier.toKotlin()
} }
class object {
public var forceDotCall: Boolean = true
}
} }
@@ -25,18 +25,15 @@ public class LocalVariable(val identifier: Identifier,
val initializer: Expression, val initializer: Expression,
val converter: Converter) : Expression() { val converter: Converter) : Expression() {
public fun isImmutable(): Boolean = forceImmutable || modifiersSet.contains(Modifier.FINAL) public fun isImmutable(): Boolean =
converter.settings.forceLocalVariableImmutability || modifiersSet.contains(Modifier.FINAL)
override fun toKotlin(): String { override fun toKotlin(): String {
if (initializer.isEmpty()) { if (initializer.isEmpty()) {
return "${identifier.toKotlin()} : ${javaType.toKotlin()}" return "${identifier.toKotlin()} : ${javaType.toKotlin()}"
} }
return "${identifier.toKotlin()} ${if (specifyTypeExplicitly) ": ${javaType.toKotlin()} " else ""}= ${initializer.toKotlin()}" val shouldSpecifyType = converter.settings.specifyLocalVariableTypeByDefault
} return "${identifier.toKotlin()} ${if (shouldSpecifyType) ": ${javaType.toKotlin()} " else ""}= ${initializer.toKotlin()}"
class object {
public var specifyTypeExplicitly: Boolean = false
public var forceImmutable: Boolean = true
} }
} }
@@ -21,7 +21,8 @@ import org.jetbrains.jet.j2k.Converter
public fun Type.isPrimitive(): Boolean = this is PrimitiveType public fun Type.isPrimitive(): Boolean = this is PrimitiveType
public abstract class MayBeNullableType(override public val nullable: Boolean, val converter: Converter): Type { public abstract class MayBeNullableType(nullable: Boolean, val converter: Converter): Type {
override public val nullable: Boolean = !converter.settings.forceNotNullTypes && nullable
} }
public trait NotNullType : Type { public trait NotNullType : Type {
@@ -39,13 +40,6 @@ public trait Type : Element {
} }
protected fun isNullableStr(): String? { protected fun isNullableStr(): String? {
return (if (nullable && !forceNotNullTypes) return if (nullable) "?" else ""
"?"
else
"")
}
class object {
public var forceNotNullTypes: Boolean = true
} }
} }
@@ -18,9 +18,7 @@ package org.jetbrains.jet.j2k.test;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import org.jetbrains.jet.j2k.ast.CallChainExpression; import org.jetbrains.jet.j2k.J2kPackage;
import org.jetbrains.jet.j2k.ast.LocalVariable;
import org.jetbrains.jet.j2k.ast.types.Type;
import static org.jetbrains.jet.j2k.test.TestPackage.suiteForDirectory; import static org.jetbrains.jet.j2k.test.TestPackage.suiteForDirectory;
@@ -32,15 +30,12 @@ public class BasicConverterTestSuite {
public static Test suite() { public static Test suite() {
TestSuite suite = new TestSuite(); TestSuite suite = new TestSuite();
suite.addTest(suiteForDirectory("j2k/tests/testData", "/ast", new NamedTestFactory() { suite.addTest(suiteForDirectory("j2k/tests/testData", "/ast", new NamedTestFactory() {
@Override
public Test createTest(String dataPath, String name) { public Test createTest(String dataPath, String name) {
//noinspection JUnitTestCaseWithNoTests //noinspection JUnitTestCaseWithNoTests
return new StandaloneJavaToKotlinConverterTest(dataPath, name) { return new StandaloneJavaToKotlinConverterTest(dataPath, name, J2kPackage.getTestSettings()) {
@Override @Override
protected void runTest() { protected void runTest() {
CallChainExpression.forceDotCall = false;
LocalVariable.specifyTypeExplicitly = true;
LocalVariable.forceImmutable = false;
Type.forceNotNullTypes = false;
super.runTest(); super.runTest();
} }
}; };
@@ -18,9 +18,7 @@ package org.jetbrains.jet.j2k.test;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import org.jetbrains.jet.j2k.ast.CallChainExpression; import org.jetbrains.jet.j2k.J2kPackage;
import org.jetbrains.jet.j2k.ast.LocalVariable;
import org.jetbrains.jet.j2k.ast.types.Type;
import static org.jetbrains.jet.j2k.test.TestPackage.suiteForDirectory; import static org.jetbrains.jet.j2k.test.TestPackage.suiteForDirectory;
@@ -32,15 +30,12 @@ public class ConverterTestSuiteForPlugin {
TestSuite suite = new TestSuite(); TestSuite suite = new TestSuite();
suite.addTest(suiteForDirectory("j2k/tests/testData", "/plugin", new NamedTestFactory() { suite.addTest(suiteForDirectory("j2k/tests/testData", "/plugin", new NamedTestFactory() {
@Override
public Test createTest(String dataPath, String name) { public Test createTest(String dataPath, String name) {
//noinspection JUnitTestCaseWithNoTests //noinspection JUnitTestCaseWithNoTests
return new StandaloneJavaToKotlinConverterTest(dataPath, name) { return new StandaloneJavaToKotlinConverterTest(dataPath, name, J2kPackage.getPluginSettings()) {
@Override @Override
protected void runTest() { protected void runTest() {
CallChainExpression.forceDotCall = true;
LocalVariable.specifyTypeExplicitly = false;
LocalVariable.forceImmutable = true;
Type.forceNotNullTypes = true;
super.runTest(); super.runTest();
} }
}; };
@@ -31,12 +31,15 @@ import org.jetbrains.jet.j2k.JavaToKotlinTranslator
import org.jetbrains.jet.ConfigurationKind import org.jetbrains.jet.ConfigurationKind
import org.jetbrains.jet.JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations import org.jetbrains.jet.JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations
import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.UsefulTestCase
import org.jetbrains.jet.j2k.ConverterSettings
public abstract class StandaloneJavaToKotlinConverterTest(val dataPath: String, val name: String) : UsefulTestCase() { public abstract class StandaloneJavaToKotlinConverterTest(val dataPath: String,
val name: String,
val settings: ConverterSettings) : UsefulTestCase() {
protected override fun runTest(): Unit { protected override fun runTest(): Unit {
val jetCoreEnvironment = createEnvironmentWithMockJdkAndIdeaAnnotations(getTestRootDisposable(), ConfigurationKind.JDK_ONLY) val jetCoreEnvironment = createEnvironmentWithMockJdkAndIdeaAnnotations(getTestRootDisposable(), ConfigurationKind.JDK_ONLY)
val converter = Converter(jetCoreEnvironment.getProject()) val converter = Converter(jetCoreEnvironment.getProject(), settings)
val javaPath = "j2k/tests/testData/" + getTestFilePath() val javaPath = "j2k/tests/testData/" + getTestFilePath()
val kotlinPath = javaPath.replace(".jav", ".kt") val kotlinPath = javaPath.replace(".jav", ".kt")
val kotlinFile = File(kotlinPath) val kotlinFile = File(kotlinPath)