Big refactoring in j2k converter to support java&kotlin code updating to reflect changes in declarations produced by conversion (work in progress but all tests pass)
This commit is contained in:
committed by
valentin
parent
16f117571f
commit
030faa4630
Generated
+1
@@ -4,6 +4,7 @@
|
||||
<w>initializers</w>
|
||||
<w>inserter</w>
|
||||
<w>pparent</w>
|
||||
<w>processings</w>
|
||||
<w>rparenth</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
|
||||
@@ -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$,
|
||||
|
||||
@@ -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<VirtualFile> convertFiles(final Converter converter, List<PsiJavaFile> allJavaFilesNear) {
|
||||
static List<VirtualFile> convertFiles(final JavaToKotlinConverter converter, List<PsiJavaFile> allJavaFilesNear) {
|
||||
final List<VirtualFile> result = new LinkedList<VirtualFile>();
|
||||
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) {
|
||||
|
||||
+2
-2
@@ -86,7 +86,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
|
||||
}
|
||||
|
||||
private fun convertCopiedCodeToKotlin(code: CopiedCode, fileCopiedFrom: PsiJavaFile, fileCopiedTo: JetFile): String {
|
||||
val converter = Converter.create(fileCopiedFrom.getProject(),
|
||||
val converter = JavaToKotlinConverter(fileCopiedFrom.getProject(),
|
||||
ConverterSettings.defaultSettings,
|
||||
FilesConversionScope(listOf(fileCopiedFrom)),
|
||||
IdeaReferenceSearcher,
|
||||
@@ -105,7 +105,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBl
|
||||
|
||||
private fun convertRangeToKotlin(file: PsiJavaFile,
|
||||
range: TextRange,
|
||||
converter: Converter): String {
|
||||
converter: JavaToKotlinConverter): String {
|
||||
val result = StringBuilder()
|
||||
var currentRange = range
|
||||
//TODO: probably better to use document to get text by range
|
||||
|
||||
@@ -31,7 +31,7 @@ class AnnotationConverter(private val converter: Converter) {
|
||||
private fun convertAnnotationsOnly(owner: PsiModifierListOwner): Annotations {
|
||||
val modifierList = owner.getModifierList()
|
||||
val annotations = modifierList?.getAnnotations()?.filter { it.getQualifiedName() !in annotationsToRemove }
|
||||
if (annotations == null || annotations.isEmpty()) return Annotations.Empty
|
||||
if (annotations == null || annotations.isEmpty()) return Annotations.Empty()
|
||||
|
||||
val newLines = run {
|
||||
if (!modifierList!!.isInSingleLine()) {
|
||||
@@ -73,7 +73,7 @@ class AnnotationConverter(private val converter: Converter) {
|
||||
|
||||
val nameRef = annotation.getNameReferenceElement()
|
||||
val name = Identifier((nameRef ?: return null).getText()!!).assignPrototype(nameRef)
|
||||
val annotationClass = nameRef!!.resolve() as? PsiClass
|
||||
val annotationClass = nameRef.resolve() as? PsiClass
|
||||
val lastMethod = annotationClass?.getMethods()?.lastOrNull()
|
||||
val arguments = annotation.getParameterList().getAttributes().flatMap {
|
||||
val method = annotationClass?.findMethodsByName(it.getName() ?: "value", false)?.firstOrNull()
|
||||
@@ -97,7 +97,7 @@ class AnnotationConverter(private val converter: Converter) {
|
||||
|
||||
private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List<Expression> {
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<PsiExpression>): List<Expression>
|
||||
= 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<String, String> = 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"
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
@@ -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<String, String>()
|
||||
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<PsiStatement>()
|
||||
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<PsiField, PsiStatement>? {
|
||||
@@ -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<Field>()).filter { it.isVal }
|
||||
val updatedFactoryFunctions = ArrayList<FactoryFunction>()
|
||||
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<FactoryFunction>): List<FactoryFunction> {
|
||||
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<FactoryFunction>) {
|
||||
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<String, String>,
|
||||
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<String, String>) : 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<PsiJavaFile>) : ConversionScope {
|
||||
override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it }
|
||||
}
|
||||
private class State(val specialContext: PsiElement?,
|
||||
val importsToAdd: MutableSet<String>,
|
||||
val lazyElements: MutableList<LazyElement<*>>,
|
||||
val usageProcessings: MutableCollection<UsageProcessing>,
|
||||
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<String>?)
|
||||
public val specialContext: PsiElement? = state.specialContext
|
||||
public val importsToAdd: MutableCollection<String> = state.importsToAdd
|
||||
|
||||
val typeConverter: TypeConverter = TypeConverter(this)
|
||||
|
||||
val methodReturnType: PsiType? = state.methodReturnType
|
||||
val specialContext: PsiElement? = state.specialContext
|
||||
val importNames: Set<String> = state.importList?.imports?.mapTo(HashSet<String>()) { it.name } ?: setOf()
|
||||
val importsToAdd: MutableCollection<String>? = state.importsToAdd
|
||||
|
||||
val annotationConverter = AnnotationConverter(this)
|
||||
private val importList = (elementToConvert as? PsiJavaFile)?.getImportList()?.let { convertImportList(it) }
|
||||
public val importNames: Set<String> = importList?.imports?.mapTo(HashSet<String>()) { 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<String>): 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<UsageProcessing>
|
||||
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<TResult : Element> lazyElement(generator: (CodeConverter) -> TResult): LazyElement<TResult> {
|
||||
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<String>()
|
||||
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<ImportList>()).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<PsiMember>?, constructorConverter: ConstructorConverter?): Member? {
|
||||
return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove, constructorConverter)?.assignPrototype(method)
|
||||
}
|
||||
|
||||
private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>?, constructorConverter: ConstructorConverter?): Member? {
|
||||
public fun convertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>?, 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<Statement>()
|
||||
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<PsiExpression>): List<Expression>
|
||||
= 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<Element>? = null): ReferenceElement {
|
||||
public fun convertCodeReferenceElement(element: PsiJavaCodeReferenceElement, hasExternalQualifier: Boolean, typeArgsConverted: List<Element>? = 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<out PsiType?>): List<Type>
|
||||
= 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<String, String> = 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])
|
||||
|
||||
@@ -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<PsiAssignmentExpression>())
|
||||
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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<PsiJavaFile>) : 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter): Expression? {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter): Expression {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
|
||||
= BinaryExpression(converter.convertExpression(arguments[0]), converter.convertExpression(arguments[1]), "==")
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
|
||||
= MethodCallExpression.build(null, "listOf", listOf(converter.convertExpression(arguments.single())), typeArgumentsConverted, false)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter)
|
||||
= MethodCallExpression.build(null, "setOf", listOf(converter.convertExpression(arguments.single())), typeArgumentsConverted, false)
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, 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<PsiExpression>, typeArgumentsConverted: List<Type>, converter: Converter): Expression?
|
||||
abstract fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression?
|
||||
}
|
||||
@@ -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<CatchStatement> {
|
||||
val catches = ArrayList<CatchStatement>()
|
||||
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<PsiResourceVariable>, catchesConverted: List<CatchStatement>, 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
|
||||
|
||||
@@ -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<PsiStatement>)
|
||||
|
||||
@@ -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<Case>, caseIndex: Int, allowBlock: Boolean = true): List<Statement> {
|
||||
|
||||
@@ -63,7 +63,7 @@ class TypeVisitor(private val converter: Converter) : PsiTypeVisitor<Type>() {
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -59,12 +59,13 @@ class Annotations(val annotations: List<Annotation>) : 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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class Block(val statements: List<Statement>, val lBrace: LBrace, val rBrace: RBr
|
||||
}
|
||||
|
||||
class object {
|
||||
val Empty = Block(listOf(), LBrace(), RBrace())
|
||||
fun Empty() = Block(listOf(), LBrace(), RBrace())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -22,22 +22,24 @@ import com.intellij.util.IncorrectOperationException
|
||||
class PrimaryConstructor(annotations: Annotations,
|
||||
modifiers: Modifiers,
|
||||
val parameterList: ParameterList,
|
||||
val block: Block)
|
||||
val body: LazyElement<Block>)
|
||||
: 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<Block>)
|
||||
: Function(name, annotations, modifiers, returnType, typeParameterList, parameterList, body, false)
|
||||
|
||||
fun FactoryFunction.withBody(body: Block)
|
||||
= FactoryFunction(name, annotations, modifiers, returnType, parameterList, typeParameterList, body).assignPrototypesFrom(this)
|
||||
@@ -57,15 +57,7 @@ fun Element.canonicalCode(): String {
|
||||
}
|
||||
|
||||
abstract class Element {
|
||||
public var prototypes: List<PrototypeInfo>? = 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<PrototypeInfo>? = 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<PrototypeInfo>? by EmptyElementPrototypes // to not hold references to psi
|
||||
}
|
||||
|
||||
class object {
|
||||
var saveCreationStacktraces = false
|
||||
}
|
||||
}
|
||||
|
||||
object EmptyElementPrototypes {
|
||||
public fun get(thisRef: Element, desc: PropertyMetadata): List<PrototypeInfo>? = null
|
||||
public fun set(thisRef: Element, desc: PropertyMetadata, value: List<PrototypeInfo>?) { }
|
||||
}
|
||||
|
||||
// this class should never be created directly - Converter.lazyElement() should be used!
|
||||
class LazyElement<TResult : Element>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class EnumConstant(
|
||||
annotations: Annotations,
|
||||
modifiers: Modifiers,
|
||||
val type: Type,
|
||||
val params: Element
|
||||
val params: LazyElement<ExpressionList>
|
||||
) : 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 ")"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<PrototypeInfo>? by EmptyElementPrototypes // to not hold references to psi
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Expression>,
|
||||
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
|
||||
|
||||
@@ -25,7 +25,7 @@ open class Function(
|
||||
val returnType: Type,
|
||||
val typeParameterList: TypeParameterList,
|
||||
val parameterList: ParameterList,
|
||||
val body: Block?,
|
||||
val body: LazyElement<Block>?,
|
||||
val isInTrait: Boolean
|
||||
) : Member(annotations, modifiers) {
|
||||
|
||||
|
||||
@@ -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<String> = setOf(
|
||||
"package", "as", "type", "val", "var", "fun", "is", "in", "object", "when", "trait", "This"
|
||||
|
||||
@@ -30,7 +30,7 @@ class Import(val name: String) : Element() {
|
||||
}
|
||||
}
|
||||
|
||||
class ImportList(public val imports: List<Import>) : Element() {
|
||||
class ImportList(public var imports: List<Import>) : Element() {
|
||||
override val isEmpty: Boolean
|
||||
get() = imports.isEmpty()
|
||||
|
||||
|
||||
@@ -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<Block>, modifiers: Modifiers) : Member(Annotations.Empty(), modifiers) {
|
||||
override fun generateCode(builder: CodeBuilder) {
|
||||
builder.append(block)
|
||||
builder.append(body)
|
||||
}
|
||||
|
||||
override val isEmpty: Boolean
|
||||
get() = body.isEmpty
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class Modifiers(val modifiers: Collection<Modifier>) : Element() {
|
||||
fun accessModifier(): Modifier? = modifiers.firstOrNull { it in ACCESS_MODIFIERS }
|
||||
|
||||
class object {
|
||||
val Empty = Modifiers(listOf())
|
||||
fun Empty() = Modifiers(listOf())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PrototypeInfo>? 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, "@")
|
||||
}
|
||||
|
||||
@@ -50,14 +50,13 @@ class TypeParameterList(val parameters: List<TypeParameter>) : 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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<UsageProcessing>) : 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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user