diff --git a/.idea/dictionaries/valentin.xml b/.idea/dictionaries/valentin.xml
index 54354129c96..0bfc803d560 100644
--- a/.idea/dictionaries/valentin.xml
+++ b/.idea/dictionaries/valentin.xml
@@ -4,6 +4,7 @@
initializers
inserter
pparent
+ processings
rparenth
diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java
index 201d4eacac7..04468a1a14a 100644
--- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java
+++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java
@@ -25,10 +25,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiJavaFile;
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.j2k.IdeaReferenceSearcher;
+import org.jetbrains.jet.j2k.*;
import org.jetbrains.jet.plugin.j2k.J2kPostProcessor;
import java.util.List;
@@ -47,7 +44,7 @@ public class JavaToKotlinAction extends AnAction {
return;
}
- final Converter converter = Converter.OBJECT$.create(project,
+ final JavaToKotlinConverter converter = new JavaToKotlinConverter(project,
ConverterSettings.defaultSettings,
new FilesConversionScope(selectedJavaFiles),
IdeaReferenceSearcher.INSTANCE$,
diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java
index 4a848965605..ed8fd3931de 100644
--- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java
+++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java
@@ -27,7 +27,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.CodeStyleManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jet.j2k.Converter;
+import org.jetbrains.jet.j2k.JavaToKotlinConverter;
import java.io.IOException;
import java.util.*;
@@ -83,7 +83,7 @@ public class JavaToKotlinActionUtil {
}
@NotNull
- static List convertFiles(final Converter converter, List allJavaFilesNear) {
+ static List convertFiles(final JavaToKotlinConverter converter, List allJavaFilesNear) {
final List result = new LinkedList();
for (final PsiFile f : allJavaFilesNear) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@@ -120,7 +120,7 @@ public class JavaToKotlinActionUtil {
}
@Nullable
- private static VirtualFile convertOneFile(Converter converter, PsiFile psiFile) {
+ private static VirtualFile convertOneFile(JavaToKotlinConverter converter, PsiFile psiFile) {
try {
VirtualFile virtualFile = psiFile.getVirtualFile();
if (psiFile instanceof PsiJavaFile && virtualFile != null) {
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 31b23c15c5a..6a5fdc7ef05 100644
--- a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt
+++ b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt
@@ -86,7 +86,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor {
return when (value) {
- is PsiExpression -> listOf(converter.convertExpression(value as? PsiExpression, expectedType).assignPrototype(value))
+ is PsiExpression -> listOf(converter.createDefaultCodeConverter()/*TODO*/.convertExpression(value as? PsiExpression, expectedType).assignPrototype(value))
is PsiArrayInitializerMemberValue -> {
val componentType = (expectedType as? PsiArrayType)?.getComponentType()
diff --git a/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt b/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt
index 2c190b9342c..a63b30acb3d 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt
@@ -35,9 +35,15 @@ import com.intellij.psi.PsiExpressionStatement
import com.intellij.psi.PsiAssignmentExpression
import com.intellij.psi.PsiExpression
import com.intellij.psi.JavaTokenType
-import com.intellij.psi.PsiElementFactory
-class FieldCorrectionInfo(val name: Identifier, val access: Modifier?, val setterAccess: Modifier?)
+class FieldCorrectionInfo(val name: String, val access: Modifier?, val setterAccess: Modifier?) {
+ val identifier = Identifier(name).assignNoPrototype()
+}
+
+enum class AccessorKind {
+ GETTER
+ SETTER
+}
class ClassBodyConverter(private val psiClass: PsiClass,
private val converter: Converter) {
@@ -47,10 +53,8 @@ class ClassBodyConverter(private val psiClass: PsiClass,
public fun convertBody(): ClassBody {
processAccessorsToDrop()
- val correctedConverter = buildConverterWithCorrectedFieldNames()
-
val constructorConverter = if (psiClass.getName() != null)
- ConstructorConverter(psiClass, correctedConverter, fieldCorrections)
+ ConstructorConverter(psiClass, converter, fieldCorrections)
else
null
@@ -59,8 +63,8 @@ class ClassBodyConverter(private val psiClass: PsiClass,
if (element is PsiMember) {
if (element is PsiAnnotationMethod) continue // converted in convertAnnotationType()
- val converted = correctedConverter.convertMember(element, membersToRemove, constructorConverter)
- if (converted != null && !converted.isEmpty) {
+ val converted = converter.convertMember(element, membersToRemove, constructorConverter)
+ if (converted != null/* && !converted.isEmpty()*/) {
convertedMembers.put(element, converted)
}
}
@@ -79,11 +83,8 @@ class ClassBodyConverter(private val psiClass: PsiClass,
for ((psiMember, member) in convertedMembers) {
if (member is PrimaryConstructor) {
assert(primaryConstructorSignature == null)
- primaryConstructorSignature = member.signature()
- val initializer = member.initializer()
- if (initializer != null) {
- members.add(initializer)
- }
+ primaryConstructorSignature = member.createSignature(converter)
+ members.add(member.initializer())
}
else if (member is FactoryFunction) {
factoryFunctions.add(member)
@@ -171,17 +172,10 @@ class ClassBodyConverter(private val psiClass: PsiClass,
else
converter.convertModifiers(field).accessModifier()
//TODO: check that setter access is not bigger
- fieldCorrections[field] = FieldCorrectionInfo(Identifier(getterInfo.propertyName).assignNoPrototype(),
- getterAccess,
- setterAccess)
+ fieldCorrections[field] = FieldCorrectionInfo(getterInfo.propertyName, getterAccess, setterAccess)
}
}
- private enum class AccessorKind {
- GETTER
- SETTER
- }
-
private class AccessorInfo(val method: PsiMethod, val field: PsiField, val kind: AccessorKind, val propertyName: String)
private fun getAccessorInfo(method: PsiMethod): AccessorInfo? {
@@ -215,36 +209,4 @@ class ClassBodyConverter(private val psiClass: PsiClass,
if (field.getContainingClass() != psiClass || field.hasModifierProperty(PsiModifier.STATIC)) return null
return field
}
-
- //TODO: correct usages to accessors (and field too) across all code being converted + all other Kotlin code in the project
- private fun buildConverterWithCorrectedFieldNames(): Converter {
- if (fieldCorrections.isEmpty()) return converter
- return converter.withExpressionConverter { prevExpressionConverter ->
- object : ExpressionConverter {
- override fun convertExpression(expression: PsiExpression, converter: Converter): Expression {
- val result = prevExpressionConverter.convertExpression(expression, converter)
- if (expression !is PsiReferenceExpression) return result
-
- val field = expression.resolve() as? PsiField ?: return result
- val correction = fieldCorrections[field] ?: return result
- if (correction.name.name == field.getName()) return result
-
- val qualifier = expression.getQualifierExpression()
- return if (qualifier != null) {
- QualifiedExpression(converter.convertExpression(qualifier), correction.name)
- }
- else {
- // check if field name is shadowed
- val elementFactory = PsiElementFactory.SERVICE.getInstance(expression.getProject())
- val refExpr = elementFactory.createExpressionFromText(correction.name.name, expression) as PsiReferenceExpression
- if (refExpr.resolve() == null)
- correction.name
- else
- QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), correction.name) //TODO: this is not correct in case of nested/anonymous classes
- }
-
- }
- }
- }
- }
}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt
new file mode 100644
index 00000000000..8ad53ef746f
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.j2k
+
+import com.intellij.psi.PsiType
+import com.intellij.psi.PsiCodeBlock
+import com.intellij.psi.PsiStatement
+import org.jetbrains.jet.j2k.ast.Block
+import org.jetbrains.jet.j2k.ast.LBrace
+import org.jetbrains.jet.j2k.ast.assignPrototype
+import org.jetbrains.jet.j2k.ast.RBrace
+import org.jetbrains.jet.j2k.ast.Statement
+import com.intellij.psi.PsiExpression
+import org.jetbrains.jet.j2k.ast.Expression
+import com.intellij.psi.PsiLocalVariable
+import org.jetbrains.jet.j2k.ast.LocalVariable
+import com.intellij.psi.PsiModifier
+import org.jetbrains.jet.j2k.ast.declarationIdentifier
+import org.jetbrains.jet.j2k.ast.Identifier
+import com.intellij.psi.PsiPrimitiveType
+import com.intellij.psi.PsiClassType
+import org.jetbrains.jet.j2k.ast.BangBangExpression
+import org.jetbrains.jet.j2k.ast.assignNoPrototype
+import org.jetbrains.jet.j2k.ast.LiteralExpression
+import org.jetbrains.jet.j2k.ast.MethodCallExpression
+import org.jetbrains.jet.j2k.ast.Type
+import org.jetbrains.jet.j2k.ast.ErrorType
+import org.jetbrains.jet.j2k.ast.Nullability
+import com.intellij.psi.CommonClassNames.JAVA_LANG_BYTE
+import com.intellij.psi.CommonClassNames.JAVA_LANG_SHORT
+import com.intellij.psi.CommonClassNames.JAVA_LANG_INTEGER
+import com.intellij.psi.CommonClassNames.JAVA_LANG_LONG
+import com.intellij.psi.CommonClassNames.JAVA_LANG_FLOAT
+import com.intellij.psi.CommonClassNames.JAVA_LANG_DOUBLE
+import com.intellij.psi.CommonClassNames.JAVA_LANG_CHARACTER
+import com.intellij.psi.PsiAnonymousClass
+import org.jetbrains.jet.j2k.ast.AnonymousClassBody
+
+class CodeConverter(public val converter: Converter,
+ private val expressionConverter: ExpressionConverter,
+ private val statementConverter: StatementConverter,
+ public val methodReturnType: PsiType?) {
+
+ public val typeConverter: TypeConverter = converter.typeConverter
+ public val settings: ConverterSettings = converter.settings
+
+ public fun withSpecialExpressionConverter(specialConverter: SpecialExpressionConverter): CodeConverter
+ = CodeConverter(converter, expressionConverter.withSpecialConverter(specialConverter), statementConverter, methodReturnType)
+
+ public fun withMethodReturnType(methodReturnType: PsiType?): CodeConverter
+ = CodeConverter(converter, expressionConverter, statementConverter, methodReturnType)
+
+ public fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = { true }): Block {
+ if (block == null) return Block.Empty()
+
+ val lBrace = LBrace().assignPrototype(block.getLBrace())
+ val rBrace = RBrace().assignPrototype(block.getRBrace())
+ return Block(block.getStatements().filter(statementFilter).map { convertStatement(it) }, lBrace, rBrace, notEmpty).assignPrototype(block)
+ }
+
+ public fun convertStatement(statement: PsiStatement?): Statement {
+ if (statement == null) return Statement.Empty
+
+ return statementConverter.convertStatement(statement, this).assignPrototype(statement)
+ }
+
+ public fun convertExpressions(expressions: Array): List
+ = expressions.map { convertExpression(it) }
+
+ public fun convertExpression(expression: PsiExpression?): Expression {
+ if (expression == null) return Expression.Empty
+
+ return expressionConverter.convertExpression(expression, this).assignPrototype(expression)
+ }
+
+ public fun convertLocalVariable(variable: PsiLocalVariable): LocalVariable {
+ val isVal = variable.hasModifierProperty(PsiModifier.FINAL) ||
+ variable.getInitializer() == null/* we do not know actually and prefer val until we have better analysis*/ ||
+ !variable.hasWriteAccesses(converter.referenceSearcher, variable.getContainingMethod())
+ return LocalVariable(variable.declarationIdentifier(),
+ converter.convertAnnotations(variable),
+ converter.convertModifiers(variable),
+ converter.variableTypeToDeclare(variable, settings.specifyLocalVariableTypeByDefault, isVal),
+ convertExpression(variable.getInitializer(), variable.getType()),
+ isVal).assignPrototype(variable)
+ }
+
+ public fun convertExpression(expression: PsiExpression?, expectedType: PsiType?): Expression {
+ if (expression == null) return Identifier.Empty()
+
+ var convertedExpression = convertExpression(expression)
+ if (expectedType == null || expectedType == PsiType.VOID) return convertedExpression
+
+ val actualType = expression.getType()
+ if (actualType == null) return convertedExpression
+
+ if (convertedExpression.isNullable &&
+ (actualType is PsiPrimitiveType || actualType is PsiClassType && expectedType is PsiPrimitiveType)) {
+ convertedExpression = BangBangExpression(convertedExpression).assignNoPrototype()
+ }
+
+ if (needConversion(actualType, expectedType) && convertedExpression !is LiteralExpression) {
+ val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedType.getCanonicalText()]
+ if (conversion != null) {
+ convertedExpression = MethodCallExpression.buildNotNull(convertedExpression, conversion)
+ }
+ }
+
+ return convertedExpression.assignPrototype(expression)
+ }
+
+ public fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type {
+ var convertedExpression = convertExpression(expression)
+ val actualType = expression.getType()
+ if (actualType == null) return ErrorType()
+ var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull)
+
+ if (actualType is PsiPrimitiveType && resultType.isNullable ||
+ expectedType is PsiPrimitiveType && actualType is PsiClassType) {
+ resultType = resultType.toNotNullType()
+ }
+
+ if (needConversion(actualType, expectedType) && convertedExpression !is LiteralExpression) {
+ val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedType.getCanonicalText()]
+ if (conversion != null) {
+ resultType = typeConverter.convertType(expectedType, Nullability.NotNull)
+ }
+ }
+
+ return resultType
+ }
+
+ public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody {
+ return AnonymousClassBody(ClassBodyConverter(anonymousClass, converter).convertBody(),
+ anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass)
+ }
+
+ private fun needConversion(actual: PsiType, expected: PsiType): Boolean {
+ val expectedStr = expected.getCanonicalText()
+ val actualStr = actual.getCanonicalText()
+ return expectedStr != actualStr &&
+ expectedStr != typeConversionMap[actualStr] &&
+ actualStr != typeConversionMap[expectedStr]
+ }
+
+ private val typeConversionMap: Map = mapOf(
+ JAVA_LANG_BYTE to "byte",
+ JAVA_LANG_SHORT to "short",
+ JAVA_LANG_INTEGER to "int",
+ JAVA_LANG_LONG to "long",
+ JAVA_LANG_FLOAT to "float",
+ JAVA_LANG_DOUBLE to "double",
+ JAVA_LANG_CHARACTER to "char"
+ )
+
+
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt b/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt
index ef02b091e97..3ff53639152 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt
@@ -164,33 +164,36 @@ class ConstructorConverter(private val psiClass: PsiClass,
if (constructor in constructorsToDrop) return null
val params = converter.convertParameterList(constructor.getParameterList())
- val bodyConverter = converter.withExpressionConverter { prevExpressionConverter ->
- object : ExpressionConverter {
- override fun convertExpression(expression: PsiExpression, converter: Converter): Expression {
- if (expression is PsiReferenceExpression && expression.isQualifierEmptyOrThis()) {
- val member = expression.getReference()?.resolve() as? PsiMember
- if (member != null &&
- !member.isConstructor() &&
- member.getContainingClass() == constructor.getContainingClass()) {
- val isNullable = member is PsiField && typeConverter.variableNullability(member).isNullable(converter.settings)
- val qualifier = if (member.hasModifierProperty(PsiModifier.STATIC)) constructor.declarationIdentifier() else tempValIdentifier()
- val name = fieldCorrections[member]?.name ?: Identifier(expression.getReferenceName()!!, isNullable).assignNoPrototype()
- return QualifiedExpression(qualifier, name)
- }
- }
-
- return prevExpressionConverter.convertExpression(expression, converter)
- }
- }
- }
- var body = postProcessBody(bodyConverter.convertBlock(constructor.getBody()))
val containingClass = constructor.getContainingClass()
val typeParameterList = converter.convertTypeParameterList(containingClass?.getTypeParameterList())
- val factoryFunctionType = ClassType(ReferenceElement(containingClass?.declarationIdentifier() ?: Identifier.Empty, typeParameterList.parameters).assignNoPrototype(),
+ val factoryFunctionType = ClassType(ReferenceElement(containingClass?.declarationIdentifier() ?: Identifier.Empty(), typeParameterList.parameters).assignNoPrototype(),
Nullability.NotNull,
converter.settings).assignNoPrototype()
+
+ fun convertBody(codeConverter: CodeConverter): Block {
+ val bodyConverter = codeConverter.withSpecialExpressionConverter(
+ object : SpecialExpressionConverter {
+ override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
+ if (expression is PsiReferenceExpression && expression.isQualifierEmptyOrThis()) {
+ val member = expression.getReference()?.resolve() as? PsiMember
+ if (member != null &&
+ !member.isConstructor() &&
+ member.getContainingClass() == constructor.getContainingClass()) {
+ val isNullable = member is PsiField && typeConverter.variableNullability(member).isNullable(codeConverter.settings)
+ val qualifier = if (member.hasModifierProperty(PsiModifier.STATIC)) constructor.declarationIdentifier() else tempValIdentifier()
+ val name = fieldCorrections[member]?.name ?: expression.getReferenceName()!!
+ return QualifiedExpression(qualifier, Identifier(name, isNullable).assignNoPrototype())
+ }
+ }
+
+ return null
+ }
+ })
+ return postProcessBody(bodyConverter.convertBlock(constructor.getBody()))
+ }
+
return FactoryFunction(constructor.declarationIdentifier(), annotations, correctFactoryFunctionAccess(modifiers),
- factoryFunctionType, params, typeParameterList, body)
+ factoryFunctionType, params, typeParameterList, converter.lazyElement(::convertBody))
}
}
@@ -204,7 +207,8 @@ class ConstructorConverter(private val psiClass: PsiClass,
val parameterUsageReplacementMap = HashMap()
val correctedTypeConverter = converter.withSpecialContext(psiClass).typeConverter /* to correct nested class references */
- val block = if (body != null) {
+
+ val bodyGenerator: (CodeConverter) -> Block = if (body != null) {
val statementsToRemove = HashSet()
for (parameter in params) {
val (field, initializationStatement) = findBackingFieldForConstructorParameter(parameter, primaryConstructor) ?: continue
@@ -230,44 +234,46 @@ class ConstructorConverter(private val psiClass: PsiClass,
statementsToRemove.add(initializationStatement)
membersToRemove.add(field)
- val fieldName = fieldCorrection?.name?.name ?: field.getName()!!
+ val fieldName = fieldCorrection?.name ?: field.getName()!!
if (fieldName != parameter.getName()) {
parameterUsageReplacementMap.put(parameter.getName()!!, fieldName)
}
}
- val bodyConverter = converter.withExpressionConverter { prevExpressionConverter ->
- object : ReplacingExpressionConverter(parameterUsageReplacementMap, prevExpressionConverter) {
- override fun convertExpression(expression: PsiExpression, converter: Converter): Expression {
- if (expression is PsiMethodCallExpression && expression.isSuperConstructorCall()) {
- return Expression.Empty // skip it
- }
- return super.convertExpression(expression, converter)
- }
- }
+ { codeConverter ->
+ val bodyConverter = codeConverter.withSpecialExpressionConverter(
+ object : ReplacingExpressionConverter(this, parameterUsageReplacementMap) {
+ override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
+ if (expression is PsiMethodCallExpression && expression.isSuperConstructorCall()) {
+ return Expression.Empty // skip it
+ }
+ return super.convertExpression(expression, codeConverter)
+ }
+ })
+ postProcessBody(bodyConverter.convertBlock(body, false, { !statementsToRemove.contains(it) }))
}
- postProcessBody(bodyConverter.convertBlock(body, false, { !statementsToRemove.contains(it) }))
}
else {
- Block.Empty
+ { it -> Block.Empty() }
}
// we need to replace renamed parameter usages in base class constructor arguments and in default values
- val correctedConverter = converter.withExpressionConverter {
- prevExpressionConverter -> ReplacingExpressionConverter(parameterUsageReplacementMap, prevExpressionConverter)
- }.withSpecialContext(psiClass) /* to correct nested class references */
+ val correctedConverter = converter.withSpecialContext(psiClass) /* to correct nested class references */
+ val correctedCodeConverter = correctedConverter.createDefaultCodeConverter()/*TODO!!!*/
+ .withSpecialExpressionConverter(ReplacingExpressionConverter(this, parameterUsageReplacementMap))
+
val statement = primaryConstructor.getBody()?.getStatements()?.firstOrNull()
val methodCall = (statement as? PsiExpressionStatement)?.getExpression() as? PsiMethodCallExpression
if (methodCall != null && methodCall.isSuperConstructorCall()) {
- baseClassParams = correctedConverter.convertExpressions(methodCall.getArgumentList().getExpressions())
+ baseClassParams = correctedCodeConverter.convertExpressions(methodCall.getArgumentList().getExpressions())
}
val parameterList = ParameterList(params.indices.map { i ->
val parameter = params[i]
val indexFromEnd = params.size - i - 1
val defaultValue = if (indexFromEnd < lastParamDefaults.size)
- correctedConverter.convertExpression(lastParamDefaults[indexFromEnd], parameter.getType())
+ correctedCodeConverter.convertExpression(lastParamDefaults[indexFromEnd], parameter.getType())
else
null
if (!parameterToField.containsKey(parameter)) {
@@ -276,7 +282,7 @@ class ConstructorConverter(private val psiClass: PsiClass,
else {
val (field, type) = parameterToField[parameter]!!
val fieldCorrection = fieldCorrections[field]
- val name = fieldCorrection?.name ?: field.declarationIdentifier()
+ val name = fieldCorrection?.identifier ?: field.declarationIdentifier()
val accessModifiers = if (fieldCorrection != null)
Modifiers(listOf()).with(fieldCorrection.access).assignNoPrototype()
else
@@ -289,7 +295,7 @@ class ConstructorConverter(private val psiClass: PsiClass,
defaultValue).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
}
}).assignPrototype(primaryConstructor.getParameterList())
- return PrimaryConstructor(annotations, modifiers, parameterList, block).assignPrototype(primaryConstructor)
+ return PrimaryConstructor(annotations, modifiers, parameterList, converter.lazyElement(bodyGenerator)).assignPrototype(primaryConstructor)
}
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair? {
@@ -328,8 +334,8 @@ class ConstructorConverter(private val psiClass: PsiClass,
return generateArtificialPrimaryConstructor(classBody)
}
else {
- val updatedFunctions = processFactoryFunctionsWithConstructorCall(classBody.factoryFunctions)
- return ClassBody(classBody.primaryConstructorSignature, classBody.baseClassParams, classBody.members, classBody.classObjectMembers, updatedFunctions, classBody.lBrace, classBody.rBrace)
+ processFactoryFunctionsWithConstructorCall(classBody.factoryFunctions)
+ return classBody
}
}
@@ -337,14 +343,13 @@ class ConstructorConverter(private val psiClass: PsiClass,
assert(classBody.primaryConstructorSignature == null)
val fieldsToInitialize = classBody.members.filterIsInstance(javaClass()).filter { it.isVal }
- val updatedFactoryFunctions = ArrayList()
for (function in classBody.factoryFunctions) {
- val body = function.body!!
- // 2 cases: secondary constructor either calls another constructor or does not call any
- val newStatements = processFactoryFunctionWithConstructorCall(body) ?:
- insertCallToArtificialPrimary(body, fieldsToInitialize)
- val newBody = Block(newStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
- updatedFactoryFunctions.add(function.withBody(newBody))
+ function.body!!.updateGenerator { (codeConverter, block) ->
+ // 2 cases: secondary constructor either calls another constructor or does not call any
+ val newStatements = processFactoryFunctionWithConstructorCall(block) ?:
+ insertCallToArtificialPrimary(block, fieldsToInitialize)
+ Block(newStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
+ }
}
val parameters = fieldsToInitialize.map { field ->
@@ -352,24 +357,25 @@ class ConstructorConverter(private val psiClass: PsiClass,
Parameter(field.identifier, field.type, varValModifier, field.annotations, field.modifiers.filter { it in ACCESS_MODIFIERS }).assignPrototypesFrom(field)
}
- val modifiers = Modifiers.Empty
+ val modifiers = Modifiers.Empty()
//TODO: we can generate it private when secondary constructors are supported by Kotlin
//val modifiers = Modifiers(listOf(Modifier.PRIVATE)).assignNoPrototype()
val parameterList = ParameterList(parameters).assignNoPrototype()
- val constructorSignature = PrimaryConstructorSignature(Annotations.Empty, modifiers, parameterList).assignNoPrototype()
+ val constructorSignature = PrimaryConstructorSignature(Annotations.Empty(), modifiers, parameterList).assignNoPrototype()
val updatedMembers = classBody.members.filter { !fieldsToInitialize.contains(it) }
- return ClassBody(constructorSignature, classBody.baseClassParams, updatedMembers, classBody.classObjectMembers, updatedFactoryFunctions, classBody.lBrace, classBody.rBrace)
+ return ClassBody(constructorSignature, classBody.baseClassParams, updatedMembers, classBody.classObjectMembers, classBody.factoryFunctions, classBody.lBrace, classBody.rBrace)
}
- private fun processFactoryFunctionsWithConstructorCall(functions: List): List {
- return functions.map { function ->
- val body = function.body!!
- val statements = processFactoryFunctionWithConstructorCall(body)
- if (statements != null) {
- function.withBody(Block(statements, body.lBrace, body.rBrace).assignPrototypesFrom(body))
- }
- else {
- function
+ private fun processFactoryFunctionsWithConstructorCall(functions: List) {
+ for (function in functions) {
+ function.body!!.updateGenerator { (codeConverter, block) ->
+ val statements = processFactoryFunctionWithConstructorCall(block)
+ if (statements != null) {
+ Block(statements, block.lBrace, block.rBrace).assignPrototypesFrom(block)
+ }
+ else {
+ block
+ }
}
}
}
@@ -387,7 +393,7 @@ class ConstructorConverter(private val psiClass: PsiClass,
statements[i] = ReturnStatement(constructorCall).assignNoPrototype()
return statements
}
- val localVar = LocalVariable(tempValIdentifier(), Annotations.Empty, Modifiers.Empty, null, constructorCall, true).assignNoPrototype()
+ val localVar = LocalVariable(tempValIdentifier(), Annotations.Empty(), Modifiers.Empty(), null, constructorCall, true).assignNoPrototype()
statements[i] = DeclarationStatement(listOf(localVar)).assignNoPrototype()
statements.add(ReturnStatement(tempValIdentifier()).assignNoPrototype())
return statements
@@ -431,8 +437,8 @@ class ConstructorConverter(private val psiClass: PsiClass,
val initializer = MethodCallExpression.buildNotNull(null, className, arguments).assignNoPrototype()
if (statements.isNotEmpty()) {
val localVar = LocalVariable(tempValIdentifier(),
- Annotations.Empty,
- Modifiers.Empty,
+ Annotations.Empty(),
+ Modifiers.Empty(),
null,
initializer,
true).assignNoPrototype()
@@ -460,11 +466,10 @@ class ConstructorConverter(private val psiClass: PsiClass,
return ref.getCanonicalText() == "super" && ref.resolve()?.isConstructor() ?: false
}
- private inner open class ReplacingExpressionConverter(
- val parameterUsageReplacementMap: Map,
- val prevExpressionConverter: ExpressionConverter
- ) : ExpressionConverter {
- override fun convertExpression(expression: PsiExpression, converter: Converter): Expression {
+ private /*inner*//*TODO: see KT-5343*/ open class ReplacingExpressionConverter(
+ val owner: ConstructorConverter, val parameterUsageReplacementMap: Map) : SpecialExpressionConverter {
+
+ override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
if (expression is PsiReferenceExpression && expression.getQualifier() == null) {
val replacement = parameterUsageReplacementMap[expression.getReferenceName()]
if (replacement != null) {
@@ -472,14 +477,14 @@ class ConstructorConverter(private val psiClass: PsiClass,
if (target is PsiParameter) {
val scope = target.getDeclarationScope()
// we do not check for exactly this constructor because default values reference parameters in other constructors
- if (scope.isConstructor() && scope.getParent() == psiClass) {
- return Identifier(replacement, converter.typeConverter.variableNullability(target).isNullable(converter.settings))
+ if (scope.isConstructor() && scope.getParent() == owner.psiClass) {
+ return Identifier(replacement, codeConverter.typeConverter.variableNullability(target).isNullable(codeConverter.settings))
}
}
}
}
- return prevExpressionConverter.convertExpression(expression, converter)
+ return null
}
}
}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt
index ff4c745a01c..48082c270de 100644
--- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt
@@ -24,122 +24,54 @@ 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
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.openapi.progress.ProcessCanceledException
+import org.jetbrains.jet.j2k.usageProcessing.UsageProcessing
+import org.jetbrains.jet.j2k.usageProcessing.FieldToPropertyProcessing
-public trait ConversionScope {
- public fun contains(element: PsiElement): Boolean
-}
+class Converter private(private val elementToConvert: PsiElement,
+ val settings: ConverterSettings,
+ val conversionScope: ConversionScope,
+ val referenceSearcher: ReferenceSearcher,
+ private val postProcessor: PostProcessor?,
+ private val state: Converter.State) {
-public class FilesConversionScope(val files: Collection) : ConversionScope {
- override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it }
-}
+ private class State(val specialContext: PsiElement?,
+ val importsToAdd: MutableSet,
+ val lazyElements: MutableList>,
+ val usageProcessings: MutableCollection,
+ val postUnfoldActions: MutableList<() -> Unit>)
-public trait PostProcessor {
- public val contextToAnalyzeIn: PsiElement
- public fun analyzeFile(file: JetFile): BindingContext
- public fun doAdditionalProcessing(file: JetFile)
-}
+ public val project: Project = elementToConvert.getProject()
+ public val typeConverter: TypeConverter = TypeConverter(this)
+ public val annotationConverter: AnnotationConverter = AnnotationConverter(this)
-public class Converter private(val project: Project,
- val settings: ConverterSettings,
- val conversionScope: ConversionScope,
- val referenceSearcher: ReferenceSearcher,
- private val postProcessor: PostProcessor?,
- private val state: Converter.State) {
- private class State(val methodReturnType: PsiType?,
- val expressionConverter: ExpressionConverter,
- val statementConverter: StatementConverter,
- val specialContext: PsiElement?,
- val importList: ImportList?,
- val importsToAdd: MutableCollection?)
+ public val specialContext: PsiElement? = state.specialContext
+ public val importsToAdd: MutableCollection = state.importsToAdd
- val typeConverter: TypeConverter = TypeConverter(this)
-
- val methodReturnType: PsiType? = state.methodReturnType
- val specialContext: PsiElement? = state.specialContext
- val importNames: Set = state.importList?.imports?.mapTo(HashSet()) { it.name } ?: setOf()
- val importsToAdd: MutableCollection? = state.importsToAdd
-
- val annotationConverter = AnnotationConverter(this)
+ private val importList = (elementToConvert as? PsiJavaFile)?.getImportList()?.let { convertImportList(it) }
+ public val importNames: Set = importList?.imports?.mapTo(HashSet()) { it.name } ?: setOf()
class object {
- private val LOG = Logger.getInstance("#org.jetbrains.jet.j2k.Converter")
-
- public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope,
+ public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope,
referenceSearcher: ReferenceSearcher, postProcessor: PostProcessor?): Converter {
- val state = State(null, DefaultExpressionConverter(), DefaultStatementConverter(), null, null, null)
- return Converter(project, settings, conversionScope, referenceSearcher, postProcessor, state)
+ return Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, State(null, LinkedHashSet(), ArrayList(), ArrayList(), ArrayList()))
}
}
- fun withMethodReturnType(methodReturnType: PsiType?): Converter
- = Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
- State(methodReturnType, state.expressionConverter, state.statementConverter, state.specialContext, state.importList, state.importsToAdd))
+ public fun withSpecialContext(context: PsiElement): Converter
+ = Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor,
+ State(context, state.importsToAdd, state.lazyElements, state.usageProcessings, state.postUnfoldActions))
- fun withExpressionConverter(factory: (prevConverter: ExpressionConverter) -> ExpressionConverter): Converter
- = Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
- State(state.methodReturnType, factory(state.expressionConverter), state.statementConverter, state.specialContext, state.importList, state.importsToAdd))
+ /*TODO: it should be private*/ fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
- fun withStatementConverter(factory: (prevConverter: StatementConverter) -> StatementConverter): Converter
- = Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
- State(state.methodReturnType, state.expressionConverter, factory(state.statementConverter), state.specialContext, state.importList, state.importsToAdd))
+ public fun convert(): Element? = convertTopElement(elementToConvert)
- fun withSpecialContext(context: PsiElement): Converter
- = Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
- State(state.methodReturnType, state.expressionConverter, state.statementConverter, context, state.importList, state.importsToAdd))
-
- private fun withImportList(importList: ImportList): Converter
- = Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
- State(state.methodReturnType, state.expressionConverter, state.statementConverter, state.specialContext, importList, state.importsToAdd))
-
- private fun withImportsToAdd(importsToAdd: MutableCollection): Converter
- = Converter(project, settings, conversionScope, referenceSearcher, postProcessor,
- State(state.methodReturnType, state.expressionConverter, state.statementConverter, state.specialContext, state.importList, importsToAdd))
-
- public fun elementToKotlin(element: PsiElement): String {
- try {
- val converted = convertTopElement(element) ?: return ""
- val builder = CodeBuilder(element)
- builder.append(converted)
-
- if (postProcessor != null) {
- try {
- return AfterConversionPass(project, postProcessor).run(builder.result)
- }
- catch(e: ProcessCanceledException) {
- throw e
- }
- catch(t: Throwable) {
- LOG.error(t)
- return builder.result
- }
- }
- else {
- return builder.result
- }
- }
- catch(e: ElementCreationStackTraceRequiredException) {
- // if we got this exception then we need to turn element creation stack traces on to get better diagnostic
- Element.saveCreationStacktraces = true
- try {
- return elementToKotlin(element)
- }
- finally {
- Element.saveCreationStacktraces = false
- }
- }
- }
-
- private fun convertTopElement(element: PsiElement?): Element? = when (element) {
+ private fun convertTopElement(element: PsiElement): Element? = when (element) {
is PsiJavaFile -> convertFile(element)
is PsiClass -> convertClass(element)
is PsiMethod -> convertMethod(element, null, null)
is PsiField -> convertField(element, null)
- is PsiStatement -> convertStatement(element)
- is PsiExpression -> convertExpression(element)
+ is PsiStatement -> createDefaultCodeConverter().convertStatement(element)
+ is PsiExpression -> createDefaultCodeConverter().convertExpression(element)
is PsiImportList -> convertImportList(element)
is PsiImportStatementBase -> convertImport(element, false)
is PsiAnnotation -> annotationConverter.convertAnnotation(element, false, false)
@@ -147,24 +79,49 @@ public class Converter private(val project: Project,
else -> null
}
+ public val usageProcessings: Collection
+ get() = state.usageProcessings
+
+ public fun unfoldLazyElements(codeConverter: CodeConverter) {
+ // we use loop with index because new lazy elements can be added during unfolding
+ var i = 0
+ while (i < state.lazyElements.size) {
+ state.lazyElements[i++].unfold(codeConverter)
+ }
+
+ state.postUnfoldActions.forEach { it() }
+ }
+
+ public fun lazyElement(generator: (CodeConverter) -> TResult): LazyElement {
+ val element = LazyElement(generator)
+ state.lazyElements.add(element)
+ return element
+ }
+
+ public fun addUsageProcessing(processing: UsageProcessing) {
+ state.usageProcessings.add(processing)
+ }
+
+ public fun addPostUnfoldLazyElementsAction(action: () -> Unit) {
+ state.postUnfoldActions.add(action)
+ }
+
private fun convertFile(javaFile: PsiJavaFile): File {
- val importsToAdd = LinkedHashSet()
- var converter = this.withImportsToAdd(importsToAdd)
var convertedChildren = javaFile.getChildren().map {
if (it is PsiImportList) {
- val importList = convertImportList(it)
- converter = converter.withImportList(importList)
+ assert(it == javaFile.getImportList())
importList
}
else {
- converter.convertTopElement(it)
+ convertTopElement(it)
}
}.filterNotNull()
- if (importsToAdd.isNotEmpty()) {
- val importList = convertedChildren.filterIsInstance(javaClass()).first()
- val newImportList = ImportList(importList.imports + importsToAdd.map { Import(it).assignNoPrototype() }).assignPrototypesFrom(importList)
- convertedChildren = convertedChildren.map { if (it == importList) newImportList else it }
+ addPostUnfoldLazyElementsAction {
+ assert(importList != null)
+ if (importsToAdd.isNotEmpty()) {
+ importList!!.imports = importList.imports + importsToAdd.map { Import(it).assignNoPrototype() }
+ }
}
return File(convertedChildren, createMainFunction(javaFile)).assignPrototype(javaFile)
@@ -180,20 +137,15 @@ public class Converter private(val project: Project,
return null
}
- fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody {
- return AnonymousClassBody(ClassBodyConverter(anonymousClass, this).convertBody(),
- anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass)
- }
-
- fun convertAnnotations(owner: PsiModifierListOwner): Annotations
+ public fun convertAnnotations(owner: PsiModifierListOwner): Annotations
= annotationConverter.convertAnnotations(owner)
- fun convertClass(psiClass: PsiClass): Class {
+ public fun convertClass(psiClass: PsiClass): Class {
if (psiClass.isAnnotationType()) {
return convertAnnotationType(psiClass)
}
- val annotations = annotationConverter.convertAnnotations(psiClass)
+ val annotations = convertAnnotations(psiClass)
var modifiers = convertModifiers(psiClass)
val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList())
val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes())
@@ -242,7 +194,7 @@ public class Converter private(val project: Project,
annotationConverter.convertAnnotationMethodDefault(method)).assignPrototype(method, noBlankLinesInheritance)
}
val parameterList = ParameterList(parameters).assignNoPrototype()
- val constructorSignature = PrimaryConstructorSignature(Annotations.Empty, Modifiers.Empty, parameterList).assignNoPrototype()
+ val constructorSignature = PrimaryConstructorSignature(Annotations.Empty(), Modifiers.Empty(), parameterList).assignNoPrototype()
// to convert fields and nested types - they are not allowed in Kotlin but we convert them and let user refactor code
var classBody = ClassBodyConverter(psiClass, this).convertBody()
@@ -252,54 +204,58 @@ public class Converter private(val project: Project,
return Class(psiClass.declarationIdentifier(),
(convertAnnotations(psiClass) + Annotations(listOf(annotationAnnotation))).assignNoPrototype(),
convertModifiers(psiClass).without(Modifier.ABSTRACT),
- TypeParameterList.Empty,
+ TypeParameterList.Empty(),
listOf(),
listOf(),
listOf(),
classBody).assignPrototype(psiClass)
}
- fun convertInitializer(initializer: PsiClassInitializer): Initializer {
- return Initializer(convertBlock(initializer.getBody()), convertModifiers(initializer)).assignPrototype(initializer)
+ public fun convertInitializer(initializer: PsiClassInitializer): Initializer {
+ return Initializer(lazyElement { codeConverter -> codeConverter.convertBlock(initializer.getBody()) },
+ convertModifiers(initializer)).assignPrototype(initializer)
}
- fun convertField(field: PsiField, correction: FieldCorrectionInfo?): Member {
- val annotations = annotationConverter.convertAnnotations(field)
+ public fun convertField(field: PsiField, correction: FieldCorrectionInfo?): Member {
+ val annotations = convertAnnotations(field)
var modifiers = convertModifiers(field)
if (correction != null) {
modifiers = modifiers.without(modifiers.accessModifier()).with(correction.access)
}
- val name = correction?.name ?: field.declarationIdentifier()
+ val name = correction?.identifier ?: field.declarationIdentifier()
val converted = if (field is PsiEnumConstant) {
val argumentList = field.getArgumentList()
EnumConstant(name,
annotations,
modifiers,
typeConverter.convertType(field.getType(), Nullability.NotNull),
- ExpressionList(convertExpressions(argumentList?.getExpressions() ?: array())).assignPrototype(argumentList))
+ lazyElement { codeConverter -> ExpressionList(codeConverter.convertExpressions(argumentList?.getExpressions() ?: array())).assignPrototype(argumentList) })
}
else {
val isVal = isVal(referenceSearcher, field)
val typeToDeclare = variableTypeToDeclare(field,
settings.specifyFieldTypeByDefault || modifiers.isPublic || modifiers.isProtected,
isVal && modifiers.isPrivate)
- val initializer = convertExpression(field.getInitializer(), field.getType())
+ val propertyType = typeToDeclare ?: typeConverter.convertVariableType(field)
+
+ addUsageProcessing(FieldToPropertyProcessing(field, correction?.name ?: field.getName(), propertyType.isNullable))
+
Field(name,
annotations,
modifiers,
- typeToDeclare ?: typeConverter.convertVariableType(field),
- initializer,
+ propertyType,
+ lazyElement { codeConverter -> codeConverter.convertExpression(field.getInitializer(), field.getType()) },
isVal,
typeToDeclare != null,
- initializer.isEmpty && shouldGenerateDefaultInitializer(referenceSearcher, field),
+ shouldGenerateDefaultInitializer(referenceSearcher, field),
if (correction != null) correction.setterAccess else modifiers.accessModifier())
}
return converted.assignPrototype(field)
}
- private fun variableTypeToDeclare(variable: PsiVariable, specifyAlways: Boolean, canChangeType: Boolean): Type? {
+ public fun variableTypeToDeclare(variable: PsiVariable, specifyAlways: Boolean, canChangeType: Boolean): Type? {
fun convertType() = typeConverter.convertVariableType(variable)
if (specifyAlways) return convertType()
@@ -311,27 +267,23 @@ public class Converter private(val project: Project,
if (canChangeType) return null
val convertedType = convertType()
- var initializerType = convertedExpressionType(initializer, variable.getType())
+ var initializerType = createDefaultCodeConverter().convertedExpressionType(initializer, variable.getType())
if (initializerType is ErrorType) return null // do not add explicit type when initializer is not resolved, let user add it if really needed
return if (convertedType == initializerType) null else convertedType
}
- fun convertMethod(method: PsiMethod, membersToRemove: MutableSet?, constructorConverter: ConstructorConverter?): Member? {
- return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove, constructorConverter)?.assignPrototype(method)
- }
-
- private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet?, constructorConverter: ConstructorConverter?): Member? {
+ public fun convertMethod(method: PsiMethod, membersToRemove: MutableSet?, constructorConverter: ConstructorConverter?): Member? {
val returnType = typeConverter.convertMethodReturnType(method)
- val annotations = (annotationConverter.convertAnnotations(method) + convertThrows(method)).assignNoPrototype()
+ val annotations = (convertAnnotations(method) + convertThrows(method)).assignNoPrototype()
var modifiers = convertModifiers(method)
val statementsToInsert = ArrayList()
for (parameter in method.getParameterList().getParameters()) {
if (parameter.hasWriteAccesses(referenceSearcher, method)) {
val variable = LocalVariable(parameter.declarationIdentifier(),
- Annotations.Empty,
- Modifiers.Empty,
+ Annotations.Empty(),
+ Modifiers.Empty(),
null,
parameter.declarationIdentifier(),
false).assignNoPrototype()
@@ -347,8 +299,8 @@ public class Converter private(val project: Project,
}
}
- if (method.isConstructor() && constructorConverter != null) {
- return constructorConverter.convertConstructor(method, annotations, modifiers, membersToRemove!!, postProcessBody)
+ val function = if (method.isConstructor() && constructorConverter != null) {
+ constructorConverter.convertConstructor(method, annotations, modifiers, membersToRemove!!, postProcessBody)
}
else {
val isOverride = isOverride(method)
@@ -368,9 +320,14 @@ public class Converter private(val project: Project,
var params = convertParameterList(method.getParameterList())
val typeParameterList = convertTypeParameterList(method.getTypeParameterList())
- var body = postProcessBody(convertBlock(method.getBody()))
- return Function(method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, body, containingClass?.isInterface() ?: false)
+ var body = lazyElement { (codeConverter: CodeConverter) ->
+ val body = codeConverter.withMethodReturnType(method.getReturnType()).convertBlock(method.getBody())
+ postProcessBody(body)
+ }
+ Function(method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, body, containingClass?.isInterface() ?: false)
}
+
+ return function?.assignPrototype(method)
}
/**
@@ -408,42 +365,7 @@ public class Converter private(val project: Project,
return false
}
- fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = { true }): Block {
- if (block == null) return Block.Empty
-
- val lBrace = LBrace().assignPrototype(block.getLBrace())
- val rBrace = RBrace().assignPrototype(block.getRBrace())
- return Block(block.getStatements().filter(statementFilter).map { convertStatement(it) }, lBrace, rBrace, notEmpty).assignPrototype(block)
- }
-
- fun convertStatement(statement: PsiStatement?): Statement {
- if (statement == null) return Statement.Empty
-
- return state.statementConverter.convertStatement(statement, this).assignPrototype(statement)
- }
-
- fun convertExpressions(expressions: Array): List
- = expressions.map { convertExpression(it) }
-
- fun convertExpression(expression: PsiExpression?): Expression {
- if (expression == null) return Expression.Empty
-
- return state.expressionConverter.convertExpression(expression, this).assignPrototype(expression)
- }
-
- fun convertLocalVariable(variable: PsiLocalVariable): LocalVariable {
- val isVal = variable.hasModifierProperty(PsiModifier.FINAL) ||
- variable.getInitializer() == null/* we do not know actually and prefer val until we have better analysis*/ ||
- !variable.hasWriteAccesses(referenceSearcher, variable.getContainingMethod())
- return LocalVariable(variable.declarationIdentifier(),
- annotationConverter.convertAnnotations(variable),
- convertModifiers(variable),
- variableTypeToDeclare(variable, settings.specifyLocalVariableTypeByDefault, isVal),
- convertExpression(variable.getInitializer(), variable.getType()),
- isVal).assignPrototype(variable)
- }
-
- fun convertCodeReferenceElement(element: PsiJavaCodeReferenceElement, hasExternalQualifier: Boolean, typeArgsConverted: List? = null): ReferenceElement {
+ public fun convertCodeReferenceElement(element: PsiJavaCodeReferenceElement, hasExternalQualifier: Boolean, typeArgsConverted: List? = null): ReferenceElement {
val typeArgs = typeArgsConverted ?: typeConverter.convertTypes(element.getTypeParameters())
if (element.isQualified()) {
@@ -483,19 +405,19 @@ public class Converter private(val project: Project,
return null
}
- fun convertTypeElement(element: PsiTypeElement?): TypeElement
+ public fun convertTypeElement(element: PsiTypeElement?): TypeElement
= TypeElement(if (element == null) ErrorType().assignNoPrototype() else typeConverter.convertType(element.getType())).assignPrototype(element)
private fun convertToNotNullableTypes(types: Array): List
= types.map { typeConverter.convertType(it, Nullability.NotNull) }
- fun convertParameterList(parameterList: PsiParameterList): ParameterList
+ public fun convertParameterList(parameterList: PsiParameterList): ParameterList
= ParameterList(parameterList.getParameters().map { convertParameter(it) }).assignPrototype(parameterList)
- fun convertParameter(parameter: PsiParameter,
+ public fun convertParameter(parameter: PsiParameter,
nullability: Nullability = Nullability.Default,
varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None,
- modifiers: Modifiers = Modifiers.Empty,
+ modifiers: Modifiers = Modifiers.Empty(),
defaultValue: Expression? = null): Parameter {
var type = typeConverter.convertVariableType(parameter)
when (nullability) {
@@ -503,79 +425,16 @@ public class Converter private(val project: Project,
Nullability.Nullable -> type = type.toNullableType()
}
return Parameter(parameter.declarationIdentifier(), type, varValModifier,
- annotationConverter.convertAnnotations(parameter), modifiers, defaultValue).assignPrototype(parameter)
+ convertAnnotations(parameter), modifiers, defaultValue).assignPrototype(parameter)
}
- fun convertExpression(expression: PsiExpression?, expectedType: PsiType?): Expression {
- if (expression == null) return Identifier.Empty
-
- var convertedExpression = convertExpression(expression)
- if (expectedType == null || expectedType == PsiType.VOID) return convertedExpression
-
- val actualType = expression.getType()
- if (actualType == null) return convertedExpression
-
- if (convertedExpression.isNullable &&
- (actualType is PsiPrimitiveType || actualType is PsiClassType && expectedType is PsiPrimitiveType)) {
- convertedExpression = BangBangExpression(convertedExpression).assignNoPrototype()
- }
-
- if (needConversion(actualType, expectedType) && convertedExpression !is LiteralExpression) {
- val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedType.getCanonicalText()]
- if (conversion != null) {
- convertedExpression = MethodCallExpression.buildNotNull(convertedExpression, conversion)
- }
- }
-
- return convertedExpression.assignPrototype(expression)
- }
-
- fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type {
- var convertedExpression = convertExpression(expression)
- val actualType = expression.getType()
- if (actualType == null) return ErrorType()
- var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull)
-
- if (actualType is PsiPrimitiveType && resultType.isNullable ||
- expectedType is PsiPrimitiveType && actualType is PsiClassType) {
- resultType = resultType.toNotNullType()
- }
-
- if (needConversion(actualType, expectedType) && convertedExpression !is LiteralExpression) {
- val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedType.getCanonicalText()]
- if (conversion != null) {
- resultType = typeConverter.convertType(expectedType, Nullability.NotNull)
- }
- }
-
- return resultType
- }
-
- private fun needConversion(actual: PsiType, expected: PsiType): Boolean {
- val expectedStr = expected.getCanonicalText()
- val actualStr = actual.getCanonicalText()
- return expectedStr != actualStr &&
- expectedStr != typeConversionMap[actualStr] &&
- actualStr != typeConversionMap[expectedStr]
- }
-
- private val typeConversionMap: Map = mapOf(
- JAVA_LANG_BYTE to "byte",
- JAVA_LANG_SHORT to "short",
- JAVA_LANG_INTEGER to "int",
- JAVA_LANG_LONG to "long",
- JAVA_LANG_FLOAT to "float",
- JAVA_LANG_DOUBLE to "double",
- JAVA_LANG_CHARACTER to "char"
- )
-
- fun convertIdentifier(identifier: PsiIdentifier?): Identifier {
- if (identifier == null) return Identifier.Empty
+ public fun convertIdentifier(identifier: PsiIdentifier?): Identifier {
+ if (identifier == null) return Identifier.Empty()
return Identifier(identifier.getText()!!).assignPrototype(identifier)
}
- fun convertModifiers(owner: PsiModifierListOwner): Modifiers {
+ public fun convertModifiers(owner: PsiModifierListOwner): Modifiers {
return Modifiers(MODIFIERS_MAP.filter { owner.hasModifierProperty(it.first) }.map { it.second })
.assignPrototype(owner.getModifierList(), CommentsAndSpacesInheritance(blankLinesBefore = false))
}
@@ -592,7 +451,7 @@ public class Converter private(val project: Project,
val types = throwsList.getReferencedTypes()
val refElements = throwsList.getReferenceElements()
assert(types.size == refElements.size)
- if (types.isEmpty()) return Annotations.Empty
+ if (types.isEmpty()) return Annotations.Empty()
val arguments = types.indices.map {
val convertedType = typeConverter.convertType(types[it], Nullability.NotNull)
null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(convertedType)).assignPrototype(refElements[it])
diff --git a/j2k/src/org/jetbrains/jet/j2k/ExpressionConverter.kt b/j2k/src/org/jetbrains/jet/j2k/ExpressionConverter.kt
index 6d416b83b6d..07b2e13f59d 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ExpressionConverter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ExpressionConverter.kt
@@ -39,20 +39,30 @@ import org.jetbrains.jet.asJava.KotlinLightField
import org.jetbrains.jet.lang.psi.JetObjectDeclaration
trait ExpressionConverter {
- fun convertExpression(expression: PsiExpression, converter: Converter): Expression
+ fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression
+}
+
+trait SpecialExpressionConverter {
+ fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression?
+}
+
+fun ExpressionConverter.withSpecialConverter(specialConverter: SpecialExpressionConverter): ExpressionConverter {
+ return object: ExpressionConverter {
+ override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter)
+ = specialConverter.convertExpression(expression, codeConverter) ?: this@withSpecialConverter.convertExpression(expression, codeConverter)
+ }
}
class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
- private var _converter: Converter? = null
+ private var _codeConverter: CodeConverter? = null
private var result: Expression = Expression.Empty
- private val converter: Converter get() {
- return _converter!!
- }
- private val typeConverter: TypeConverter get() = converter.typeConverter
+ private val codeConverter: CodeConverter get() = _codeConverter!!
+ private val typeConverter: TypeConverter get() = codeConverter.typeConverter
+ private val converter: Converter get() = codeConverter.converter
- override fun convertExpression(expression: PsiExpression, converter: Converter): Expression {
- this._converter = converter
+ override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression {
+ this._codeConverter = codeConverter
result = Expression.Empty
expression.accept(this)
@@ -62,8 +72,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
override fun visitArrayAccessExpression(expression: PsiArrayAccessExpression) {
val assignment = PsiTreeUtil.getParentOfType(expression, javaClass())
val lvalue = assignment != null && expression == assignment.getLExpression();
- result = ArrayAccessExpression(converter.convertExpression(expression.getArrayExpression()),
- converter.convertExpression(expression.getIndexExpression()),
+ result = ArrayAccessExpression(codeConverter.convertExpression(expression.getArrayExpression()),
+ codeConverter.convertExpression(expression.getIndexExpression()),
lvalue)
}
@@ -71,7 +81,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val expressionType = typeConverter.convertType(expression.getType())
assert(expressionType is ArrayType, "Array initializer must have array type")
result = createArrayInitializerExpression(expressionType as ArrayType,
- converter.convertExpressions(expression.getInitializers()),
+ codeConverter.convertExpressions(expression.getInitializers()),
needExplicitType = true/*TODO: it's often redundant*/)
}
@@ -87,8 +97,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
else -> ""
}
- val lhs = converter.convertExpression(expression.getLExpression())
- val rhs = converter.convertExpression(expression.getRExpression()!!, expression.getLExpression().getType())
+ val lhs = codeConverter.convertExpression(expression.getLExpression())
+ val rhs = codeConverter.convertExpression(expression.getRExpression()!!, expression.getLExpression().getType())
if (!secondOp.isEmpty()) {
result = AssignmentExpression(lhs, BinaryExpression(lhs, rhs, secondOp).assignNoPrototype(), " = ")
}
@@ -107,8 +117,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
else -> null
}
- val lhs = converter.convertExpression(expression.getLOperand(), operandsExpectedType)
- val rhs = converter.convertExpression(expression.getROperand(), operandsExpectedType)
+ val lhs = codeConverter.convertExpression(expression.getLOperand(), operandsExpectedType)
+ val rhs = codeConverter.convertExpression(expression.getROperand(), operandsExpectedType)
if (expression.getOperationTokenType() == JavaTokenType.GTGTGT) {
result = MethodCallExpression.buildNotNull(lhs, "ushr", listOf(rhs))
}
@@ -147,18 +157,18 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val condition = expression.getCondition()
val type = condition.getType()
val expr = if (type != null)
- converter.convertExpression(condition, type)
+ codeConverter.convertExpression(condition, type)
else
- converter.convertExpression(condition)
+ codeConverter.convertExpression(condition)
result = IfStatement(expr,
- converter.convertExpression(expression.getThenExpression()),
- converter.convertExpression(expression.getElseExpression()),
+ codeConverter.convertExpression(expression.getThenExpression()),
+ codeConverter.convertExpression(expression.getElseExpression()),
expression.isInSingleLine())
}
override fun visitInstanceOfExpression(expression: PsiInstanceOfExpression) {
val checkType = expression.getCheckType()
- result = IsOperator(converter.convertExpression(expression.getOperand()),
+ result = IsOperator(codeConverter.convertExpression(expression.getOperand()),
converter.convertTypeElement(checkType))
}
@@ -196,7 +206,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val methodExpr = expression.getMethodExpression()
val arguments = expression.getArgumentList().getExpressions()
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(codeConverter.settings) else false
val typeArguments = convertTypeArguments(expression)
if (target is KotlinLightMethod) {
@@ -213,12 +223,12 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val isExtension = property.isExtensionDeclaration()
val propertyAccess = if (isTopLevel) {
if (isExtension)
- QualifiedExpression(converter.convertExpression(arguments.firstOrNull()), propertyName).assignNoPrototype()
+ QualifiedExpression(codeConverter.convertExpression(arguments.firstOrNull()), propertyName).assignNoPrototype()
else
propertyName
}
else {
- QualifiedExpression(converter.convertExpression(methodExpr.getQualifierExpression()), propertyName).assignNoPrototype()
+ QualifiedExpression(codeConverter.convertExpression(methodExpr.getQualifierExpression()), propertyName).assignNoPrototype()
}
when(if (isExtension) parameterCount - 1 else parameterCount) {
@@ -228,7 +238,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
1 /* setter */ -> {
- val argument = converter.convertExpression(arguments[if (isExtension) 1 else 0])
+ val argument = codeConverter.convertExpression(arguments[if (isExtension) 1 else 0])
result = AssignmentExpression(propertyAccess, argument, "=")
return
}
@@ -238,7 +248,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
else if (origin is JetFunction) {
if (isTopLevel) {
result = if (origin.isExtensionDeclaration()) {
- val qualifier = converter.convertExpression(arguments.firstOrNull())
+ val qualifier = codeConverter.convertExpression(arguments.firstOrNull())
MethodCallExpression.build(qualifier,
origin.getName()!!,
convertArguments(expression, isExtension = true),
@@ -260,7 +270,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
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, typeArguments, converter)
+ val converted = specialMethod.convertCall(methodExpr.getQualifierExpression(), arguments, typeArguments, codeConverter)
if (converted != null) {
result = converted
return
@@ -268,7 +278,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
}
- result = MethodCallExpression(converter.convertExpression(methodExpr),
+ result = MethodCallExpression(codeConverter.convertExpression(methodExpr),
convertArguments(expression),
typeArguments,
isNullable)
@@ -297,12 +307,12 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
override fun visitNewExpression(expression: PsiNewExpression) {
if (expression.getArrayInitializer() != null) {
- result = converter.convertExpression(expression.getArrayInitializer())
+ result = codeConverter.convertExpression(expression.getArrayInitializer())
}
else if (expression.getArrayDimensions().size > 0 && expression.getType() is PsiArrayType) {
result = ArrayWithoutInitializationExpression(
typeConverter.convertType(expression.getType(), Nullability.NotNull) as ArrayType,
- converter.convertExpressions(expression.getArrayDimensions()))
+ codeConverter.convertExpressions(expression.getArrayDimensions()))
}
else {
val anonymousClass = expression.getAnonymousClass()
@@ -311,22 +321,22 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val classRefConverted = if (classRef != null) converter.convertCodeReferenceElement(classRef, hasExternalQualifier = qualifier != null) else null
result = NewClassExpression(classRefConverted,
convertArguments(expression),
- converter.convertExpression(qualifier),
- if (anonymousClass != null) converter.convertAnonymousClassBody(anonymousClass) else null)
+ codeConverter.convertExpression(qualifier),
+ if (anonymousClass != null) codeConverter.convertAnonymousClassBody(anonymousClass) else null)
}
}
override fun visitParenthesizedExpression(expression: PsiParenthesizedExpression) {
- result = ParenthesizedExpression(converter.convertExpression(expression.getExpression()))
+ result = ParenthesizedExpression(codeConverter.convertExpression(expression.getExpression()))
}
override fun visitPostfixExpression(expression: PsiPostfixExpression) {
result = PostfixOperator(getOperatorString(expression.getOperationSign().getTokenType()),
- converter.convertExpression(expression.getOperand()))
+ codeConverter.convertExpression(expression.getOperand()))
}
override fun visitPrefixExpression(expression: PsiPrefixExpression) {
- val operand = converter.convertExpression(expression.getOperand(), expression.getOperand()!!.getType())
+ val operand = codeConverter.convertExpression(expression.getOperand(), expression.getOperand()!!.getType())
val token = expression.getOperationTokenType()
if (token == JavaTokenType.TILDE) {
result = MethodCallExpression.buildNotNull(operand, "inv")
@@ -342,7 +352,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
override fun visitReferenceExpression(expression: PsiReferenceExpression) {
val referenceName = expression.getReferenceName()!!
val target = expression.getReference()?.resolve()
- val isNullable = target is PsiVariable && typeConverter.variableNullability(target).isNullable(converter.settings)
+ val isNullable = target is PsiVariable && typeConverter.variableNullability(target).isNullable(codeConverter.settings)
val qualifier = expression.getQualifierExpression()
var identifier = Identifier(referenceName, isNullable).assignNoPrototype()
@@ -351,7 +361,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
else if (qualifier != null) {
if (target is KotlinLightField<*, *> && target.getOrigin() is JetObjectDeclaration) {
- result = converter.convertExpression(qualifier)
+ result = codeConverter.convertExpression(qualifier)
return
}
}
@@ -382,19 +392,19 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
}
- result = if (qualifier != null) QualifiedExpression(converter.convertExpression(qualifier), identifier) else identifier
+ result = if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
}
override fun visitSuperExpression(expression: PsiSuperExpression) {
val psiQualifier = expression.getQualifier()
val qualifier = psiQualifier?.getReferenceName()
- result = SuperExpression(if (qualifier != null) Identifier(qualifier).assignPrototype(psiQualifier) else Identifier.Empty)
+ result = SuperExpression(if (qualifier != null) Identifier(qualifier).assignPrototype(psiQualifier) else Identifier.Empty())
}
override fun visitThisExpression(expression: PsiThisExpression) {
val psiQualifier = expression.getQualifier()
val qualifier = psiQualifier?.getReferenceName()
- result = ThisExpression(if (qualifier != null) Identifier(qualifier).assignPrototype(psiQualifier) else Identifier.Empty)
+ result = ThisExpression(if (qualifier != null) Identifier(qualifier).assignPrototype(psiQualifier) else Identifier.Empty())
}
override fun visitTypeCastExpression(expression: PsiTypeCastExpression) {
@@ -404,15 +414,15 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val typeText = castType.getType().getCanonicalText()
val typeConversion = PRIMITIVE_TYPE_CONVERSIONS[typeText]
if (operandType is PsiPrimitiveType && typeConversion != null) {
- result = MethodCallExpression.buildNotNull(converter.convertExpression(operand), typeConversion)
+ result = MethodCallExpression.buildNotNull(codeConverter.convertExpression(operand), typeConversion)
}
else {
- result = TypeCastExpression(typeConverter.convertType(castType.getType()), converter.convertExpression(operand))
+ result = TypeCastExpression(typeConverter.convertType(castType.getType()), codeConverter.convertExpression(operand))
}
}
override fun visitPolyadicExpression(expression: PsiPolyadicExpression) {
- val args = expression.getOperands().map { converter.convertExpression(it, expression.getType()) }
+ val args = expression.getOperands().map { codeConverter.convertExpression(it, expression.getType()) }
result = PolyadicExpression(args, getOperatorString(expression.getOperationTokenType()))
}
@@ -428,14 +438,14 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
return if (arguments.size == expectedTypes.size())
(0..arguments.lastIndex).map { i ->
val argument = arguments[i]
- val converted = converter.convertExpression(argument, expectedTypes[i])
+ val converted = codeConverter.convertExpression(argument, expectedTypes[i])
if (parameters != null && i == arguments.lastIndex && parameters[i].isVarArgs() && argument.getType() is PsiArrayType)
StarExpression(converted).assignNoPrototype()
else
converted
}
else
- arguments.map { converter.convertExpression(it) }
+ arguments.map { codeConverter.convertExpression(it) }
}
private fun getOperatorString(tokenType: IElementType): String {
diff --git a/j2k/src/org/jetbrains/jet/j2k/ForConverter.kt b/j2k/src/org/jetbrains/jet/j2k/ForConverter.kt
index a9354a2f0ec..e10be4adb41 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ForConverter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ForConverter.kt
@@ -55,7 +55,11 @@ import org.jetbrains.jet.j2k.ast.MethodCallExpression
import org.jetbrains.jet.j2k.ast.LambdaExpression
import org.jetbrains.jet.j2k.ast.Statement
-class ForConverter(private val statement: PsiForStatement, private val converter: Converter) {
+class ForConverter(private val statement: PsiForStatement, private val codeConverter: CodeConverter) {
+ private val referenceSearcher = codeConverter.converter.referenceSearcher
+ private val settings = codeConverter.settings
+ private val project = codeConverter.converter.project
+
private val initialization = statement.getInitialization()
private val update = statement.getUpdate()
private val condition = statement.getCondition()
@@ -70,11 +74,11 @@ class ForConverter(private val statement: PsiForStatement, private val converter
val condition = statement.getCondition()
val body = statement.getBody()
- val initializationConverted = converter.convertStatement(initialization)
- val updateConverted = converter.convertStatement(update)
+ val initializationConverted = codeConverter.convertStatement(initialization)
+ val updateConverted = codeConverter.convertStatement(update)
val whileBody = if (updateConverted.isEmpty) {
- converter.convertStatementOrBlock(body)
+ codeConverter.convertStatementOrBlock(body)
}
else if (body is PsiBlockStatement) {
val nameConflict = initialization is PsiDeclarationStatement && initialization.getDeclaredElements().any { loopVar ->
@@ -86,21 +90,21 @@ class ForConverter(private val statement: PsiForStatement, private val converter
}
if (nameConflict) {
- val statements = listOf(converter.convertStatement(body), updateConverted)
+ val statements = listOf(codeConverter.convertStatement(body), updateConverted)
Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype()
}
else {
- val block = converter.convertBlock(body.getCodeBlock(), true)
+ val block = codeConverter.convertBlock(body.getCodeBlock(), true)
Block(block.statements + listOf(updateConverted), block.lBrace, block.rBrace, true).assignPrototypesFrom(block)
}
}
else {
- val statements = listOf(converter.convertStatement(body), updateConverted)
+ val statements = listOf(codeConverter.convertStatement(body), updateConverted)
Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype()
}
val whileStatement = WhileStatement(
- if (condition != null) converter.convertExpression(condition) else LiteralExpression("true").assignNoPrototype(),
+ if (condition != null) codeConverter.convertExpression(condition) else LiteralExpression("true").assignNoPrototype(),
whileBody,
statement.isInSingleLine()).assignNoPrototype()
if (initializationConverted.isEmpty) return whileStatement
@@ -114,8 +118,8 @@ class ForConverter(private val statement: PsiForStatement, private val converter
if (initialization is PsiDeclarationStatement) {
val loopVar = initialization.getDeclaredElements().singleOrNull2() as? PsiLocalVariable
if (loopVar != null
- && !loopVar.hasWriteAccesses(converter.referenceSearcher, body)
- && !loopVar.hasWriteAccesses(converter.referenceSearcher, condition)
+ && !loopVar.hasWriteAccesses(referenceSearcher, body)
+ && !loopVar.hasWriteAccesses(referenceSearcher, condition)
&& condition is PsiBinaryExpression) {
val operationTokenType = condition.getOperationTokenType()
val lowerBound = condition.getLOperand()
@@ -128,11 +132,11 @@ class ForConverter(private val statement: PsiForStatement, private val converter
if (start != null &&
(update as? PsiExpressionStatement)?.getExpression()?.isVariablePlusPlus(loopVar) ?: false) {
val range = forIterationRange(start, upperBound, operationTokenType).assignNoPrototype()
- val explicitType = if (converter.settings.specifyLocalVariableTypeByDefault)
+ val explicitType = if (settings.specifyLocalVariableTypeByDefault)
PrimitiveType(Identifier("Int").assignNoPrototype()).assignNoPrototype()
else
null
- return ForeachStatement(loopVar.declarationIdentifier(), explicitType, range, converter.convertStatementOrBlock(body), statement.isInSingleLine())
+ return ForeachStatement(loopVar.declarationIdentifier(), explicitType, range, codeConverter.convertStatementOrBlock(body), statement.isInSingleLine())
}
}
}
@@ -160,10 +164,10 @@ class ForConverter(private val statement: PsiForStatement, private val converter
if (methodExpr is PsiReferenceExpression && methodExpr.getReferenceName() == "size") {
val qualifier = methodExpr.getQualifierExpression()
if (qualifier is PsiReferenceExpression /* we don't convert to .indices if qualifier is method call or something because of possible side effects */) {
- val listType = PsiElementFactory.SERVICE.getInstance(converter.project).createTypeByFQClassName(CommonClassNames.JAVA_UTIL_LIST)
+ val listType = PsiElementFactory.SERVICE.getInstance(project).createTypeByFQClassName(CommonClassNames.JAVA_UTIL_LIST)
val qualifierType = qualifier.getType()
if (qualifierType != null && listType.isAssignableFrom(qualifierType)) {
- return QualifiedExpression(converter.convertExpression(qualifier), Identifier("indices", false).assignNoPrototype())
+ return QualifiedExpression(codeConverter.convertExpression(qualifier), Identifier("indices", false).assignNoPrototype())
}
}
}
@@ -174,17 +178,17 @@ class ForConverter(private val statement: PsiForStatement, private val converter
&& upperBound.getReferenceName() == "length") {
val qualifier = upperBound.getQualifierExpression()
if (qualifier is PsiReferenceExpression && qualifier.getType() is PsiArrayType) {
- return QualifiedExpression(converter.convertExpression(qualifier), Identifier("indices", false).assignNoPrototype())
+ return QualifiedExpression(codeConverter.convertExpression(qualifier), Identifier("indices", false).assignNoPrototype())
}
}
}
- val end = converter.convertExpression(upperBound)
+ val end = codeConverter.convertExpression(upperBound)
val endExpression = if (comparisonTokenType == JavaTokenType.LT)
BinaryExpression(end, LiteralExpression("1").assignNoPrototype(), "-").assignNoPrototype()
else
end
- return RangeExpression(converter.convertExpression(start), endExpression)
+ return RangeExpression(codeConverter.convertExpression(start), endExpression)
}
}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt
new file mode 100644
index 00000000000..e4bceb4c36d
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.j2k
+
+import com.intellij.psi.PsiElement
+import com.intellij.openapi.progress.ProcessCanceledException
+import org.jetbrains.jet.j2k.ast.Element
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiJavaFile
+import org.jetbrains.jet.lang.psi.JetFile
+import org.jetbrains.jet.lang.resolve.BindingContext
+import com.intellij.openapi.diagnostic.Logger
+import org.jetbrains.jet.j2k.usageProcessing.UsageProcessingExpressionConverter
+
+public trait ConversionScope {
+ public fun contains(element: PsiElement): Boolean
+}
+
+public class FilesConversionScope(val files: Collection) : ConversionScope {
+ override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it }
+}
+
+public trait PostProcessor {
+ public val contextToAnalyzeIn: PsiElement
+ public fun analyzeFile(file: JetFile): BindingContext
+ public fun doAdditionalProcessing(file: JetFile)
+}
+
+public class JavaToKotlinConverter(private val project: Project,
+ private val settings: ConverterSettings,
+ private val conversionScope: ConversionScope,
+ private val referenceSearcher: ReferenceSearcher,
+ private val postProcessor: PostProcessor?) {
+ private val LOG = Logger.getInstance("#org.jetbrains.jet.j2k.JavaToKotlinConverter")
+
+ //TODO: run not for one element when multiple files
+ public fun elementToKotlin(psiElement: PsiElement): String {
+ try {
+ val converter = Converter.create(psiElement, settings, conversionScope, referenceSearcher, postProcessor)
+ val element = converter.convert() ?: return ""
+
+ val codeConverter = converter.createDefaultCodeConverter()
+ .withSpecialExpressionConverter(UsageProcessingExpressionConverter(converter.usageProcessings))
+
+ converter.unfoldLazyElements(codeConverter)
+
+ val builder = CodeBuilder(psiElement)
+ builder.append(element)
+
+ if (postProcessor != null) {
+ try {
+ return AfterConversionPass(project, postProcessor).run(builder.result)
+ }
+ catch(e: ProcessCanceledException) {
+ throw e
+ }
+ catch(t: Throwable) {
+ LOG.error(t)
+ return builder.result
+ }
+ }
+ else {
+ return builder.result
+ }
+ }
+ catch(e: ElementCreationStackTraceRequiredException) {
+ // if we got this exception then we need to turn element creation stack traces on to get better diagnostic
+ Element.saveCreationStacktraces = true
+ try {
+ return elementToKotlin(psiElement)
+ }
+ finally {
+ Element.saveCreationStacktraces = false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt
index 522674fbf0c..006f77ed77d 100644
--- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt
@@ -90,7 +90,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)), EmptyReferenceSearcher, null)
+ val converter = JavaToKotlinConverter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file)), EmptyReferenceSearcher, null)
return prettify(converter.elementToKotlin(file))
}
return ""
diff --git a/j2k/src/org/jetbrains/jet/j2k/SpecialMethod.kt b/j2k/src/org/jetbrains/jet/j2k/SpecialMethod.kt
index a23780ed2da..d4c48fe1be5 100644
--- a/j2k/src/org/jetbrains/jet/j2k/SpecialMethod.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/SpecialMethod.kt
@@ -33,47 +33,47 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
override fun matches(method: PsiMethod)
= super.matches(method) && method.getParameterList().getParameters().single().getType().getCanonicalText() == JAVA_LANG_OBJECT
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter): Expression? {
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? {
if (qualifier == null || qualifier is PsiSuperExpression) return null
- return BinaryExpression(converter.convertExpression(qualifier), converter.convertExpression(arguments.single()), "==")
+ return BinaryExpression(codeConverter.convertExpression(qualifier), codeConverter.convertExpression(arguments.single()), "==")
}
}
OBJECT_GET_CLASS: SpecialMethod("java.lang.Object", "getClass", 0) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter): Expression {
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression {
val identifier = Identifier("javaClass", false).assignNoPrototype()
- return if (qualifier != null) QualifiedExpression(converter.convertExpression(qualifier), identifier) else identifier
+ return if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
}
}
OBJECTS_EQUALS: SpecialMethod("java.util.Objects", "equals", 2) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter)
- = BinaryExpression(converter.convertExpression(arguments[0]), converter.convertExpression(arguments[1]), "==")
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter)
+ = BinaryExpression(codeConverter.convertExpression(arguments[0]), codeConverter.convertExpression(arguments[1]), "==")
}
COLLECTIONS_EMPTY_LIST: SpecialMethod("java.util.Collections", "emptyList", 0) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter)
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "listOf", listOf(), typeArgumentsConverted, false)
}
COLLECTIONS_EMPTY_SET: SpecialMethod("java.util.Collections", "emptySet", 0) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter)
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "setOf", listOf(), typeArgumentsConverted, false)
}
COLLECTIONS_EMPTY_MAP: SpecialMethod("java.util.Collections", "emptyMap", 0) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter)
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "mapOf", listOf(), typeArgumentsConverted, false)
}
COLLECTIONS_SINGLETON_LIST: SpecialMethod("java.util.Collections", "singletonList", 1) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter)
- = MethodCallExpression.build(null, "listOf", listOf(converter.convertExpression(arguments.single())), typeArgumentsConverted, false)
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter)
+ = MethodCallExpression.build(null, "listOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false)
}
COLLECTIONS_SINGLETON: SpecialMethod("java.util.Collections", "singleton", 1) {
- override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter)
- = MethodCallExpression.build(null, "setOf", listOf(converter.convertExpression(arguments.single())), typeArgumentsConverted, false)
+ override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter)
+ = MethodCallExpression.build(null, "setOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false)
}
open fun matches(method: PsiMethod): Boolean {
@@ -82,5 +82,5 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
return method.getParameterList().getParametersCount() == parameterCount
}
- abstract fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, converter: Converter): Expression?
+ abstract fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression?
}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/StatementConverter.kt b/j2k/src/org/jetbrains/jet/j2k/StatementConverter.kt
index fb48f4d4976..51cb8001628 100644
--- a/j2k/src/org/jetbrains/jet/j2k/StatementConverter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/StatementConverter.kt
@@ -21,19 +21,18 @@ import org.jetbrains.jet.j2k.ast.*
import java.util.ArrayList
trait StatementConverter {
- fun convertStatement(statement: PsiStatement, converter: Converter): Statement
+ fun convertStatement(statement: PsiStatement, codeConverter: CodeConverter): Statement
}
class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
- private var _converter: Converter? = null
+ private var _codeConverter: CodeConverter? = null
private var result: Statement = Statement.Empty
- private val converter: Converter get() {
- return _converter!!
- }
+ private val codeConverter: CodeConverter get() = _codeConverter!!
+ private val converter: Converter get() = codeConverter.converter
- override fun convertStatement(statement: PsiStatement, converter: Converter): Statement {
- this._converter = converter
+ override fun convertStatement(statement: PsiStatement, codeConverter: CodeConverter): Statement {
+ this._codeConverter = codeConverter
result = Statement.Empty
statement.accept(this)
@@ -42,12 +41,12 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
override fun visitAssertStatement(statement: PsiAssertStatement) {
val descriptionExpr = statement.getAssertDescription()
- val condition = converter.convertExpression(statement.getAssertCondition())
+ val condition = codeConverter.convertExpression(statement.getAssertCondition())
if (descriptionExpr == null) {
result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition))
}
else {
- val description = converter.convertExpression(descriptionExpr)
+ val description = codeConverter.convertExpression(descriptionExpr)
if (descriptionExpr is PsiLiteralExpression) {
result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition, description))
}
@@ -60,13 +59,13 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
}
override fun visitBlockStatement(statement: PsiBlockStatement) {
- val block = converter.convertBlock(statement.getCodeBlock())
+ val block = codeConverter.convertBlock(statement.getCodeBlock())
result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block).assignNoPrototype())
}
override fun visitBreakStatement(statement: PsiBreakStatement) {
if (statement.getLabelIdentifier() == null) {
- result = BreakStatement(Identifier.Empty)
+ result = BreakStatement(Identifier.Empty())
}
else {
result = BreakStatement(converter.convertIdentifier(statement.getLabelIdentifier()))
@@ -75,7 +74,7 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
override fun visitContinueStatement(statement: PsiContinueStatement) {
if (statement.getLabelIdentifier() == null) {
- result = ContinueStatement(Identifier.Empty)
+ result = ContinueStatement(Identifier.Empty())
}
else {
result = ContinueStatement(converter.convertIdentifier(statement.getLabelIdentifier()))
@@ -85,7 +84,7 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
override fun visitDeclarationStatement(statement: PsiDeclarationStatement) {
result = DeclarationStatement(statement.getDeclaredElements().map {
when (it) {
- is PsiLocalVariable -> converter.convertLocalVariable(it)
+ is PsiLocalVariable -> codeConverter.convertLocalVariable(it)
is PsiClass -> converter.convertClass(it)
else -> Element.Empty //what else can be here?
}
@@ -95,73 +94,73 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
override fun visitDoWhileStatement(statement: PsiDoWhileStatement) {
val condition = statement.getCondition()
val expression = if (condition != null && condition.getType() != null)
- converter.convertExpression(condition, condition.getType())
+ codeConverter.convertExpression(condition, condition.getType())
else
- converter.convertExpression(condition)
- result = DoWhileStatement(expression, converter.convertStatementOrBlock(statement.getBody()), statement.isInSingleLine())
+ codeConverter.convertExpression(condition)
+ result = DoWhileStatement(expression, codeConverter.convertStatementOrBlock(statement.getBody()), statement.isInSingleLine())
}
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
- result = converter.convertExpression(statement.getExpression())
+ result = codeConverter.convertExpression(statement.getExpression())
}
override fun visitExpressionListStatement(statement: PsiExpressionListStatement) {
- result = ExpressionListStatement(converter.convertExpressions(statement.getExpressionList().getExpressions()))
+ result = ExpressionListStatement(codeConverter.convertExpressions(statement.getExpressionList().getExpressions()))
}
override fun visitForStatement(statement: PsiForStatement) {
- result = ForConverter(statement, converter).execute()
+ result = ForConverter(statement, codeConverter).execute()
}
override fun visitForeachStatement(statement: PsiForeachStatement) {
- val iteratorExpr = converter.convertExpression(statement.getIteratedValue())
+ val iteratorExpr = codeConverter.convertExpression(statement.getIteratedValue())
val iterator = if (iteratorExpr.isNullable) BangBangExpression(iteratorExpr).assignNoPrototype() else iteratorExpr
val iterationParameter = statement.getIterationParameter()
result = ForeachStatement(iterationParameter.declarationIdentifier(),
- if (converter.settings.specifyLocalVariableTypeByDefault) converter.typeConverter.convertVariableType(iterationParameter) else null,
+ if (codeConverter.settings.specifyLocalVariableTypeByDefault) codeConverter.typeConverter.convertVariableType(iterationParameter) else null,
iterator,
- converter.convertStatementOrBlock(statement.getBody()),
+ codeConverter.convertStatementOrBlock(statement.getBody()),
statement.isInSingleLine())
}
override fun visitIfStatement(statement: PsiIfStatement) {
val condition = statement.getCondition()
- val expression = converter.convertExpression(condition, PsiType.BOOLEAN)
+ val expression = codeConverter.convertExpression(condition, PsiType.BOOLEAN)
result = IfStatement(expression,
- converter.convertStatementOrBlock(statement.getThenBranch()),
- converter.convertStatementOrBlock(statement.getElseBranch()),
+ codeConverter.convertStatementOrBlock(statement.getThenBranch()),
+ codeConverter.convertStatementOrBlock(statement.getElseBranch()),
statement.isInSingleLine())
}
override fun visitLabeledStatement(statement: PsiLabeledStatement) {
result = LabelStatement(converter.convertIdentifier(statement.getLabelIdentifier()),
- converter.convertStatement(statement.getStatement()))
+ codeConverter.convertStatement(statement.getStatement()))
}
override fun visitSwitchLabelStatement(statement: PsiSwitchLabelStatement) {
result = if (statement.isDefaultCase())
ElseWhenEntrySelector()
else
- ValueWhenEntrySelector(converter.convertExpression(statement.getCaseValue()))
+ ValueWhenEntrySelector(codeConverter.convertExpression(statement.getCaseValue()))
}
override fun visitSwitchStatement(statement: PsiSwitchStatement) {
- result = SwitchConverter(converter).convert(statement)
+ result = SwitchConverter(codeConverter).convert(statement)
}
override fun visitSynchronizedStatement(statement: PsiSynchronizedStatement) {
- result = SynchronizedStatement(converter.convertExpression(statement.getLockExpression()),
- converter.convertBlock(statement.getBody()))
+ result = SynchronizedStatement(codeConverter.convertExpression(statement.getLockExpression()),
+ codeConverter.convertBlock(statement.getBody()))
}
override fun visitThrowStatement(statement: PsiThrowStatement) {
- result = ThrowStatement(converter.convertExpression(statement.getException()))
+ result = ThrowStatement(codeConverter.convertExpression(statement.getException()))
}
override fun visitTryStatement(tryStatement: PsiTryStatement) {
val tryBlock = tryStatement.getTryBlock()
val catchesConverted = convertCatches(tryStatement)
- val finallyConverted = converter.convertBlock(tryStatement.getFinallyBlock())
+ val finallyConverted = codeConverter.convertBlock(tryStatement.getFinallyBlock())
val resourceList = tryStatement.getResourceList()
if (resourceList != null) {
@@ -172,13 +171,13 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
}
}
- result = TryStatement(converter.convertBlock(tryBlock), catchesConverted, finallyConverted)
+ result = TryStatement(codeConverter.convertBlock(tryBlock), catchesConverted, finallyConverted)
}
private fun convertCatches(tryStatement: PsiTryStatement): List {
val catches = ArrayList()
for ((block, parameter) in tryStatement.getCatchBlocks().zip(tryStatement.getCatchBlockParameters())) {
- val blockConverted = converter.convertBlock(block)
+ val blockConverted = codeConverter.convertBlock(block)
val annotations = converter.convertAnnotations(parameter)
val parameterType = parameter.getType()
val types = if (parameterType is PsiDisjunctionType)
@@ -186,12 +185,12 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
else
listOf(parameterType)
for (t in types) {
- var convertedType = converter.typeConverter.convertType(t, Nullability.NotNull)
+ var convertedType = codeConverter.typeConverter.convertType(t, Nullability.NotNull)
val convertedParameter = Parameter(parameter.declarationIdentifier(),
convertedType,
Parameter.VarValModifier.None,
annotations,
- Modifiers.Empty).assignPrototype(parameter)
+ Modifiers.Empty()).assignPrototype(parameter)
catches.add(CatchStatement(convertedParameter, blockConverted).assignNoPrototype())
}
}
@@ -200,13 +199,13 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
private fun convertTryWithResources(tryBlock: PsiCodeBlock?, resourceVariables: List, catchesConverted: List, finallyConverted: Block): Statement {
var wrapResultStatement: (Expression) -> Statement = { it }
- var converterForBody = converter
+ var converterForBody = codeConverter
var block = converterForBody.convertBlock(tryBlock)
var expression: Expression = Expression.Empty
for (variable in resourceVariables.reverse()) {
val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), block)
- expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda)
+ expression = MethodCallExpression.build(codeConverter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda)
expression.assignNoPrototype()
block = Block(listOf(expression), LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
}
@@ -236,19 +235,19 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
override fun visitWhileStatement(statement: PsiWhileStatement) {
val condition = statement.getCondition()
val expression = if (condition?.getType() != null)
- converter.convertExpression(condition, condition!!.getType())
+ codeConverter.convertExpression(condition, condition!!.getType())
else
- converter.convertExpression(condition)
- result = WhileStatement(expression, converter.convertStatementOrBlock(statement.getBody()), statement.isInSingleLine())
+ codeConverter.convertExpression(condition)
+ result = WhileStatement(expression, codeConverter.convertStatementOrBlock(statement.getBody()), statement.isInSingleLine())
}
override fun visitReturnStatement(statement: PsiReturnStatement) {
val returnValue = statement.getReturnValue()
- val methodReturnType = converter.methodReturnType
+ val methodReturnType = codeConverter.methodReturnType
val expression = if (returnValue != null && methodReturnType != null)
- converter.convertExpression(returnValue, methodReturnType)
+ codeConverter.convertExpression(returnValue, methodReturnType)
else
- converter.convertExpression(returnValue)
+ codeConverter.convertExpression(returnValue)
result = ReturnStatement(expression)
}
@@ -257,7 +256,7 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
}
}
-fun Converter.convertStatementOrBlock(statement: PsiStatement?): Statement {
+fun CodeConverter.convertStatementOrBlock(statement: PsiStatement?): Statement {
return if (statement is PsiBlockStatement)
convertBlock(statement.getCodeBlock())
else
diff --git a/j2k/src/org/jetbrains/jet/j2k/SwitchConverter.kt b/j2k/src/org/jetbrains/jet/j2k/SwitchConverter.kt
index 8fe34cc9f39..932f3f56cf0 100644
--- a/j2k/src/org/jetbrains/jet/j2k/SwitchConverter.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/SwitchConverter.kt
@@ -20,9 +20,9 @@ import com.intellij.psi.*
import org.jetbrains.jet.j2k.ast.*
import java.util.ArrayList
-class SwitchConverter(private val converter: Converter) {
+class SwitchConverter(private val codeConverter: CodeConverter) {
public fun convert(statement: PsiSwitchStatement): WhenStatement
- = WhenStatement(converter.convertExpression(statement.getExpression()), switchBodyToWhenEntries(statement.getBody()))
+ = WhenStatement(codeConverter.convertExpression(statement.getExpression()), switchBodyToWhenEntries(statement.getBody()))
private class Case(val label: PsiSwitchLabelStatement?, val statements: List)
@@ -38,7 +38,7 @@ class SwitchConverter(private val converter: Converter) {
result.add(WhenEntry(listOf(ValueWhenEntrySelector(Expression.Empty).assignNoPrototype()), convertCaseStatementsToBody(cases, i)).assignNoPrototype())
continue
}
- pendingSelectors.add(converter.convertStatement(case.label) as WhenEntrySelector)
+ pendingSelectors.add(codeConverter.convertStatement(case.label) as WhenEntrySelector)
if (case.statements.isNotEmpty()) {
result.add(WhenEntry(pendingSelectors, convertCaseStatementsToBody(cases, i)).assignNoPrototype())
pendingSelectors = ArrayList()
@@ -81,10 +81,10 @@ class SwitchConverter(private val converter: Converter) {
if (allowBlock && statementsToKeep.size == 1) {
val block = statementsToKeep.single() as? PsiBlockStatement
if (block != null) {
- return listOf(converter.convertBlock(block.getCodeBlock(), true, { !isSwitchBreak(it) }))
+ return listOf(codeConverter.convertBlock(block.getCodeBlock(), true, { !isSwitchBreak(it) }))
}
}
- return statementsToKeep.map { converter.convertStatement(it) }
+ return statementsToKeep.map { codeConverter.convertStatement(it) }
}
private fun convertCaseStatements(cases: List, caseIndex: Int, allowBlock: Boolean = true): List {
diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/TypeVisitor.kt
index 8a74d730c5e..d3c2b4a0181 100644
--- a/j2k/src/org/jetbrains/jet/j2k/TypeVisitor.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/TypeVisitor.kt
@@ -63,7 +63,7 @@ class TypeVisitor(private val converter: Converter) : PsiTypeVisitor() {
if (kotlinClassName != null) {
val kotlinShortName = getShortName(kotlinClassName)
if (kotlinShortName == getShortName(javaClassName!!) && converter.importNames.contains(getPackageName(javaClassName) + ".*")) {
- converter.importsToAdd?.add(kotlinClassName)
+ converter.importsToAdd.add(kotlinClassName)
}
return ReferenceElement(Identifier(kotlinShortName).assignNoPrototype(), typeArgs).assignNoPrototype()
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt
index 775b608715a..b96ae0560bf 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt
@@ -59,12 +59,13 @@ class Annotations(val annotations: List) : Element() {
builder.append(annotations, "")
}
- override val isEmpty: Boolean = annotations.isEmpty()
+ override val isEmpty: Boolean
+ get() = annotations.isEmpty()
fun plus(other: Annotations) = Annotations(annotations + other.annotations)
class object {
- val Empty = Annotations(listOf())
+ fun Empty() = Annotations(listOf())
}
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt
index 2691210e640..1c4fd847be3 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt
@@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.CodeBuilder
class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean)
-: Class(Identifier.Empty, Annotations.Empty, Modifiers.Empty, TypeParameterList.Empty, listOf(), listOf(), listOf(), body) {
+: Class(Identifier.Empty(), Annotations.Empty(), Modifiers.Empty(), TypeParameterList.Empty(), listOf(), listOf(), listOf(), body) {
override fun generateCode(builder: CodeBuilder) {
body.append(builder)
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt
index 15b417ffe06..35a77d5e286 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt
@@ -32,7 +32,7 @@ class Block(val statements: List, val lBrace: LBrace, val rBrace: RBr
}
class object {
- val Empty = Block(listOf(), LBrace(), RBrace())
+ fun Empty() = Block(listOf(), LBrace(), RBrace())
}
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt
index d2ce78f18fa..6bd425c3e81 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt
@@ -30,13 +30,14 @@ class ClassBody (
val rBrace: RBrace) {
fun append(builder: CodeBuilder) {
- if (members.isEmpty() && classObjectMembers.isEmpty()) return
+ val membersFiltered = members.filter { !it.isEmpty }
+ if (membersFiltered.isEmpty() && classObjectMembers.isEmpty()) return
builder append " " append lBrace append "\n"
- builder.append(members, "\n")
+ builder.append(membersFiltered, "\n")
- appendClassObject(builder, members.isNotEmpty())
+ appendClassObject(builder, membersFiltered.isNotEmpty())
builder append "\n" append rBrace
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt
index 1f837a6a977..f941db0aed4 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt
@@ -22,22 +22,24 @@ import com.intellij.util.IncorrectOperationException
class PrimaryConstructor(annotations: Annotations,
modifiers: Modifiers,
val parameterList: ParameterList,
- val block: Block)
+ val body: LazyElement)
: Member(annotations, modifiers) {
override fun generateCode(builder: CodeBuilder) { throw IncorrectOperationException() }
- public fun initializer(): Initializer? {
- return if (!block.isEmpty)
- Initializer(block, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false))
- else
- null
- }
+ public fun initializer(): Initializer
+ = Initializer(body, Modifiers.Empty()).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false))
- public fun signature(): PrimaryConstructorSignature {
- val noBody = block.isEmpty
- val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = noBody, commentsInside = noBody)
- return PrimaryConstructorSignature(annotations, modifiers, parameterList).assignPrototypesFrom(this, inheritance)
+ public fun createSignature(converter: Converter): PrimaryConstructorSignature {
+ val signature = PrimaryConstructorSignature(annotations, modifiers, parameterList)
+
+ // assign prototypes later because we don't know yet whether the body is empty or not
+ converter.addPostUnfoldLazyElementsAction {
+ val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = body.isEmpty, commentsInside = body.isEmpty)
+ signature.assignPrototypesFrom(this, inheritance)
+ }
+
+ return signature
}
}
@@ -64,8 +66,5 @@ class FactoryFunction(name: Identifier,
returnType: Type,
parameterList: ParameterList,
typeParameterList: TypeParameterList,
- body: Block)
+ body: LazyElement)
: Function(name, annotations, modifiers, returnType, typeParameterList, parameterList, body, false)
-
-fun FactoryFunction.withBody(body: Block)
- = FactoryFunction(name, annotations, modifiers, returnType, parameterList, typeParameterList, body).assignPrototypesFrom(this)
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt
index 38a1ebb313b..dbe8e155ca3 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt
@@ -57,15 +57,7 @@ fun Element.canonicalCode(): String {
}
abstract class Element {
- public var prototypes: List? = null
- set(value) {
- // no prototypes assigned to empty elements because they can be singleton instances (and they are not needed anyway)
- if (isEmpty) {
- $prototypes = listOf()
- return
- }
- $prototypes = value
- }
+ public open var prototypes: List? = null
public var createdAt: String?
= if (saveCreationStacktraces)
@@ -83,9 +75,52 @@ abstract class Element {
object Empty : Element() {
override fun generateCode(builder: CodeBuilder) { }
override val isEmpty: Boolean get() = true
+ override var prototypes: List? by EmptyElementPrototypes // to not hold references to psi
}
class object {
var saveCreationStacktraces = false
}
}
+
+object EmptyElementPrototypes {
+ public fun get(thisRef: Element, desc: PropertyMetadata): List? = null
+ public fun set(thisRef: Element, desc: PropertyMetadata, value: List?) { }
+}
+
+// this class should never be created directly - Converter.lazyElement() should be used!
+class LazyElement(private var generator: (CodeConverter) -> TResult) : Element() {
+ private var result: TResult? = null
+
+ {
+ assignNoPrototype()
+ }
+
+ public fun unfold(codeConverter: CodeConverter) {
+ assert(result == null)
+ result = generator(codeConverter)
+ }
+
+ override fun generateCode(builder: CodeBuilder) {
+ resultNotNull.generateCode(builder)
+ }
+
+ override val isEmpty: Boolean
+ get() = resultNotNull.isEmpty
+
+ private val resultNotNull: TResult
+ get() {
+ assert(result != null) { "No code generated for lazy element $this. Possible reason is that it has been created directly instead of Converter.lazyElement() call." }
+ return result!!
+ }
+
+ public fun updateGenerator(generatorUpdater: (codeConverter: CodeConverter, prevResult: TResult) -> TResult) {
+ assert(result == null, "Cannot update generator when code has been generated")
+ val prevGenerator = generator
+ generator = { codeConverter ->
+ val prevResult = prevGenerator(codeConverter)
+ generatorUpdater(codeConverter, prevResult)
+ }
+ }
+}
+
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt
index 3d7f17c2988..2dc770ab980 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt
@@ -23,7 +23,7 @@ class EnumConstant(
annotations: Annotations,
modifiers: Modifiers,
val type: Type,
- val params: Element
+ val params: LazyElement
) : Member(annotations, modifiers) {
override fun generateCode(builder: CodeBuilder) {
@@ -34,6 +34,4 @@ class EnumConstant(
builder append annotations append identifier append " : " append type append "(" append params append ")"
}
-
-
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt
index e9fa4713ae3..04705e34a3c 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt
@@ -17,14 +17,14 @@
package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.CodeBuilder
-
+import org.jetbrains.jet.j2k.CodeConverter
abstract class Expression() : Statement() {
open val isNullable: Boolean get() = false
object Empty : Expression() {
override fun generateCode(builder: CodeBuilder) {}
-
override val isEmpty: Boolean get() = true
+ override var prototypes: List? by EmptyElementPrototypes // to not hold references to psi
}
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt
index 7ea324efc6e..5e5623ff0cc 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt
@@ -18,12 +18,13 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.*
+//TODO: rename it to Property
class Field(
val identifier: Identifier,
annotations: Annotations,
modifiers: Modifiers,
val type: Type,
- val initializer: Element,
+ private val initializer: LazyElement,
val isVal: Boolean,
val explicitType: Boolean,
private val defaultInitializer: Boolean,
@@ -40,9 +41,9 @@ class Field(
builder append ":" append type
}
- var initializerToUse = initializer
+ var initializerToUse: Element = initializer
if (initializerToUse.isEmpty && defaultInitializer) {
- initializerToUse = getDefaultInitializer(this) ?: Expression.Empty
+ initializerToUse = getDefaultInitializer(this) ?: Element.Empty
}
if (!initializerToUse.isEmpty) {
builder append " = " append initializerToUse
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt
index 775f0792bee..95f3d21a14e 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt
@@ -25,7 +25,7 @@ open class Function(
val returnType: Type,
val typeParameterList: TypeParameterList,
val parameterList: ParameterList,
- val body: Block?,
+ val body: LazyElement?,
val isInTrait: Boolean
) : Member(annotations, modifiers) {
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt
index d2bf0331d0c..42d6dc9ba3e 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt
@@ -18,10 +18,11 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.CodeBuilder
import com.intellij.psi.PsiNameIdentifierOwner
+import org.jetbrains.jet.j2k.CodeConverter
fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier {
val name = getName()
- return if (name != null) Identifier(name, false).assignPrototype(getNameIdentifier()!!) else Identifier.Empty
+ return if (name != null) Identifier(name, false).assignPrototype(getNameIdentifier()!!) else Identifier.Empty()
}
class Identifier(
@@ -50,7 +51,7 @@ class Identifier(
override fun toString() = if (isNullable) "$name?" else name
class object {
- val Empty = Identifier("")
+ fun Empty() = Identifier("")
val ONLY_KOTLIN_KEYWORDS: Set = setOf(
"package", "as", "type", "val", "var", "fun", "is", "in", "object", "when", "trait", "This"
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt
index 4bce8bea9a8..cea8c79d2f0 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt
@@ -30,7 +30,7 @@ class Import(val name: String) : Element() {
}
}
-class ImportList(public val imports: List) : Element() {
+class ImportList(public var imports: List) : Element() {
override val isEmpty: Boolean
get() = imports.isEmpty()
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt
index 4be86f4d9bf..a57326d76bd 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt
@@ -18,8 +18,11 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.*
-class Initializer(val block: Block, modifiers: Modifiers) : Member(Annotations.Empty, modifiers) {
+class Initializer(val body: LazyElement, modifiers: Modifiers) : Member(Annotations.Empty(), modifiers) {
override fun generateCode(builder: CodeBuilder) {
- builder.append(block)
+ builder.append(body)
}
+
+ override val isEmpty: Boolean
+ get() = body.isEmpty
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt
index 27f6d277ddf..2e0230b3183 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt
@@ -60,7 +60,7 @@ class Modifiers(val modifiers: Collection) : Element() {
fun accessModifier(): Modifier? = modifiers.firstOrNull { it in ACCESS_MODIFIERS }
class object {
- val Empty = Modifiers(listOf())
+ fun Empty() = Modifiers(listOf())
}
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt
index 96c8319182c..435aedc2bf8 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt
@@ -22,9 +22,8 @@ import org.jetbrains.jet.j2k.*
abstract class Statement() : Element() {
object Empty : Statement() {
override fun generateCode(builder: CodeBuilder) { }
-
- override val isEmpty: Boolean
- get() = true
+ override val isEmpty: Boolean get() = true
+ override var prototypes: List? by EmptyElementPrototypes // to not hold references to psi
}
}
@@ -107,13 +106,13 @@ class ForeachStatement(
}
}
-class BreakStatement(val label: Identifier = Identifier.Empty) : Statement() {
+class BreakStatement(val label: Identifier = Identifier.Empty()) : Statement() {
override fun generateCode(builder: CodeBuilder) {
builder.append("break").appendWithPrefix(label, "@")
}
}
-class ContinueStatement(val label: Identifier = Identifier.Empty) : Statement() {
+class ContinueStatement(val label: Identifier = Identifier.Empty()) : Statement() {
override fun generateCode(builder: CodeBuilder) {
builder.append("continue").appendWithPrefix(label, "@")
}
diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt
index 3247ad06855..8d539404bb5 100644
--- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt
+++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt
@@ -50,14 +50,13 @@ class TypeParameterList(val parameters: List) : Element() {
return builder
}
-
override val isEmpty: Boolean
get() = parameters.isEmpty()
private fun hasWhere(): Boolean = parameters.any { it.hasWhere() }
class object {
- val Empty = TypeParameterList(ArrayList())
+ fun Empty() = TypeParameterList(listOf())
}
}
@@ -70,5 +69,5 @@ fun Converter.convertTypeParameterList(typeParameterList: PsiTypeParameterList?)
return if (typeParameterList != null)
TypeParameterList(typeParameterList.getTypeParameters()!!.toList().map { convertTypeParameter(it) }).assignPrototype(typeParameterList)
else
- TypeParameterList.Empty
+ TypeParameterList.Empty()
}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/usageProcessing/AccessorToPropertyProcessing.kt b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/AccessorToPropertyProcessing.kt
new file mode 100644
index 00000000000..48e1e0715a2
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/AccessorToPropertyProcessing.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.j2k.usageProcessing
+
+import com.intellij.psi.*
+import org.jetbrains.jet.j2k.*
+import org.jetbrains.jet.j2k.ast.*
+
+class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKind: AccessorKind, val propertyName: String) : UsageProcessing {
+ override val targetElement: PsiElement get() = accessorMethod
+
+ override val convertedCodeProcessor = object: ConvertedCodeProcessor {
+ override fun convertMethodUsage(methodCall: PsiMethodCallExpression, codeConverter: CodeConverter): Expression? {
+ val isNullable = codeConverter.typeConverter.methodNullability(accessorMethod).isNullable(codeConverter.settings)
+
+ val methodExpr = methodCall.getMethodExpression()
+ val arguments = methodCall.getArgumentList().getExpressions()
+
+ val propertyName = Identifier(propertyName, isNullable).assignNoPrototype()
+ val propertyAccess = QualifiedExpression(codeConverter.convertExpression(methodExpr.getQualifierExpression()), propertyName).assignNoPrototype()
+
+ if (accessorKind == AccessorKind.GETTER) {
+ if (arguments.size != 0) return null // incorrect call
+ return propertyAccess
+ }
+ else {
+ if (arguments.size != 1) return null // incorrect call
+ val argument = codeConverter.convertExpression(arguments[0])
+ return AssignmentExpression(propertyAccess, argument, "=")
+ }
+ }
+ }
+
+ override val javaCodeProcessor: ExternalCodeProcessor? = null
+
+ override val kotlinCodeProcessor: ExternalCodeProcessor? = object: ExternalCodeProcessor {
+ override fun processUsage(reference: PsiReference) {
+ //TODO
+ //reference.getElement() as JetSimpleNameExpression
+ }
+ }
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/usageProcessing/FieldToPropertyProcessing.kt b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/FieldToPropertyProcessing.kt
new file mode 100644
index 00000000000..ad879b41803
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/FieldToPropertyProcessing.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.j2k.usageProcessing
+
+import com.intellij.psi.*
+import org.jetbrains.jet.j2k.CodeConverter
+import org.jetbrains.jet.j2k.ast.*
+
+class FieldToPropertyProcessing(val field: PsiField, val propertyName: String, val isNullable: Boolean) : UsageProcessing {
+ override val targetElement: PsiElement get() = field
+
+ override val convertedCodeProcessor = if (field.getName() != propertyName) {
+ object: ConvertedCodeProcessor {
+ override fun convertVariableUsage(expression: PsiReferenceExpression, codeConverter: CodeConverter): Expression? {
+ val identifier = Identifier(propertyName, isNullable).assignNoPrototype()
+
+ val qualifier = expression.getQualifierExpression()
+ return if (qualifier != null) {
+ QualifiedExpression(codeConverter.convertExpression(qualifier), identifier)
+ }
+ else {
+ // check if field name is shadowed
+ val elementFactory = PsiElementFactory.SERVICE.getInstance(expression.getProject())
+ val refExpr = elementFactory.createExpressionFromText(propertyName, expression) as PsiReferenceExpression
+ if (refExpr.resolve() == null)
+ identifier
+ else
+ QualifiedExpression(ThisExpression(Identifier.Empty()).assignNoPrototype(), identifier) //TODO: this is not correct in case of nested/anonymous classes
+ }
+ }
+ }
+ }
+ else {
+ null
+ }
+
+ override val javaCodeProcessor: ExternalCodeProcessor? get() = null //TODO
+
+ override val kotlinCodeProcessor: ExternalCodeProcessor? get() = null //TODO
+}
\ No newline at end of file
diff --git a/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt
new file mode 100644
index 00000000000..917c3723e99
--- /dev/null
+++ b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.j2k.usageProcessing
+
+import org.jetbrains.jet.j2k.ast.Expression
+import com.intellij.psi.*
+import org.jetbrains.jet.j2k.CodeConverter
+import org.jetbrains.jet.j2k.SpecialExpressionConverter
+
+trait UsageProcessing {
+ val targetElement: PsiElement
+ val convertedCodeProcessor: ConvertedCodeProcessor?
+ val javaCodeProcessor: ExternalCodeProcessor?
+ val kotlinCodeProcessor: ExternalCodeProcessor?
+}
+
+trait ConvertedCodeProcessor {
+ fun convertVariableUsage(expression: PsiReferenceExpression, codeConverter: CodeConverter): Expression? = null
+
+ fun convertMethodUsage(methodCall: PsiMethodCallExpression, codeConverter: CodeConverter): Expression? = null
+}
+
+trait ExternalCodeProcessor {
+ fun processUsage(reference: PsiReference)
+}
+
+class UsageProcessingExpressionConverter(processings: Collection) : SpecialExpressionConverter {
+ private val targetToProcessing = processings.toMap { it.targetElement } // we assume that there will be no more than one processing for one target element
+
+ override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
+ if (targetToProcessing.isEmpty()) return null
+
+ //TODO: method usages
+
+ if (expression is PsiReferenceExpression) {
+ val target = expression.resolve() ?: return null
+ val processor = targetToProcessing[target]?.convertedCodeProcessor ?: return null
+ return processor.convertVariableUsage(expression, codeConverter)
+ }
+
+ return null
+ }
+}
\ 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 f802419267e..b0f08373111 100644
--- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt
+++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt
@@ -18,8 +18,6 @@ package org.jetbrains.jet.j2k.test
import java.io.File
import com.intellij.openapi.util.io.FileUtil
-import org.jetbrains.jet.j2k.Converter
-import org.jetbrains.jet.j2k.JavaToKotlinTranslator
import org.jetbrains.jet.j2k.ConverterSettings
import java.util.regex.Pattern
import com.intellij.testFramework.LightPlatformTestCase
@@ -40,6 +38,8 @@ import org.jetbrains.jet.j2k.translateToKotlin
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
import org.jetbrains.jet.JetTestCaseBuilder
import com.intellij.openapi.util.Disposer
+import org.jetbrains.jet.j2k.JavaToKotlinConverter
+import org.jetbrains.jet.j2k.JavaToKotlinTranslator
public abstract class AbstractJavaToKotlinConverterTest() : LightCodeInsightFixtureTestCase() {
val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n")
@@ -136,14 +136,14 @@ public abstract class AbstractJavaToKotlinConverterTest() : LightCodeInsightFixt
private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String {
val fileWithText = createJavaFile(text)
- val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText)), IdeaReferenceSearcher, J2kPostProcessor(fileWithText))
+ val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(fileWithText)), IdeaReferenceSearcher, J2kPostProcessor(fileWithText))
val element = fileWithText.getFirstChild()!!
return converter.elementToKotlin(element)
}
private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String {
val file = createJavaFile(text)
- val converter = Converter.create(project, settings, FilesConversionScope(listOf(file)), IdeaReferenceSearcher, J2kPostProcessor(file))
+ val converter = JavaToKotlinConverter(project, settings, FilesConversionScope(listOf(file)), IdeaReferenceSearcher, J2kPostProcessor(file))
return converter.elementToKotlin(file)
}