J2K: fixed conversion of default parameter values and annotation arguments

This commit is contained in:
Valentin Kipyatkov
2014-10-17 21:45:53 +04:00
committed by valentin
parent 7762d4e7c6
commit 7941314c60
9 changed files with 83 additions and 49 deletions
@@ -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 -23
View File
@@ -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()
+5 -1
View File
@@ -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)