diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt index e4f9e98a417..6cfa7125b25 100644 --- a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt +++ b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt @@ -21,7 +21,6 @@ import java.util.HashSet import org.jetbrains.jet.lang.psi.psiUtil.isAncestor import java.util.ArrayList import org.jetbrains.jet.j2k.ast.Element -import org.jetbrains.jet.j2k.ast.Modifiers import kotlin.platform.platformName fun CodeBuilder.append(generators: Collection<() -> T>, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder { @@ -79,14 +78,21 @@ class CodeBuilder(private val topElement: PsiElement?) { public fun append(element: Element): CodeBuilder { if (element.isEmpty) return this // do not insert comment and spaces for empty elements to avoid multiple blank lines - if (element.prototypes.isEmpty() || topElement == null) { + if (element.prototypes == null && topElement != null) { + val s = "Element $element has no prototypes assigned.\n" + + "Use Element.assignPrototype() or Element.assignNoPrototype().\n" + + "Element created at:\n${element.createdAt}" + throw RuntimeException(s) + } + + if (topElement == null || element.prototypes!!.isEmpty()) { element.generateCode(this) return this } val prefixElements = ArrayList(1) val postfixElements = ArrayList(1) - for ((prototype, inheritBlankLinesBefore) in element.prototypes) { + for ((prototype, inheritBlankLinesBefore) in element.prototypes!!) { assert(prototype !is PsiComment) assert(prototype !is PsiWhiteSpace) assert(topElement.isAncestor(prototype)) @@ -112,7 +118,7 @@ class CodeBuilder(private val topElement: PsiElement?) { element.generateCode(this) // scan for all comments inside which are not yet used in the text and put them here to not loose any comment from code - for ((prototype, _) in element.prototypes) { + for ((prototype, _) in element.prototypes!!) { prototype.accept(object : JavaRecursiveElementVisitor(){ override fun visitComment(comment: PsiComment) { if (commentsAndSpacesUsed.add(comment)) { diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 34e60bd3847..db1a1a60199 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -225,7 +225,7 @@ public class Converter private(val project: Project, val settings: ConverterSett var keepStatement = true if (statement is AssignmentExpression) { val assignee = statement.left - if (assignee is QualifiedExpression && (assignee.qualifier as? Identifier)?.name == SecondaryConstructor.tempValIdentifier.name) { + if (assignee is QualifiedExpression && (assignee.qualifier as? Identifier)?.name == SecondaryConstructor.tempValName) { val name = (assignee.identifier as Identifier).name for (field in finalOrWithEmptyInitializerFields) { if (name == field.identifier.name) { @@ -245,24 +245,27 @@ public class Converter private(val project: Project, val settings: ConverterSett } val initializer = MethodCallExpression.buildNotNull(null, className.name, finalOrWithEmptyInitializerFields.map { initializers[it]!! }) - val localVar = LocalVariable(SecondaryConstructor.tempValIdentifier, + initializer.assignNoPrototype() + val localVar = LocalVariable(SecondaryConstructor.tempValIdentifier(), Annotations.Empty, Modifiers.Empty, { ClassType(className, listOf(), Nullability.NotNull, settings) }, initializer, true, - settings) - newStatements.add(0, DeclarationStatement(listOf(localVar))) - constructor.block = Block(newStatements, LBrace(), RBrace()) + settings).assignNoPrototype() + newStatements.add(0, DeclarationStatement(listOf(localVar)).assignNoPrototype()) + constructor.block = Block(newStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype() } //TODO: comments? val parameters = finalOrWithEmptyInitializerFields.map { field -> val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var - Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { it in ACCESS_MODIFIERS }) + Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { it in ACCESS_MODIFIERS }).assignPrototypesFrom(field) } - val primaryConstructor = PrimaryConstructor(this, Annotations.Empty, Modifiers(listOf(Modifier.PRIVATE)), ParameterList(parameters), Block.Empty) + val modifiers = Modifiers(listOf(Modifier.PRIVATE)).assignNoPrototype() + val parameterList = ParameterList(parameters).assignNoPrototype() + val primaryConstructor = PrimaryConstructor(this, Annotations.Empty, modifiers, parameterList, Block.Empty) val updatedMembers = classBody.normalMembers.filter { !finalOrWithEmptyInitializerFields.contains(it) } return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace) } @@ -330,7 +333,7 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { val returnType = typeConverter.convertMethodReturnType(method) - val annotations = convertAnnotations(method) + convertThrows(method) + val annotations = (convertAnnotations(method) + convertThrows(method)).assignNoPrototype() var modifiers = convertModifiers(method) if (method.isConstructor()) { @@ -453,7 +456,7 @@ public class Converter private(val project: Project, val settings: ConverterSett convertAnnotations(parameter) + convertAnnotations(field), convertModifiers(field).filter { it in ACCESS_MODIFIERS }).assignPrototypes(listOf(parameter, field), inheritBlankLinesBefore = false) } - }) + }).assignPrototype(constructor.getParameterList()) return PrimaryConstructor(this, annotations, modifiers, parameterList, block).assignPrototype(constructor) } @@ -524,7 +527,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } fun convertTypeElement(element: PsiTypeElement?): TypeElement - = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())).assignPrototype(element) + = TypeElement(if (element == null) ErrorType().assignNoPrototype() else typeConverter.convertType(element.getType())).assignPrototype(element) private fun convertToNotNullableTypes(types: Array): List = types.map { typeConverter.convertType(it, Nullability.NotNull) } @@ -608,13 +611,13 @@ public class Converter private(val project: Project, val settings: ConverterSett } val list = annotations.map { convertAnnotation(it, owner is PsiLocalVariable) }.filterNotNull() //TODO: brackets are also needed for local classes - return Annotations(list, newLines) + return Annotations(list, newLines).assignNoPrototype() } private fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { val qualifiedName = annotation.getQualifiedName() if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { - return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets).assignPrototype(annotation) //TODO: insert comment + return Annotation(Identifier("deprecated").assignNoPrototype(), listOf(null to LiteralExpression("\"\"").assignNoPrototype()), brackets).assignPrototype(annotation) //TODO: insert comment } val nameRef = annotation.getNameReferenceElement() @@ -625,7 +628,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val method = annotationClass?.findMethodsByName(it.getName() ?: "value", false)?.firstOrNull() val expectedType = method?.getReturnType() - val attrName = it.getName()?.let { Identifier(it) } + val attrName = it.getName()?.let { Identifier(it).assignNoPrototype() } val value = it.getValue() val isVarArg = method == lastMethod /* converted to vararg in Kotlin */ @@ -638,7 +641,7 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List { return when (value) { - is PsiExpression -> listOf(convertExpression(value as? PsiExpression, expectedType)) + is PsiExpression -> listOf(convertExpression(value as? PsiExpression, expectedType).assignPrototype(value)) is PsiArrayInitializerMemberValue -> { val componentType = (expectedType as? PsiArrayType)?.getComponentType() @@ -650,27 +653,35 @@ public class Converter private(val project: Project, val settings: ConverterSett val expectedTypeConverted = typeConverter.convertType(expectedType) if (expectedTypeConverted is ArrayType) { val array = createArrayInitializerExpression(expectedTypeConverted, componentsConverted, needExplicitType = false) - listOf(if (isVararg) StarExpression(array) else array) + if (isVararg) { + listOf(StarExpression(array.assignNoPrototype()).assignPrototype(value)) + } + else { + listOf(array.assignPrototype(value)) + } } else { - listOf(DummyStringExpression(value.getText()!!)) + listOf(DummyStringExpression(value.getText()!!).assignPrototype(value)) } } } - else -> listOf(DummyStringExpression(value?.getText() ?: "")) + else -> listOf(DummyStringExpression(value?.getText() ?: "").assignPrototype(value)) } } private fun convertThrows(method: PsiMethod): Annotations { val throwsList = method.getThrowsList() val types = throwsList.getReferencedTypes() + val refElements = throwsList.getReferenceElements() + assert(types.size == refElements.size) if (types.isEmpty()) return Annotations.Empty - val annotation = Annotation(Identifier("throws"), - types.map { null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeConverter.convertType(it, Nullability.NotNull))) }, - false) - return Annotations(listOf(annotation.assignPrototype(throwsList)), - true) + 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 annotation = Annotation(Identifier("throws").assignNoPrototype(), arguments, false) + return Annotations(listOf(annotation.assignPrototype(throwsList)), true).assignPrototype(throwsList) } private val TYPE_MAP: Map = mapOf( diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 4458f631e5c..1bbae9ac64b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -26,6 +26,8 @@ import org.jetbrains.jet.j2k.ast.Import import org.jetbrains.jet.j2k.ast.ImportList import org.jetbrains.jet.j2k.ast.assignPrototype import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT +import org.jetbrains.jet.j2k.ast.assignNoPrototype +import org.jetbrains.jet.j2k.ast.ErrorType class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) { private val nullabilityCache = HashMap() @@ -40,12 +42,12 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver private var importNames: Set = setOf() public val importsToAdd: Collection - get() = classesToImport.map { Import(it) } + get() = classesToImport.map { Import(it).assignNoPrototype() } public fun convertType(`type`: PsiType?, nullability: Nullability = Nullability.Default): Type { - if (`type` == null) return Type.Empty + if (`type` == null) return ErrorType().assignNoPrototype() - val result = `type`.accept(TypeVisitor(this, importNames, classesToImport))!! + val result = `type`.accept(TypeVisitor(this, importNames, classesToImport))!!.assignNoPrototype() return when (nullability) { Nullability.NotNull -> result.toNotNullType() Nullability.Nullable -> result.toNullableType() diff --git a/j2k/src/org/jetbrains/jet/j2k/Utils.kt b/j2k/src/org/jetbrains/jet/j2k/Utils.kt index eee0ce84cfe..b866f27c523 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Utils.kt @@ -59,20 +59,22 @@ fun PsiModifierListOwner.nullabilityFromAnnotations(): Nullability { fun getDefaultInitializer(field: Field): Expression { val t = field.`type` - if (t.isNullable) { - return LiteralExpression("null") + val result = if (t.isNullable) { + LiteralExpression("null") } - - if (t is PrimitiveType) { - when(t.name.name) { - "Boolean" -> return LiteralExpression("false") - "Char" -> return LiteralExpression("' '") - "Double" -> return MethodCallExpression.buildNotNull(LiteralExpression("0"), OperatorConventions.DOUBLE.toString()) - "Float" -> return MethodCallExpression.buildNotNull(LiteralExpression("0"), OperatorConventions.FLOAT.toString()) + else if (t is PrimitiveType) { + when (t.name.name) { + "Boolean" -> LiteralExpression("false") + "Char" -> LiteralExpression("' '") + "Double" -> MethodCallExpression.buildNotNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.DOUBLE.toString()) + "Float" -> MethodCallExpression.buildNotNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.FLOAT.toString()) + else -> LiteralExpression("0") } } - - return LiteralExpression("0") + else { + LiteralExpression("0") + } + return result.assignNoPrototype() } fun isQualifierEmptyOrThis(ref: PsiReferenceExpression): Boolean { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index 57b51cc5775..31172b2742c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -58,6 +58,8 @@ class Annotations(val annotations: List, val newLines: Boolean) : El } } + override val isEmpty: Boolean = annotations.isEmpty() + fun plus(other: Annotations) = Annotations(annotations + other.annotations, newLines || other.newLines) class object { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 5c29743fb18..3a3da3bc732 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -25,7 +25,7 @@ abstract class Constructor( modifiers: Modifiers, parameterList: ParameterList, block: Block -) : Function(converter, Identifier.Empty, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) +) : Function(converter, Identifier.Empty, annotations, modifiers, ErrorType(), TypeParameterList.Empty, parameterList, block, false) class PrimaryConstructor(converter: Converter, annotations: Annotations, @@ -54,18 +54,22 @@ class SecondaryConstructor(converter: Converter, public fun toFactoryFunction(containingClass: Class?): Function { val statements = ArrayList(block?.statements ?: listOf()) - statements.add(ReturnStatement(tempValIdentifier)) - val block = Block(statements, block?.lBrace ?: LBrace(), block?.rBrace ?: RBrace()) - val typeParameters = ArrayList() - if (containingClass != null) { - typeParameters.addAll(containingClass.typeParameterList.parameters) + statements.add(ReturnStatement(tempValIdentifier()).assignNoPrototype()) + val newBlock = Block(statements, block?.lBrace ?: LBrace().assignNoPrototype(), block?.rBrace ?: RBrace().assignNoPrototype()) + if (this.block != null) { + newBlock.assignPrototypesFrom(block!!) } - return Function(converter, Identifier("create"), annotations, modifiers, - ClassType(containingClass?.name ?: Identifier.Empty, typeParameters, Nullability.NotNull, converter.settings), - TypeParameterList(typeParameters), parameterList, block, false).assignPrototypesFrom(this) + + val typeParameters = if (containingClass != null) containingClass.typeParameterList.parameters else listOf() + val typeParameterList = TypeParameterList(typeParameters).assignNoPrototype() + + val returnType = ClassType(containingClass?.name ?: Identifier.Empty, typeParameters, Nullability.NotNull, converter.settings).assignNoPrototype() + return Function(converter, Identifier("create").assignNoPrototype(), annotations, modifiers, + returnType, typeParameterList, parameterList, newBlock, false).assignPrototypesFrom(this) } class object { - public val tempValIdentifier: Identifier = Identifier("__", false) + public val tempValName: String = "__" + public fun tempValIdentifier(): Identifier = Identifier(tempValName, false).assignNoPrototype() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 2a1b4f526b4..08e3b67e822 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -20,17 +20,23 @@ import org.jetbrains.jet.j2k.* import com.intellij.psi.PsiElement fun TElement.assignPrototype(prototype: PsiElement?, inheritBlankLinesBefore: Boolean = true): TElement { - assignPrototypeInfos(if (prototype != null) listOf(PrototypeInfo(prototype, inheritBlankLinesBefore)) else listOf()) + prototypes = if (prototype != null) listOf(PrototypeInfo(prototype, inheritBlankLinesBefore)) else listOf() return this } fun TElement.assignPrototypes(prototypes: List, inheritBlankLinesBefore: Boolean): TElement { - assignPrototypeInfos(prototypes.map { PrototypeInfo(it, inheritBlankLinesBefore) }) + this.prototypes = prototypes.map { PrototypeInfo(it, inheritBlankLinesBefore) } + return this +} + +fun TElement.assignNoPrototype(): TElement { + prototypes = listOf() return this } fun TElement.assignPrototypesFrom(element: Element): TElement { - assignPrototypeInfos(element.prototypes) + prototypes = element.prototypes + createdAt = element.createdAt return this } @@ -43,12 +49,17 @@ fun Element.canonicalCode(): String { } abstract class Element { - public var prototypes: List = listOf() - private set + public var prototypes: List? = null + set(value) { + // no prototypes assigned to empty elements because they can be singleton instances (and they are not needed anyway) + if (isEmpty) { + $prototypes = listOf() + return + } + $prototypes = value + } - public fun assignPrototypeInfos(prototypes: List) { - this.prototypes = prototypes - } + public var createdAt: String = "Element creation stacktraces turned off. Uncomment initializer of Element.createdAt." //Exception().getStackTrace().joinToString("\n") /** This method should not be used anywhere except for CodeBuilder! Use CodeBuilder.append instead. */ public abstract fun generateCode(builder: CodeBuilder) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index eee1b070edf..df207704928 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -116,6 +116,10 @@ class PolyadicExpression(val expressions: List, val token: String) : } class LambdaExpression(val arguments: String?, val block: Block) : Expression() { + { + assignPrototypesFrom(block) + } + override fun generateCode(builder: CodeBuilder) { builder append block.lBrace append " " @@ -155,7 +159,7 @@ fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List null } if (conversionFunction != null) { - return MethodCallExpression.buildNotNull(initializer, conversionFunction) + return MethodCallExpression.buildNotNull(initializer, conversionFunction).assignNoPrototype() } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 2ef4af8227a..924a55238a3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -57,8 +57,8 @@ class MethodCallExpression( typeArguments: List, isNullable: Boolean, lambdaArgument: LambdaExpression? = null): MethodCallExpression { - val identifier = Identifier(methodName, false) - return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier) else identifier, + val identifier = Identifier(methodName, false).assignNoPrototype() + return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier).assignNoPrototype() else identifier, arguments, typeArguments, isNullable, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index 91956cb8c85..8258f5420c9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -156,7 +156,10 @@ class SwitchContainer(val expression: Expression, val caseContainers: List, statements: List) : Statement() { - private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, LBrace(), RBrace(), true) + private val block = run { + val filteredStatements = statements.filterNot { it is BreakStatement || it is ContinueStatement } + Block(filteredStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype() + } override fun generateCode(builder: CodeBuilder) { builder.append(caseStatement, ", ").append(" -> ").append(block) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt index 049d69702ee..bcf79534282 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt @@ -67,7 +67,7 @@ fun Converter.convertTypeParameter(psiTypeParameter: PsiTypeParameter): TypePara fun Converter.convertTypeParameterList(typeParameterList: PsiTypeParameterList?): TypeParameterList { return if (typeParameterList != null) - TypeParameterList(typeParameterList.getTypeParameters()!!.toList().map { convertTypeParameter(it) }) + TypeParameterList(typeParameterList.getTypeParameters()!!.toList().map { convertTypeParameter(it) }).assignPrototype(typeParameterList) else TypeParameterList.Empty } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 344a4e02bdf..1e4e6fc71c2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* -fun Type.isUnit(): Boolean = this == Type.Unit +fun Type.isUnit(): Boolean = this is UnitType enum class Nullability { Nullable @@ -51,26 +51,6 @@ abstract class Type() : Element() { open fun toNullableType(): Type = this - object Empty : NotNullType() { - override fun generateCode(builder: CodeBuilder) { - builder.append("UNRESOLVED_TYPE") - } - } - - object Unit: NotNullType() { - override fun generateCode(builder: CodeBuilder) { - builder.append("Unit") - } - } - - object Null: Type() { - override val isNullable: Boolean = true - - override fun generateCode(builder: CodeBuilder) { - builder.append("???") - } - } - override fun equals(other: Any?): Boolean = other is Type && other.canonicalCode() == this.canonicalCode() override fun hashCode(): Int = canonicalCode().hashCode() @@ -78,6 +58,26 @@ abstract class Type() : Element() { override fun toString(): String = canonicalCode() } +class UnitType : NotNullType() { + override fun generateCode(builder: CodeBuilder) { + builder.append("Unit") + } +} + +class NullType : Type() { + override val isNullable: Boolean = true + + override fun generateCode(builder: CodeBuilder) { + builder.append("???") + } +} + +class ErrorType : NotNullType() { + override fun generateCode(builder: CodeBuilder) { + builder.append("UNRESOLVED_TYPE") + } +} + class ClassType(val name: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { @@ -85,8 +85,8 @@ class ClassType(val name: Identifier, val typeArgs: List, nullability: builder.append(name).append(typeArgs, ", ", "<", ">").append(isNullableStr) } - override fun toNotNullType(): Type = ClassType(name, typeArgs, Nullability.NotNull, settings) - override fun toNullableType(): Type = ClassType(name, typeArgs, Nullability.Nullable, settings) + override fun toNotNullType(): Type = ClassType(name, typeArgs, Nullability.NotNull, settings).assignPrototypesFrom(this) + override fun toNullableType(): Type = ClassType(name, typeArgs, Nullability.Nullable, settings).assignPrototypesFrom(this) } class ArrayType(val elementType: Type, nullability: Nullability, settings: ConverterSettings) @@ -101,8 +101,8 @@ class ArrayType(val elementType: Type, nullability: Nullability, settings: Conve } } - override fun toNotNullType(): Type = ArrayType(elementType, Nullability.NotNull, settings) - override fun toNullableType(): Type = ArrayType(elementType, Nullability.Nullable, settings) + override fun toNotNullType(): Type = ArrayType(elementType, Nullability.NotNull, settings).assignPrototypesFrom(this) + override fun toNullableType(): Type = ArrayType(elementType, Nullability.Nullable, settings).assignPrototypesFrom(this) } class InProjectionType(val bound: Type) : NotNullType() { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 04ae75a7702..84c10c6ef77 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -43,7 +43,7 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { override fun visitReferenceElement(reference: PsiJavaCodeReferenceElement) { val types = typeConverter.convertTypes(reference.getTypeParameters()) if (!reference.isQualified()) { - result = ReferenceElement(Identifier(reference.getReferenceName()!!), types) + result = ReferenceElement(Identifier(reference.getReferenceName()!!).assignNoPrototype(), types) } else { var code = Identifier.toKotlin(reference.getReferenceName()!!) @@ -53,7 +53,7 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { code = Identifier.toKotlin(p.getReferenceName()!!) + "." + code qualifier = p.getQualifier() } - result = ReferenceElement(Identifier(code), types) + result = ReferenceElement(Identifier(code).assignNoPrototype(), types) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 0fc68ee8b0c..002007477df 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -78,7 +78,7 @@ class ExpressionVisitor(private val converter: Converter, val lhs = converter.convertExpression(expression.getLExpression()) val rhs = converter.convertExpression(expression.getRExpression()!!, expression.getLExpression().getType()) if (!secondOp.isEmpty()) { - result = AssignmentExpression(lhs, BinaryExpression(lhs, rhs, secondOp), " = ") + result = AssignmentExpression(lhs, BinaryExpression(lhs, rhs, secondOp).assignNoPrototype(), " = ") } else { result = AssignmentExpression(lhs, rhs, expression.getOperationSign().getText()!!) @@ -173,16 +173,16 @@ class ExpressionVisitor(private val converter: Converter, origin as JetNamedDeclaration val parameterCount = target.getParameterList().getParameters().size if (parameterCount == arguments.size) { - val propertyName = Identifier(property.getName()!!, isNullable) + val propertyName = Identifier(property.getName()!!, isNullable).assignNoPrototype() val isExtension = property.isExtensionDeclaration() val propertyAccess = if (isTopLevel) { if (isExtension) - QualifiedExpression(converter.convertExpression(arguments.firstOrNull()), propertyName) + QualifiedExpression(converter.convertExpression(arguments.firstOrNull()), propertyName).assignNoPrototype() else propertyName } else { - QualifiedExpression(converter.convertExpression(methodExpr.getQualifierExpression()), propertyName) + QualifiedExpression(converter.convertExpression(methodExpr.getQualifierExpression()), propertyName).assignNoPrototype() } when(if (isExtension) parameterCount - 1 else parameterCount) { @@ -266,8 +266,8 @@ class ExpressionVisitor(private val converter: Converter, // non-primary constructor converted to factory method in class object val reference = expression.getClassReference() val typeParameters = if (reference != null) typeConverter.convertTypes(reference.getTypeParameters()) else listOf() - return QualifiedExpression(Identifier(constructor.getName(), false), - MethodCallExpression.buildNotNull(null, "create", converter.convertExpressions(arguments), typeParameters)) + return QualifiedExpression(Identifier(constructor.getName(), false).assignNoPrototype(), + MethodCallExpression.buildNotNull(null, "create", converter.convertExpressions(arguments), typeParameters).assignNoPrototype()) } return NewClassExpression(converter.convertElement(classReference), @@ -303,20 +303,20 @@ class ExpressionVisitor(private val converter: Converter, val target = expression.getReference()?.resolve() val isNullable = if (target is PsiVariable) typeConverter.variableNullability(target).isNullable(converter.settings) else false val referencedName = expression.getReferenceName()!! - var identifier: Expression = Identifier(referencedName, isNullable) + var identifier: Expression = Identifier(referencedName, isNullable).assignNoPrototype() val qualifier = expression.getQualifierExpression() val containingConstructor = expression.getContainingConstructor() val insideSecondaryConstructor = containingConstructor != null && !containingConstructor.isPrimaryConstructor() if (insideSecondaryConstructor && (expression.getReference()?.resolve() as? PsiField)?.getContainingClass() == containingConstructor!!.getContainingClass()) { - identifier = QualifiedExpression(SecondaryConstructor.tempValIdentifier, Identifier(referencedName, isNullable)) + identifier = QualifiedExpression(SecondaryConstructor.tempValIdentifier(), Identifier(referencedName, isNullable).assignNoPrototype()) } else if (insideSecondaryConstructor && expression.isThisConstructorCall()) { - identifier = Identifier("val __ = " + (containingConstructor?.getContainingClass()?.getNameIdentifier()?.getText() ?: "")) + identifier = Identifier("val __ = " + (containingConstructor?.getContainingClass()?.getNameIdentifier()?.getText() ?: "")).assignNoPrototype() } else if (qualifier != null && qualifier.getType() is PsiArrayType && referencedName == "length") { - identifier = Identifier("size", isNullable) + identifier = Identifier("size", isNullable).assignNoPrototype() } else if (qualifier != null) { if (referencedName == JvmAbi.CLASS_OBJECT_FIELD || referencedName == JvmAbi.INSTANCE_FIELD) { @@ -362,13 +362,15 @@ class ExpressionVisitor(private val converter: Converter, } override fun visitSuperExpression(expression: PsiSuperExpression) { - val qualifier = expression.getQualifier()?.getReferenceName() - result = SuperExpression(if (qualifier != null) Identifier(qualifier) else Identifier.Empty) + val psiQualifier = expression.getQualifier() + val qualifier = psiQualifier?.getReferenceName() + result = SuperExpression(if (qualifier != null) Identifier(qualifier).assignPrototype(psiQualifier) else Identifier.Empty) } override fun visitThisExpression(expression: PsiThisExpression) { - val qualifier = expression.getQualifier()?.getReferenceName() - result = ThisExpression(if (qualifier != null) Identifier(qualifier) else Identifier.Empty) + val psiQualifier = expression.getQualifier() + val qualifier = psiQualifier?.getReferenceName() + result = ThisExpression(if (qualifier != null) Identifier(qualifier).assignPrototype(psiQualifier) else Identifier.Empty) } override fun visitTypeCastExpression(expression: PsiTypeCastExpression) { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index 2bcdc76238e..3fc7a3e9e90 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -45,14 +45,16 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition, description)) } else { - result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, LambdaExpression(null, Block(listOf(description), LBrace(), RBrace()))) + val block = Block(listOf(description), LBrace().assignNoPrototype(), RBrace().assignNoPrototype()) + val lambda = LambdaExpression(null, block.assignNoPrototype()) + result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, lambda) } } } override fun visitBlockStatement(statement: PsiBlockStatement) { val block = converter.convertBlock(statement.getCodeBlock()) - result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block)) + result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block).assignNoPrototype()) } override fun visitBreakStatement(statement: PsiBreakStatement) { @@ -118,7 +120,10 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito && loopVar.getNameIdentifier() != null && onceWritableIterator) { val end = converter.convertExpression((condition as PsiBinaryExpression).getROperand()) - val endExpression = if (operationTokenType == JavaTokenType.LT) BinaryExpression(end, LiteralExpression("1"), "-") else end + val endExpression = if (operationTokenType == JavaTokenType.LT) + BinaryExpression(end, LiteralExpression("1").assignNoPrototype(), "-").assignNoPrototype() + else + end result = ForeachWithRangeStatement(loopVar.declarationIdentifier(), converter.convertExpression(loopVar.getInitializer()), endExpression, @@ -142,7 +147,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito } if (nameConflict) { - Block(listOf(converter.convertStatement(body), updateConverted), LBrace(), RBrace(), true) + val statements = listOf(converter.convertStatement(body), updateConverted) + Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype() } else { val block = converter.convertBlock(body.getCodeBlock(), true) @@ -150,18 +156,20 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito } } else { - Block(listOf(converter.convertStatement(body), updateConverted), LBrace(), RBrace(), true) + val statements = listOf(converter.convertStatement(body), updateConverted) + Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype() } val whileStatement = WhileStatement( - if (condition != null) converter.convertExpression(condition) else LiteralExpression("true"), + if (condition != null) converter.convertExpression(condition) else LiteralExpression("true").assignNoPrototype(), whileBody, - statement.isInSingleLine()) + statement.isInSingleLine()).assignNoPrototype() if (initializationConverted.isEmpty) { result = whileStatement } else { - val block = Block(listOf(initializationConverted, whileStatement), LBrace(), RBrace()) + val statements = listOf(initializationConverted, whileStatement) + val block = Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype() result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block)) } } @@ -216,7 +224,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito val result = ArrayList() var pendingLabels = ArrayList() var i = 0 - var hasDefaultCase: Boolean = false + var hasDefaultCase = false for (ls in cases) { if (ls.size() > 0) { var label = ls[0] as PsiSwitchLabelStatement @@ -225,21 +233,19 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito // TODO assert("not a right index") {allSwitchStatements?.get(i) == label} if (ls.size() > 1) { pendingLabels.add(converter.convertStatement(label)) - val slice: List = ls.subList(1, (ls.size())) + val slice = ls.subList(1, (ls.size())) fun convertStatements(elements: List): List = elements.map { if (it is PsiStatement) converter.convertStatement(it) else null }.filterNotNull() if (!containsBreak(slice)) { - val statements = ArrayList(convertStatements(slice)) - statements.addAll(convertStatements(getAllToNextBreak(allSwitchStatements, i + ls.size()))) - result.add(CaseContainer(pendingLabels, statements)) - pendingLabels = ArrayList() + val statements = convertStatements(slice) + convertStatements(getAllToNextBreak(allSwitchStatements, i + ls.size())) + result.add(CaseContainer(pendingLabels, statements).assignNoPrototype()) } else { - result.add(CaseContainer(pendingLabels, convertStatements(slice))) - pendingLabels = ArrayList() + result.add(CaseContainer(pendingLabels, convertStatements(slice)).assignNoPrototype()) } + pendingLabels = ArrayList() } else { pendingLabels.add(converter.convertStatement(label)) @@ -247,8 +253,9 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito i += ls.size() } } - if (!hasDefaultCase) - result.add(CaseContainer(listOf(DefaultSwitchLabelStatement()), ArrayList())) + if (!hasDefaultCase) { + result.add(CaseContainer(listOf(DefaultSwitchLabelStatement().assignNoPrototype()), listOf()).assignNoPrototype()) + } return result } @@ -268,7 +275,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito val catchBlockParameters = tryStatement.getCatchBlockParameters() catchBlocks.indices.map { CatchStatement(converter.convertParameter(catchBlockParameters[it], Nullability.NotNull), - converter.convertBlock(catchBlocks[it])) + converter.convertBlock(catchBlocks[it])).assignNoPrototype() } } val finallyConverted = converter.convertBlock(tryStatement.getFinallyBlock()) @@ -292,7 +299,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito val returns = collectReturns(tryBlock) //TODO: support other returns when non-local returns supported by Kotlin if (returns.size == 1 && returns.single() == tryBlock!!.getStatements().last()) { - wrapResultStatement = { ReturnStatement(it) } + wrapResultStatement = { ReturnStatement(it).assignPrototype(returns.single()) } converterForBody = converter.withStatementVisitor { object : StatementVisitor(it) { override fun visitReturnStatement(statement: PsiReturnStatement) { if (statement == returns.single()) { @@ -310,14 +317,16 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito 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) - block = Block(listOf(expression), LBrace(), RBrace()) + expression.assignNoPrototype() + block = Block(listOf(expression), LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype() } if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { return wrapResultStatement(expression) } - return TryStatement(Block(listOf(wrapResultStatement(expression)), LBrace(), RBrace(), true), catchesConverted, finallyConverted) + block = Block(listOf(wrapResultStatement(expression)), LBrace().assignPrototype(tryBlock?.getLBrace()), RBrace().assignPrototype(tryBlock?.getRBrace()), true) + return TryStatement(block.assignPrototype(tryBlock), catchesConverted, finallyConverted) } private fun collectReturns(block: PsiCodeBlock?): Collection { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 718835039df..c11ea5193d3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -31,16 +31,16 @@ class TypeVisitor(private val converter: TypeConverter, private val importNames: override fun visitPrimitiveType(primitiveType: PsiPrimitiveType): Type { val name = primitiveType.getCanonicalText() return if (name == "void") { - Type.Unit + UnitType() } else if (PRIMITIVE_TYPES_NAMES.contains(name)) { - PrimitiveType(Identifier(StringUtil.capitalize(name))) + PrimitiveType(Identifier(StringUtil.capitalize(name)).assignNoPrototype()) } else if (name == "null") { - Type.Null + NullType() } else { - PrimitiveType(Identifier(name)) + PrimitiveType(Identifier(name).assignNoPrototype()) } } @@ -81,7 +81,7 @@ class TypeVisitor(private val converter: TypeConverter, private val importNames: if (kotlinShortName == getShortName(javaClassName!!) && importNames.contains(getPackageName(javaClassName) + ".*")) { classesToImport.add(kotlinClassName) } - return Identifier(kotlinShortName) + return Identifier(kotlinShortName).assignNoPrototype() } } @@ -95,11 +95,11 @@ class TypeVisitor(private val converter: TypeConverter, private val importNames: result = Identifier.toKotlin(codeRefElement.getReferenceName()!!) + "." + result qualifier = codeRefElement.getQualifier() } - return Identifier(result) + return Identifier(result).assignNoPrototype() } } - return Identifier(classType.getClassName() ?: "") + return Identifier(classType.getClassName() ?: "").assignNoPrototype() } private fun getPackageName(className: String): String = className.substring(0, className.lastIndexOf('.'))