From 7941314c600824d200a4d2040243caab7390b7e3 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 17 Oct 2014 21:45:53 +0400 Subject: [PATCH] J2K: fixed conversion of default parameter values and annotation arguments --- .../jetbrains/jet/j2k/AnnotationConverter.kt | 41 +++++++------- .../org/jetbrains/jet/j2k/CodeConverter.kt | 3 + .../jetbrains/jet/j2k/ConstructorConverter.kt | 7 +-- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 55 +++++++++++-------- .../org/jetbrains/jet/j2k/ast/Annotation.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 2 +- ...rentFieldNameAndDefaultParameterValue.java | 15 +++++ ...ferentFieldNameAndDefaultParameterValue.kt | 1 + 9 files changed, 83 insertions(+), 49 deletions(-) create mode 100644 j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.java create mode 100644 j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/AnnotationConverter.kt b/j2k/src/org/jetbrains/jet/j2k/AnnotationConverter.kt index d26775b9e0c..378ec62c050 100644 --- a/j2k/src/org/jetbrains/jet/j2k/AnnotationConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/AnnotationConverter.kt @@ -68,7 +68,8 @@ class AnnotationConverter(private val converter: Converter) { public fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean, newLineAfter: Boolean): Annotation? { val qualifiedName = annotation.getQualifiedName() if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { - return Annotation(Identifier("deprecated").assignNoPrototype(), listOf(null to LiteralExpression("\"\"").assignNoPrototype()), brackets, newLineAfter).assignPrototype(annotation) //TODO: insert comment + val lazyExpression = converter.lazyElement { LiteralExpression("\"\"").assignNoPrototype() } + return Annotation(Identifier("deprecated").assignNoPrototype(), listOf(null to lazyExpression), brackets, newLineAfter).assignPrototype(annotation) //TODO: insert comment } val nameRef = annotation.getNameReferenceElement() @@ -85,45 +86,47 @@ class AnnotationConverter(private val converter: Converter) { val isVarArg = method == lastMethod /* converted to vararg in Kotlin */ val attrValues = convertAttributeValue(value, expectedType, isVarArg, it.getName() == null) - attrValues.map { attrName to it } + attrValues.map { attrName to converter.lazyElement(it) } } return Annotation(name, arguments, brackets, newLineAfter).assignPrototype(annotation) } - public fun convertAnnotationMethodDefault(method: PsiAnnotationMethod): Expression? { + public fun convertAnnotationMethodDefault(method: PsiAnnotationMethod): LazyElement? { val value = method.getDefaultValue() ?: return null - return convertAttributeValue(value, method.getReturnType(), false, false).single() + return converter.lazyElement(convertAttributeValue(value, method.getReturnType(), false, false).single()) } - private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List { - return when (value) { - is PsiExpression -> listOf(converter.createDefaultCodeConverter()/*TODO*/.convertExpression(value as? PsiExpression, expectedType).assignPrototype(value)) + private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List<(CodeConverter) -> Expression> { + when (value) { + is PsiExpression -> return listOf({ codeConverter -> codeConverter.convertExpression(value as? PsiExpression, expectedType).assignPrototype(value) }) is PsiArrayInitializerMemberValue -> { val componentType = (expectedType as? PsiArrayType)?.getComponentType() val componentsConverted = value.getInitializers().map { convertAttributeValue(it, componentType, false, true).single() } if (isVararg && isUnnamed) { - componentsConverted + return componentsConverted } else { - val expectedTypeConverted = converter.typeConverter.convertType(expectedType) - if (expectedTypeConverted is ArrayType) { - val array = createArrayInitializerExpression(expectedTypeConverted, componentsConverted, needExplicitType = false) - if (isVararg) { - listOf(StarExpression(array.assignNoPrototype()).assignPrototype(value)) + val expressionGenerator = { (codeConverter: CodeConverter) -> + val expectedTypeConverted = converter.typeConverter.convertType(expectedType) + if (expectedTypeConverted is ArrayType) { + val array = createArrayInitializerExpression(expectedTypeConverted, componentsConverted.map { it(codeConverter) }, needExplicitType = false) + if (isVararg) { + StarExpression(array.assignNoPrototype()).assignPrototype(value) + } + else { + array.assignPrototype(value) + } } else { - listOf(array.assignPrototype(value)) + DummyStringExpression(value.getText()!!).assignPrototype(value) } } - else { - listOf(DummyStringExpression(value.getText()!!).assignPrototype(value)) - } + return listOf(expressionGenerator) } } - else -> listOf(DummyStringExpression(value?.getText() ?: "").assignPrototype(value)) + else -> return listOf({ codeConverter -> DummyStringExpression(value?.getText() ?: "").assignPrototype(value) }) } } - } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt index 8ad53ef746f..2de349199c4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/CodeConverter.kt @@ -64,6 +64,9 @@ class CodeConverter(public val converter: Converter, public fun withMethodReturnType(methodReturnType: PsiType?): CodeConverter = CodeConverter(converter, expressionConverter, statementConverter, methodReturnType) + public fun withConverter(converter: Converter): 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() diff --git a/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt b/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt index efae0a8a1b1..3bd46d1604c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ConstructorConverter.kt @@ -261,14 +261,13 @@ class ConstructorConverter(private val psiClass: PsiClass, val correctedConverter = converter.withSpecialContext(psiClass) /* to correct nested class references */ - fun correctCodeConverter(codeConverter: CodeConverter) - = codeConverter.withSpecialExpressionConverter(ReplacingExpressionConverter(this, parameterUsageReplacementMap)) + fun CodeConverter.correct() = withSpecialExpressionConverter(ReplacingExpressionConverter(this@ConstructorConverter, parameterUsageReplacementMap)) val statement = primaryConstructor.getBody()?.getStatements()?.firstOrNull() val methodCall = (statement as? PsiExpressionStatement)?.getExpression() as? PsiMethodCallExpression if (methodCall != null && methodCall.isSuperConstructorCall()) { baseClassParams = methodCall.getArgumentList().getExpressions().map { - correctedConverter.lazyElement { codeConverter -> correctCodeConverter(codeConverter).convertExpression(it) } + correctedConverter.lazyElement { codeConverter -> codeConverter.correct().convertExpression(it) } } } @@ -276,7 +275,7 @@ class ConstructorConverter(private val psiClass: PsiClass, val parameter = params[i] val indexFromEnd = params.size - i - 1 val defaultValue = if (indexFromEnd < lastParamDefaults.size) - correctCodeConverter(correctedConverter.createDefaultCodeConverter()/*TODO!!*/).convertExpression(lastParamDefaults[indexFromEnd], parameter.getType()) + correctedConverter.lazyElement { codeConverter -> codeConverter.correct().convertExpression(lastParamDefaults[indexFromEnd], parameter.getType()) } else null if (!parameterToField.containsKey(parameter)) { diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 48082c270de..ff0cdc38dbf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -32,20 +32,26 @@ class Converter private(private val elementToConvert: PsiElement, val conversionScope: ConversionScope, val referenceSearcher: ReferenceSearcher, private val postProcessor: PostProcessor?, - private val state: Converter.State) { + private val commonState: Converter.CommonState, + private val personalState: Converter.PersonalState) { - private class State(val specialContext: PsiElement?, - val importsToAdd: MutableSet, - val lazyElements: MutableList>, - val usageProcessings: MutableCollection, - val postUnfoldActions: MutableList<() -> Unit>) + // state which is shared between all converter's based on this one + private class CommonState { + val importsToAdd = LinkedHashSet() + val lazyElements = ArrayList>() + val usageProcessings = ArrayList() + val postUnfoldActions = ArrayList<() -> Unit>() + } + + // state which may differ in different converter's + public class PersonalState(val specialContext: PsiElement?) public val project: Project = elementToConvert.getProject() public val typeConverter: TypeConverter = TypeConverter(this) public val annotationConverter: AnnotationConverter = AnnotationConverter(this) - public val specialContext: PsiElement? = state.specialContext - public val importsToAdd: MutableCollection = state.importsToAdd + public val specialContext: PsiElement? = personalState.specialContext + public val importsToAdd: MutableCollection = commonState.importsToAdd private val importList = (elementToConvert as? PsiJavaFile)?.getImportList()?.let { convertImportList(it) } public val importNames: Set = importList?.imports?.mapTo(HashSet()) { it.name } ?: setOf() @@ -53,13 +59,15 @@ class Converter private(private val elementToConvert: PsiElement, class object { public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope, referenceSearcher: ReferenceSearcher, postProcessor: PostProcessor?): Converter { - return Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, State(null, LinkedHashSet(), ArrayList(), ArrayList(), ArrayList())) + return Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, CommonState(), PersonalState(null)) } } public fun withSpecialContext(context: PsiElement): Converter - = Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, - State(context, state.importsToAdd, state.lazyElements, state.usageProcessings, state.postUnfoldActions)) + = Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, commonState, PersonalState(context)) + + private fun withState(state: PersonalState): Converter + = Converter(elementToConvert, settings, conversionScope, referenceSearcher, postProcessor, commonState, state) /*TODO: it should be private*/ fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null) @@ -80,30 +88,31 @@ class Converter private(private val elementToConvert: PsiElement, } public val usageProcessings: Collection - get() = state.usageProcessings + get() = commonState.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) + while (i < commonState.lazyElements.size) { + val lazyElement = commonState.lazyElements[i++] + lazyElement.unfold(codeConverter.withConverter(this.withState(lazyElement.converterState))) } - state.postUnfoldActions.forEach { it() } + commonState.postUnfoldActions.forEach { it() } } public fun lazyElement(generator: (CodeConverter) -> TResult): LazyElement { - val element = LazyElement(generator) - state.lazyElements.add(element) + val element = LazyElement(generator, personalState) + commonState.lazyElements.add(element) return element } public fun addUsageProcessing(processing: UsageProcessing) { - state.usageProcessings.add(processing) + commonState.usageProcessings.add(processing) } public fun addPostUnfoldLazyElementsAction(action: () -> Unit) { - state.postUnfoldActions.add(action) + commonState.postUnfoldActions.add(action) } private fun convertFile(javaFile: PsiJavaFile): File { @@ -418,7 +427,7 @@ class Converter private(private val elementToConvert: PsiElement, nullability: Nullability = Nullability.Default, varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None, modifiers: Modifiers = Modifiers.Empty(), - defaultValue: Expression? = null): Parameter { + defaultValue: LazyElement? = null): Parameter { var type = typeConverter.convertVariableType(parameter) when (nullability) { Nullability.NotNull -> type = type.toNotNullType() @@ -452,9 +461,9 @@ class Converter private(private val elementToConvert: PsiElement, val refElements = throwsList.getReferenceElements() assert(types.size == refElements.size) 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]) + val arguments = types.indices.map { index -> + val convertedType = typeConverter.convertType(types[index], Nullability.NotNull) + null to lazyElement { MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(convertedType)).assignPrototype(refElements[index]) } } val annotation = Annotation(Identifier("throws").assignNoPrototype(), arguments, false, true) return Annotations(listOf(annotation.assignPrototype(throwsList))).assignPrototype(throwsList) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index b96ae0560bf..966a4cd2fa2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* -class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean, val newLineAfter: Boolean) : Element() { +class Annotation(val name: Identifier, val arguments: List>>, val brackets: Boolean, val newLineAfter: Boolean) : Element() { private fun CodeBuilder.surroundWithBrackets(action: () -> Unit) { if (brackets) append("[") action() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index dbe8e155ca3..63e96125956 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -89,7 +89,11 @@ object EmptyElementPrototypes { } // this class should never be created directly - Converter.lazyElement() should be used! -class LazyElement(private var generator: (CodeConverter) -> TResult) : Element() { +class LazyElement( + private var generator: (CodeConverter) -> TResult, + public val converterState: Converter.PersonalState +) : Element() { + private var result: TResult? = null { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 07a0fea3fd7..5173f632299 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -23,7 +23,7 @@ class Parameter(val identifier: Identifier, val varVal: Parameter.VarValModifier, val annotations: Annotations, val modifiers: Modifiers, - val defaultValue: Expression? = null) : Element() { + val defaultValue: LazyElement? = null) : Element() { public enum class VarValModifier { None Val diff --git a/j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.java b/j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.java new file mode 100644 index 00000000000..2225b8e0a0c --- /dev/null +++ b/j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.java @@ -0,0 +1,15 @@ +public class C { + private final int myX; + + public int getX() { + return myX; + } + + C(C c, int x){ + myX = x; + } + + C(C c){ + this(c, c.myX); + } +} diff --git a/j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.kt b/j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.kt new file mode 100644 index 00000000000..72ff7b69aeb --- /dev/null +++ b/j2k/tests/testData/ast/dropAccessors/DifferentFieldNameAndDefaultParameterValue.kt @@ -0,0 +1 @@ +public class C(c: C, public val x: Int = c.x) \ No newline at end of file