J2K: fixed conversion of default parameter values and annotation arguments
This commit is contained in:
committed by
valentin
parent
7762d4e7c6
commit
7941314c60
@@ -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<Expression> { 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<Expression>? {
|
||||
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<Expression> {
|
||||
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) })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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<String>,
|
||||
val lazyElements: MutableList<LazyElement<*>>,
|
||||
val usageProcessings: MutableCollection<UsageProcessing>,
|
||||
val postUnfoldActions: MutableList<() -> Unit>)
|
||||
// state which is shared between all converter's based on this one
|
||||
private class CommonState {
|
||||
val importsToAdd = LinkedHashSet<String>()
|
||||
val lazyElements = ArrayList<LazyElement<*>>()
|
||||
val usageProcessings = ArrayList<UsageProcessing>()
|
||||
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<String> = state.importsToAdd
|
||||
public val specialContext: PsiElement? = personalState.specialContext
|
||||
public val importsToAdd: MutableCollection<String> = commonState.importsToAdd
|
||||
|
||||
private val importList = (elementToConvert as? PsiJavaFile)?.getImportList()?.let { convertImportList(it) }
|
||||
public val importNames: Set<String> = importList?.imports?.mapTo(HashSet<String>()) { 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<UsageProcessing>
|
||||
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<TResult : Element> lazyElement(generator: (CodeConverter) -> TResult): LazyElement<TResult> {
|
||||
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<Expression>? = 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<Expression> { 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)
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.*
|
||||
|
||||
class Annotation(val name: Identifier, val arguments: List<Pair<Identifier?, Expression>>, val brackets: Boolean, val newLineAfter: Boolean) : Element() {
|
||||
class Annotation(val name: Identifier, val arguments: List<Pair<Identifier?, LazyElement<Expression>>>, val brackets: Boolean, val newLineAfter: Boolean) : Element() {
|
||||
private fun CodeBuilder.surroundWithBrackets(action: () -> Unit) {
|
||||
if (brackets) append("[")
|
||||
action()
|
||||
|
||||
@@ -89,7 +89,11 @@ object EmptyElementPrototypes {
|
||||
}
|
||||
|
||||
// this class should never be created directly - Converter.lazyElement() should be used!
|
||||
class LazyElement<TResult : Element>(private var generator: (CodeConverter) -> TResult) : Element() {
|
||||
class LazyElement<TResult : Element>(
|
||||
private var generator: (CodeConverter) -> TResult,
|
||||
public val converterState: Converter.PersonalState
|
||||
) : Element() {
|
||||
|
||||
private var result: TResult? = null
|
||||
|
||||
{
|
||||
|
||||
@@ -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<Expression>? = null) : Element() {
|
||||
public enum class VarValModifier {
|
||||
None
|
||||
Val
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
public class C(c: C, public val x: Int = c.x)
|
||||
Reference in New Issue
Block a user