Prepare repository for merge into master
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: org.jetbrains.jet.j2k.JavaToKotlinCli
|
||||
|
||||
@@ -0,0 +1,879 @@
|
||||
package org.jetbrains.jet.j2k
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import com.google.common.collect.Sets
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.jet.j2k.ast.*
|
||||
import org.jetbrains.jet.j2k.ast.types.ClassType
|
||||
import org.jetbrains.jet.j2k.ast.types.EmptyType
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import org.jetbrains.jet.j2k.visitors.*
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
import com.intellij.psi.CommonClassNames.*
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions.*
|
||||
import com.intellij.openapi.util.Pair
|
||||
import java.text.MessageFormat
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.jet.config.CompilerConfiguration
|
||||
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||
import org.jetbrains.jet.util.QualifiedNamesUtil
|
||||
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap
|
||||
|
||||
public open class Converter() {
|
||||
|
||||
private var classIdentifiersSet: MutableSet<String> = Sets.newHashSet()!!
|
||||
|
||||
private val dispatcher: Dispatcher = Dispatcher(this)
|
||||
|
||||
private val flags: MutableSet<J2KConverterFlags?>? = Sets.newHashSet()
|
||||
|
||||
private val jetCoreEnvironment = JetCoreEnvironment(
|
||||
object : Disposable {
|
||||
public override fun dispose() {
|
||||
}
|
||||
}, CompilerConfiguration())
|
||||
|
||||
|
||||
private val project = jetCoreEnvironment.getProject();
|
||||
|
||||
private val javaToKotlinClassMap: JavaToKotlinClassMap = JavaToKotlinClassMap.getInstance()
|
||||
|
||||
public open var methodReturnType: PsiType? = null
|
||||
private set
|
||||
|
||||
public open fun addFlag(flag: J2KConverterFlags): Boolean {
|
||||
return flags?.add(flag)!!
|
||||
}
|
||||
|
||||
public open fun hasFlag(flag: J2KConverterFlags): Boolean {
|
||||
return flags?.contains(flag)!!
|
||||
}
|
||||
|
||||
public open fun setClassIdentifiers(identifiers: MutableSet<String>) {
|
||||
classIdentifiersSet = identifiers
|
||||
}
|
||||
|
||||
public open fun getClassIdentifiers(): Set<String> {
|
||||
return Collections.unmodifiableSet(classIdentifiersSet)
|
||||
}
|
||||
|
||||
public open fun clearClassIdentifiers(): Unit {
|
||||
classIdentifiersSet.clear()
|
||||
}
|
||||
|
||||
public open fun elementToKotlin(element: PsiElement): String {
|
||||
val kElement = topElementToElement(element)
|
||||
return kElement?.toKotlin() ?: ""
|
||||
}
|
||||
|
||||
public open fun topElementToElement(element: PsiElement?): Node? = when(element) {
|
||||
is PsiJavaFile -> fileToFile(element)
|
||||
is PsiClass -> classToClass(element)
|
||||
is PsiMethod -> methodToFunction(element)
|
||||
is PsiField -> fieldToField(element, element.getContainingClass())
|
||||
is PsiStatement -> statementToStatement(element)
|
||||
is PsiExpression -> expressionToExpression(element)
|
||||
is PsiComment -> Comment(element.getText()!!)
|
||||
else -> null
|
||||
}
|
||||
|
||||
public open fun fileToFile(javaFile: PsiJavaFile): File {
|
||||
return fileToFile(javaFile, Collections.emptyList<String>())
|
||||
}
|
||||
|
||||
public open fun fileToFileWithCompatibilityImport(javaFile: PsiJavaFile): File {
|
||||
return fileToFile(javaFile, Collections.singletonList("kotlin.compatibility.*"))
|
||||
}
|
||||
|
||||
private fun fileToFile(javaFile: PsiJavaFile, additionalImports: List<String>): File {
|
||||
val importList: PsiImportList? = javaFile.getImportList()
|
||||
val imports: MutableList<Import> = (if (importList == null)
|
||||
arrayListOf()
|
||||
else
|
||||
ArrayList(importsToImportList(importList.getAllImportStatements()) filter {
|
||||
// If name is invalid, like with star imports, don't try to filter
|
||||
if (!QualifiedNamesUtil.isValidJavaFqName(it.name))
|
||||
true
|
||||
else {
|
||||
// If imported class has a kotlin analog, drop the import
|
||||
val kotlinAnalogsForClass = javaToKotlinClassMap.mapPlatformClass(FqName(it.name))
|
||||
kotlinAnalogsForClass.isEmpty()
|
||||
}
|
||||
}))
|
||||
for (i : String in additionalImports)
|
||||
imports.add(Import(i))
|
||||
|
||||
val body: ArrayList<Node> = arrayListOf()
|
||||
for(element in javaFile.getChildren()) {
|
||||
if (element !is PsiImportStatementBase) {
|
||||
val node = topElementToElement(element)
|
||||
if (node != null) {
|
||||
body.add(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
return File(quoteKeywords(javaFile.getPackageName()), imports, body, createMainFunction(javaFile))
|
||||
}
|
||||
|
||||
public open fun anonymousClassToAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass {
|
||||
return AnonymousClass(this, getMembers(anonymousClass))
|
||||
}
|
||||
|
||||
private fun getMembers(psiClass: PsiClass): MutableList<Node> {
|
||||
val members = ArrayList<Node>()
|
||||
val lbraceOffset = psiClass.getLBrace()?.getTextRange()?.getStartOffset() ?: 0
|
||||
for (e : PsiElement? in psiClass.getChildren()) {
|
||||
val isDocComment = e?.getTextRange()?.getStartOffset() ?: 0 < lbraceOffset
|
||||
if (isDocComment) continue
|
||||
val converted = memberToMember(e, psiClass)
|
||||
if (converted != null) members.add(converted)
|
||||
}
|
||||
return members
|
||||
}
|
||||
|
||||
private fun getDocComments(element: PsiElement): List<Node> {
|
||||
val comments = ArrayList<Node>()
|
||||
val textOffset = element.getTextOffset()
|
||||
for (e : PsiElement? in element.getChildren()) {
|
||||
if (e is PsiComment && e.getTextRange()?.getStartOffset() ?: 0 < textOffset) {
|
||||
comments.add(Comment(e.getText()!!));
|
||||
}
|
||||
}
|
||||
return comments
|
||||
}
|
||||
|
||||
private fun memberToMember(e: PsiElement?, containingClass: PsiClass): Node? = when(e) {
|
||||
is PsiMethod -> methodToFunction(e, true)
|
||||
is PsiField -> fieldToField(e, containingClass)
|
||||
is PsiClass -> classToClass(e)
|
||||
is PsiClassInitializer -> initializerToInitializer(e)
|
||||
is PsiComment -> Comment(e.getText()!!)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun classToClass(psiClass: PsiClass): Class {
|
||||
val modifiers: Set<Modifier> = modifiersListToModifiersSet(psiClass.getModifierList())
|
||||
val fields: List<Field> = fieldsToFieldList(psiClass.getFields(), psiClass)
|
||||
val typeParameters: List<Element> = elementsToElementList(psiClass.getTypeParameters())
|
||||
val implementsTypes: List<Type> = typesToNotNullableTypeList(psiClass.getImplementsListTypes())
|
||||
val extendsTypes: List<Type> = typesToNotNullableTypeList(psiClass.getExtendsListTypes())
|
||||
val name: Identifier = Identifier(psiClass.getName()!!)
|
||||
val baseClassParams= ArrayList<Expression>()
|
||||
val members = getMembers(psiClass)
|
||||
val docComments = getDocComments(psiClass)
|
||||
val visitor: SuperVisitor = SuperVisitor()
|
||||
psiClass.accept(visitor)
|
||||
val resolvedSuperCallParameters = visitor.resolvedSuperCallParameters
|
||||
if (resolvedSuperCallParameters.size() == 1) {
|
||||
val psiExpressionList = resolvedSuperCallParameters.iterator().next()
|
||||
baseClassParams.addAll(expressionsToExpressionList(psiExpressionList.getExpressions()))
|
||||
}
|
||||
|
||||
if (!psiClass.isEnum() && !psiClass.isInterface() && psiClass.getConstructors().size > 1 &&
|
||||
getPrimaryConstructorForThisCase(psiClass) == null) {
|
||||
val finalOrWithEmptyInitializer: List<Field> = getFinalOrWithEmptyInitializer(fields)
|
||||
val initializers = HashMap<String, String>()
|
||||
for (m in members) {
|
||||
if (m is Constructor) {
|
||||
if (!m.isPrimary) {
|
||||
for (fo in finalOrWithEmptyInitializer){
|
||||
val init: String = getDefaultInitializer(fo)
|
||||
initializers.put(fo.identifier.toKotlin(), init)
|
||||
}
|
||||
val newStatements = ArrayList<Element>()
|
||||
for (s in m.block!!.statements) {
|
||||
var isRemoved: Boolean = false
|
||||
if (s is AssignmentExpression) {
|
||||
val assignee = s.left
|
||||
if (assignee is CallChainExpression) {
|
||||
for (fo : Field in finalOrWithEmptyInitializer) {
|
||||
val id: String = fo.identifier.toKotlin()
|
||||
if (assignee.identifier.toKotlin().endsWith("." + id)) {
|
||||
initializers.put(id, s.right.toKotlin())
|
||||
isRemoved = true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!isRemoved) {
|
||||
newStatements.add(s)
|
||||
}
|
||||
|
||||
}
|
||||
newStatements.add(0, DummyStringExpression("val __ = " + createPrimaryConstructorInvocation(name.toKotlin(), finalOrWithEmptyInitializer, initializers)))
|
||||
m.block = Block(newStatements)
|
||||
}
|
||||
}
|
||||
}
|
||||
members.add(Constructor(Identifier.EMPTY_IDENTIFIER, arrayListOf(), Collections.emptySet<Modifier>(),
|
||||
ClassType(name, Collections.emptyList<Element>(), false),
|
||||
Collections.emptyList<Element>(),
|
||||
ParameterList(createParametersFromFields(finalOrWithEmptyInitializer)),
|
||||
Block(createInitStatementsFromFields(finalOrWithEmptyInitializer)),
|
||||
true))
|
||||
}
|
||||
|
||||
if (psiClass.isInterface()) {
|
||||
return Trait(this, name, docComments, modifiers, typeParameters, extendsTypes, Collections.emptyList<Expression>(), implementsTypes, members)
|
||||
}
|
||||
|
||||
if (psiClass.isEnum()) {
|
||||
return Enum(this, name, docComments, modifiers, typeParameters, Collections.emptyList<Type>(), Collections.emptyList<Expression>(), implementsTypes, members)
|
||||
}
|
||||
|
||||
return Class(this, name, docComments, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, members)
|
||||
}
|
||||
|
||||
private fun initializerToInitializer(i: PsiClassInitializer): Initializer {
|
||||
return Initializer(blockToBlock(i.getBody(), true), modifiersListToModifiersSet(i.getModifierList()))
|
||||
}
|
||||
|
||||
private fun fieldsToFieldList(fields: Array<PsiField>, psiClass: PsiClass): List<Field> {
|
||||
return fields.map { fieldToField(it, psiClass) }
|
||||
}
|
||||
|
||||
private fun fieldToField(field: PsiField, psiClass: PsiClass?): Field {
|
||||
val modifiers = modifiersListToModifiersSet(field.getModifierList())
|
||||
val docComments = getDocComments(field)
|
||||
if (field is PsiEnumConstant) {
|
||||
return EnumConstant(Identifier(field.getName()!!),
|
||||
docComments,
|
||||
modifiers,
|
||||
typeToType(field.getType()),
|
||||
elementToElement(field.getArgumentList()))
|
||||
}
|
||||
|
||||
var kType = typeToType(field.getType(), isAnnotatedAsNotNull(field.getModifierList()))
|
||||
if (field.hasModifierProperty(PsiModifier.FINAL) && isDefinitelyNotNull(field.getInitializer())) {
|
||||
kType = kType.convertedToNotNull();
|
||||
}
|
||||
|
||||
return Field(Identifier(field.getName()!!),
|
||||
docComments,
|
||||
modifiers,
|
||||
kType,
|
||||
expressionToExpression(field.getInitializer(), field.getType()),
|
||||
countWritingAccesses(field, psiClass))
|
||||
}
|
||||
|
||||
private fun methodToFunction(method: PsiMethod): Function {
|
||||
return methodToFunction(method, true)
|
||||
}
|
||||
|
||||
private fun methodToFunction(method: PsiMethod, notEmpty: Boolean): Function {
|
||||
if (isOverrideObjectDirect(method)) {
|
||||
dispatcher.expressionVisitor = ExpressionVisitorForDirectObjectInheritors(this)
|
||||
}
|
||||
else {
|
||||
dispatcher.expressionVisitor = ExpressionVisitor(this)
|
||||
}
|
||||
methodReturnType = method.getReturnType()
|
||||
val identifier: Identifier = Identifier(method.getName())
|
||||
val returnType: Type = typeToType(method.getReturnType(), isAnnotatedAsNotNull(method.getModifierList()))
|
||||
val body: Block = (if (hasFlag(J2KConverterFlags.SKIP_BODIES))
|
||||
Block.EMPTY_BLOCK
|
||||
else
|
||||
blockToBlock(method.getBody(), notEmpty))
|
||||
|
||||
val params: Element = createFunctionParameters(method)
|
||||
val typeParameters = elementsToElementList(method.getTypeParameters())
|
||||
val modifiers = modifiersListToModifiersSet(method.getModifierList())
|
||||
val docComments = getDocComments(method)
|
||||
if (isOverrideAnyMethodExceptMethodsFromObject(method)) {
|
||||
modifiers.add(Modifier.OVERRIDE)
|
||||
}
|
||||
|
||||
val containingClass = method.getContainingClass()
|
||||
if (containingClass != null && containingClass.isInterface()) {
|
||||
modifiers.remove(Modifier.ABSTRACT)
|
||||
}
|
||||
|
||||
if (isNotOpenMethod(method)) {
|
||||
modifiers.add(Modifier.NOT_OPEN)
|
||||
}
|
||||
|
||||
if (method.isConstructor()) {
|
||||
val isPrimary: Boolean = isConstructorPrimary(method)
|
||||
return Constructor(identifier, docComments, modifiers, returnType, typeParameters, params,
|
||||
Block(removeEmpty(body.statements), false), isPrimary)
|
||||
}
|
||||
|
||||
return Function(identifier, docComments, modifiers, returnType, typeParameters, params, body)
|
||||
}
|
||||
|
||||
private fun createFunctionParameters(method: PsiMethod): ParameterList {
|
||||
val result = ArrayList<Parameter>()
|
||||
for (parameter : PsiParameter? in method.getParameterList().getParameters()) {
|
||||
result.add(Parameter(Identifier(parameter?.getName()!!),
|
||||
typeToType(parameter?.getType(),
|
||||
isAnnotatedAsNotNull(parameter?.getModifierList())),
|
||||
isReadOnly(parameter, method.getBody())))
|
||||
}
|
||||
return ParameterList(result)
|
||||
}
|
||||
|
||||
private fun isOverrideAnyMethodExceptMethodsFromObject(method: PsiMethod): Boolean {
|
||||
var counter: Boolean = normalCase(method)
|
||||
if (counter)
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
if (isInheritFromObject(method))
|
||||
{
|
||||
return caseForObject(method)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun caseForObject(method: PsiMethod): Boolean {
|
||||
val containing: PsiClass? = method.getContainingClass()
|
||||
if (containing != null) {
|
||||
for (s : PsiClassType? in containing.getSuperTypes()) {
|
||||
val canonicalText: String? = s?.getCanonicalText()
|
||||
if (canonicalText != JAVA_LANG_OBJECT && !getClassIdentifiers().contains(canonicalText)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
public open fun blockToBlock(block: PsiCodeBlock?, notEmpty: Boolean): Block {
|
||||
if (block == null)
|
||||
return Block.EMPTY_BLOCK
|
||||
|
||||
return Block(removeEmpty(statementsToStatementList(block.getChildren())), notEmpty)
|
||||
}
|
||||
|
||||
public open fun blockToBlock(block: PsiCodeBlock?): Block {
|
||||
return blockToBlock(block, true)
|
||||
}
|
||||
|
||||
public open fun statementsToStatementList(statements: Array<PsiElement>): List<Element> {
|
||||
return statements.filterNot { it is PsiWhiteSpace }.map { statementToStatement(it) }
|
||||
}
|
||||
|
||||
public open fun statementsToStatementList(statements: List<PsiElement>): List<Element> {
|
||||
return statements.filterNot { it is PsiWhiteSpace }.map { statementToStatement(it) }
|
||||
}
|
||||
|
||||
public open fun statementToStatement(s: PsiElement?): Element {
|
||||
if (s == null)
|
||||
return Statement.EMPTY_STATEMENT
|
||||
|
||||
val statementVisitor: StatementVisitor = StatementVisitor(this)
|
||||
s.accept(statementVisitor)
|
||||
return statementVisitor.getResult()
|
||||
}
|
||||
|
||||
public open fun expressionsToExpressionList(expressions: Array<PsiExpression>): List<Expression> {
|
||||
val result = ArrayList<Expression>()
|
||||
for (e : PsiExpression? in expressions)
|
||||
result.add(expressionToExpression(e))
|
||||
return result
|
||||
}
|
||||
|
||||
public open fun expressionToExpression(e: PsiExpression?): Expression {
|
||||
if (e == null)
|
||||
return Expression.EMPTY_EXPRESSION
|
||||
|
||||
val expressionVisitor: ExpressionVisitor = dispatcher.expressionVisitor
|
||||
e.accept(expressionVisitor)
|
||||
return expressionVisitor.getResult()
|
||||
}
|
||||
|
||||
public open fun elementToElement(e: PsiElement?): Element {
|
||||
if (e == null)
|
||||
return Element.EMPTY_ELEMENT
|
||||
|
||||
val elementVisitor: ElementVisitor = ElementVisitor(this)
|
||||
e.accept(elementVisitor)
|
||||
return elementVisitor.getResult()
|
||||
}
|
||||
|
||||
public open fun elementsToElementList(elements: Array<out PsiElement?>): List<Element> {
|
||||
val result = ArrayList<Element>()
|
||||
for(element in elements) {
|
||||
result.add(elementToElement(element))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public open fun typeElementToTypeElement(element: PsiTypeElement?): TypeElement {
|
||||
return TypeElement(if (element == null)
|
||||
EmptyType()
|
||||
else
|
||||
typeToType(element.getType()))
|
||||
}
|
||||
|
||||
public open fun typeToType(`type`: PsiType?): Type {
|
||||
if (`type` == null)
|
||||
return EmptyType()
|
||||
|
||||
val typeVisitor: TypeVisitor = TypeVisitor(this)
|
||||
`type`.accept<Type>(typeVisitor)
|
||||
return typeVisitor.getResult()
|
||||
}
|
||||
|
||||
public open fun typesToTypeList(types: Array<PsiType>): List<Type> {
|
||||
return types.map { typeToType(it) }
|
||||
}
|
||||
|
||||
public open fun typeToType(`type`: PsiType?, notNull: Boolean): Type {
|
||||
val result: Type = typeToType(`type`)
|
||||
if (notNull) {
|
||||
return result.convertedToNotNull()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun typesToNotNullableTypeList(types: Array<out PsiType?>): List<Type> {
|
||||
val result = ArrayList<Type>()
|
||||
for(aType in types) {
|
||||
result.add(typeToType(aType).convertedToNotNull())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public open fun parametersToParameterList(parameters: Array<PsiParameter>): List<Parameter?> {
|
||||
return parameters.map { parameterToParameter(it) }
|
||||
}
|
||||
|
||||
public open fun parameterToParameter(parameter: PsiParameter, forceNotNull: Boolean = false): Parameter {
|
||||
return Parameter(Identifier(parameter.getName()!!),
|
||||
typeToType(parameter.getType(),
|
||||
forceNotNull || isAnnotatedAsNotNull(parameter.getModifierList())), true)
|
||||
}
|
||||
|
||||
public open fun argumentsToExpressionList(expression: PsiCallExpression): List<Expression> {
|
||||
val argumentList: PsiExpressionList? = expression.getArgumentList()
|
||||
val arguments: Array<PsiExpression> = (if (argumentList != null)
|
||||
argumentList.getExpressions()
|
||||
else
|
||||
PsiExpression.EMPTY_ARRAY)
|
||||
val result = ArrayList<Expression>()
|
||||
val resolved: PsiMethod? = expression.resolveMethod()
|
||||
val expectedTypes = ArrayList<PsiType?>()
|
||||
if (resolved != null) {
|
||||
for (p : PsiParameter? in resolved.getParameterList().getParameters())
|
||||
expectedTypes.add(p?.getType())
|
||||
}
|
||||
|
||||
if (arguments.size == expectedTypes.size()) {
|
||||
for (i in 0..expectedTypes.size() - 1) result.add(expressionToExpression(arguments[i], expectedTypes.get(i)))
|
||||
}
|
||||
else {
|
||||
for (argument : PsiExpression? in arguments) {
|
||||
result.add(expressionToExpression(argument))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public open fun expressionToExpression(argument: PsiExpression?, expectedType: PsiType?): Expression {
|
||||
if (argument == null)
|
||||
return Identifier.EMPTY_IDENTIFIER
|
||||
|
||||
var expression: Expression = expressionToExpression(argument)
|
||||
val actualType: PsiType? = argument.getType()
|
||||
val isPrimitiveTypeOrNull: Boolean = actualType == null || actualType is PsiPrimitiveType
|
||||
if (isPrimitiveTypeOrNull && expression.isNullable()) {
|
||||
expression = BangBangExpression(expression)
|
||||
}
|
||||
else if (expectedType is PsiPrimitiveType && actualType is PsiClassType) {
|
||||
if (PsiPrimitiveType.getUnboxedType(actualType) == expectedType) {
|
||||
expression = BangBangExpression(expression)
|
||||
}
|
||||
}
|
||||
|
||||
if (actualType != null) {
|
||||
if (isConversionNeeded(actualType, expectedType) && !(expression is LiteralExpression))
|
||||
{
|
||||
val conversion: String? = PRIMITIVE_TYPE_CONVERSIONS.get(expectedType?.getCanonicalText())
|
||||
if (conversion != null) {
|
||||
expression = MethodCallExpression.build(expression, conversion)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
class object {
|
||||
public val NOT_NULL_ANNOTATIONS: Set<String> = ImmutableSet.of<String>("org.jetbrains.annotations.NotNull", "com.sun.istack.internal.NotNull", "javax.annotation.Nonnull")!!
|
||||
public val PRIMITIVE_TYPE_CONVERSIONS: Map<String, String> = ImmutableMap.builder<String, String>()
|
||||
?.put("byte", BYTE.asString())
|
||||
?.put("short", SHORT.asString())
|
||||
?.put("int", INT.asString())
|
||||
?.put("long", LONG.asString())
|
||||
?.put("float", FLOAT.asString())
|
||||
?.put("double", DOUBLE.asString())
|
||||
?.put("char", CHAR.asString())
|
||||
?.put(JAVA_LANG_BYTE, BYTE.asString())
|
||||
?.put(JAVA_LANG_SHORT, SHORT.asString())
|
||||
?.put(JAVA_LANG_INTEGER, INT.asString())
|
||||
?.put(JAVA_LANG_LONG, LONG.asString())
|
||||
?.put(JAVA_LANG_FLOAT, FLOAT.asString())
|
||||
?.put(JAVA_LANG_DOUBLE, DOUBLE.asString())
|
||||
?.put(JAVA_LANG_CHARACTER, CHAR.asString())
|
||||
?.build()!!
|
||||
|
||||
private fun quoteKeywords(packageName: String): String {
|
||||
return packageName.split("\\.").map { Identifier(it).toKotlin() }.makeString(".")
|
||||
}
|
||||
|
||||
private fun getFinalOrWithEmptyInitializer(fields: List<Field>): List<Field> {
|
||||
val result = ArrayList<Field>()
|
||||
for (f : Field in fields)
|
||||
if (f.isVal() || f.initializer.toKotlin().isEmpty()) {
|
||||
result.add(f)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createParametersFromFields(fields: List<Field>): List<Parameter> {
|
||||
return fields.map { Parameter(Identifier("_" + it.identifier.name), it.`type`, true) }
|
||||
}
|
||||
|
||||
private fun createInitStatementsFromFields(fields: List<Field>): List<Element> {
|
||||
val result = ArrayList<Element>()
|
||||
for (f : Field in fields) {
|
||||
val identifierToKotlin: String? = f.identifier.toKotlin()
|
||||
result.add(DummyStringExpression(identifierToKotlin + " = " + "_" + identifierToKotlin))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createPrimaryConstructorInvocation(s: String, fields: List<Field>, initializers: Map<String, String>): String {
|
||||
return s + "(" + fields.map { initializers[it.identifier.toKotlin()] }.makeString(", ") + ")"
|
||||
}
|
||||
|
||||
public open fun getDefaultInitializer(f: Field): String {
|
||||
if (f.`type`.nullable) {
|
||||
return "null"
|
||||
}
|
||||
else {
|
||||
val typeToKotlin: String = f.`type`.toKotlin()
|
||||
if (typeToKotlin.equals("Boolean"))
|
||||
return "false"
|
||||
|
||||
if (typeToKotlin.equals("Char"))
|
||||
return "' '"
|
||||
|
||||
if (typeToKotlin.equals("Double"))
|
||||
return "0." + OperatorConventions.DOUBLE + "()"
|
||||
|
||||
if (typeToKotlin.equals("Float"))
|
||||
return "0." + OperatorConventions.FLOAT + "()"
|
||||
|
||||
return "0"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPrimaryConstructorForThisCase(psiClass: PsiClass): PsiMethod? {
|
||||
val tv = ThisVisitor()
|
||||
psiClass.accept(tv)
|
||||
return tv.getPrimaryConstructor()
|
||||
}
|
||||
|
||||
public open fun isConstructorPrimary(constructor: PsiMethod): Boolean {
|
||||
val parent = constructor.getParent()
|
||||
if (parent is PsiClass) {
|
||||
if (parent.getConstructors().size == 1) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
val c: PsiMethod? = getPrimaryConstructorForThisCase(parent)
|
||||
if (c != null && c.hashCode() == constructor.hashCode()) {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
private fun removeEmpty(statements: List<Element>): List<Element> {
|
||||
return statements.filterNot { it == Statement.EMPTY_STATEMENT ||
|
||||
it == Expression.EMPTY_EXPRESSION ||
|
||||
it == Element.EMPTY_ELEMENT }
|
||||
}
|
||||
|
||||
private fun isNotOpenMethod(method: PsiMethod): Boolean {
|
||||
val parent = method.getParent()
|
||||
if (parent is PsiClass) {
|
||||
val parentModifierList: PsiModifierList? = parent.getModifierList()
|
||||
if ((parentModifierList != null && parentModifierList.hasExplicitModifier(PsiModifier.FINAL)) || parent.isEnum()) {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun normalCase(method: PsiMethod): Boolean {
|
||||
var counter: Int = 0
|
||||
for (s : HierarchicalMethodSignature? in method.getHierarchicalMethodSignature().getSuperSignatures())
|
||||
{
|
||||
var containingClass: PsiClass? = s?.getMethod()?.getContainingClass()
|
||||
var qualifiedName: String? = (if (containingClass != null)
|
||||
containingClass?.getQualifiedName()
|
||||
else
|
||||
"")
|
||||
if (qualifiedName != null && !qualifiedName.equals(JAVA_LANG_OBJECT))
|
||||
{
|
||||
counter++
|
||||
}
|
||||
|
||||
}
|
||||
return counter > 0
|
||||
}
|
||||
|
||||
private fun isInheritFromObject(method: PsiMethod): Boolean {
|
||||
var superSignatures: List<HierarchicalMethodSignature?> = method.getHierarchicalMethodSignature().getSuperSignatures()
|
||||
for (s : HierarchicalMethodSignature? in superSignatures) {
|
||||
var containingClass: PsiClass? = s?.getMethod()?.getContainingClass()
|
||||
var qualifiedName: String? = (if (containingClass != null)
|
||||
containingClass?.getQualifiedName()
|
||||
else
|
||||
"")
|
||||
if (qualifiedName == JAVA_LANG_OBJECT) {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isOverrideObjectDirect(method: PsiMethod): Boolean {
|
||||
var superSignatures: List<HierarchicalMethodSignature?>? = method.getHierarchicalMethodSignature().getSuperSignatures()
|
||||
if (superSignatures?.size()!! == 1)
|
||||
{
|
||||
val containingClass: PsiClass? = superSignatures?.get(0)?.getMethod()?.getContainingClass()
|
||||
val qualifiedName: String? = (if (containingClass != null)
|
||||
containingClass.getQualifiedName()
|
||||
else
|
||||
"")
|
||||
if (qualifiedName == JAVA_LANG_OBJECT) {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
private fun importsToImportList(imports: Array<PsiImportStatementBase>): List<Import> {
|
||||
val result = ArrayList<Import>()
|
||||
for (i : PsiImportStatementBase? in imports) {
|
||||
if (i == null) continue
|
||||
val anImport: Import = importToImport(i)
|
||||
val name: String = anImport.name
|
||||
if (!name.isEmpty() && !NOT_NULL_ANNOTATIONS.contains(name)) {
|
||||
result.add(anImport)
|
||||
}
|
||||
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun importToImport(i: PsiImportStatementBase): Import {
|
||||
val reference: PsiJavaCodeReferenceElement? = i.getImportReference()
|
||||
if (reference != null) {
|
||||
return Import(quoteKeywords(reference.getQualifiedName()!!) + ((if (i.isOnDemand())
|
||||
".*"
|
||||
else
|
||||
"")))
|
||||
}
|
||||
|
||||
return Import("")
|
||||
}
|
||||
|
||||
public open fun identifierToIdentifier(identifier: PsiIdentifier?): Identifier {
|
||||
if (identifier == null)
|
||||
return Identifier.EMPTY_IDENTIFIER
|
||||
|
||||
return Identifier(identifier.getText()!!)
|
||||
}
|
||||
|
||||
public open fun modifiersListToModifiersSet(modifierList: PsiModifierList?): MutableSet<Modifier> {
|
||||
val modifiersSet: HashSet<Modifier> = hashSetOf()
|
||||
if (modifierList != null) {
|
||||
if (modifierList.hasExplicitModifier(PsiModifier.ABSTRACT))
|
||||
modifiersSet.add(Modifier.ABSTRACT)
|
||||
|
||||
if (modifierList.hasModifierProperty(PsiModifier.FINAL))
|
||||
modifiersSet.add(Modifier.FINAL)
|
||||
|
||||
if (modifierList.hasModifierProperty(PsiModifier.STATIC))
|
||||
modifiersSet.add(Modifier.STATIC)
|
||||
|
||||
if (modifierList.hasExplicitModifier(PsiModifier.PUBLIC))
|
||||
modifiersSet.add(Modifier.PUBLIC)
|
||||
|
||||
if (modifierList.hasExplicitModifier(PsiModifier.PROTECTED))
|
||||
modifiersSet.add(Modifier.PROTECTED)
|
||||
|
||||
if (modifierList.hasExplicitModifier(PsiModifier.PACKAGE_LOCAL))
|
||||
modifiersSet.add(Modifier.INTERNAL)
|
||||
|
||||
if (modifierList.hasExplicitModifier(PsiModifier.PRIVATE))
|
||||
modifiersSet.add(Modifier.PRIVATE)
|
||||
}
|
||||
|
||||
return modifiersSet
|
||||
}
|
||||
|
||||
private fun isConversionNeeded(actual: PsiType?, expected: PsiType?): Boolean {
|
||||
if (actual == null || expected == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val typeMap = HashMap<String, String>()
|
||||
typeMap.put(JAVA_LANG_BYTE, "byte")
|
||||
typeMap.put(JAVA_LANG_SHORT, "short")
|
||||
typeMap.put(JAVA_LANG_INTEGER, "int")
|
||||
typeMap.put(JAVA_LANG_LONG, "long")
|
||||
typeMap.put(JAVA_LANG_FLOAT, "float")
|
||||
typeMap.put(JAVA_LANG_DOUBLE, "double")
|
||||
typeMap.put(JAVA_LANG_CHARACTER, "char")
|
||||
val expectedStr: String? = expected.getCanonicalText()
|
||||
val actualStr: String? = actual.getCanonicalText()
|
||||
val o1: Boolean = expectedStr == typeMap[actualStr]
|
||||
val o2: Boolean = actualStr == typeMap[expectedStr]
|
||||
return actualStr != expectedStr && (!(o1 xor o2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun createMainFunction(file: PsiFile): String {
|
||||
val classNamesWithMains = ArrayList<Pair<String?, PsiMethod?>?>()
|
||||
for (c : PsiClass? in (file as PsiJavaFile).getClasses()) {
|
||||
var main: PsiMethod? = findMainMethod(c)
|
||||
if (main != null) {
|
||||
classNamesWithMains.add(Pair<String?, PsiMethod?>(c?.getName(), main))
|
||||
}
|
||||
}
|
||||
|
||||
if (classNamesWithMains.size() > 0) {
|
||||
var className: String? = classNamesWithMains.get(0)?.getFirst()
|
||||
return MessageFormat.format("fun main(args : Array<String>) = {0}.main(args as Array<String?>?)", className)
|
||||
}
|
||||
|
||||
return ""
|
||||
|
||||
}
|
||||
|
||||
private fun findMainMethod(aClass: PsiClass?): PsiMethod? {
|
||||
if (isMainClass(aClass)) {
|
||||
val mainMethods: Array<PsiMethod>? = aClass?.findMethodsByName("main", false)
|
||||
if (mainMethods != null) {
|
||||
return findMainMethod(mainMethods)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isMainClass(psiClass: PsiClass?): Boolean {
|
||||
if (psiClass == null || psiClass is PsiAnonymousClass)
|
||||
return false
|
||||
|
||||
if (psiClass.isInterface())
|
||||
return false
|
||||
|
||||
return psiClass.getContainingClass() == null || psiClass.hasModifierProperty(PsiModifier.STATIC)
|
||||
|
||||
}
|
||||
|
||||
private fun findMainMethod(mainMethods: Array<PsiMethod>): PsiMethod? {
|
||||
return mainMethods.find { isMainMethod(it) }
|
||||
}
|
||||
|
||||
public fun isMainMethod(method: PsiMethod?): Boolean {
|
||||
if (method == null || method.getContainingClass() == null)
|
||||
return false
|
||||
|
||||
if (PsiType.VOID != method.getReturnType())
|
||||
return false
|
||||
|
||||
if (!method.hasModifierProperty(PsiModifier.STATIC))
|
||||
return false
|
||||
|
||||
if (!method.hasModifierProperty(PsiModifier.PUBLIC))
|
||||
return false
|
||||
|
||||
val parameters: Array<PsiParameter>? = method.getParameterList().getParameters()
|
||||
if (parameters?.size!! != 1)
|
||||
return false
|
||||
|
||||
val `type`: PsiType? = parameters!![0].getType()
|
||||
if (`type` !is PsiArrayType)
|
||||
return false
|
||||
|
||||
val componentType: PsiType? = `type`.getComponentType()
|
||||
return componentType?.equalsToText("java.lang.String")!!
|
||||
}
|
||||
|
||||
public fun countWritingAccesses(element: PsiElement?, container: PsiElement?): Int {
|
||||
var counter: Int = 0
|
||||
if (container != null) {
|
||||
val visitor: ReferenceCollector = ReferenceCollector()
|
||||
container.accept(visitor)
|
||||
for (e : PsiReferenceExpression in visitor.getCollectedReferences())
|
||||
if (e.isReferenceTo(element) && PsiUtil.isAccessedForWriting(e)) {
|
||||
counter++
|
||||
}
|
||||
}
|
||||
|
||||
return counter
|
||||
}
|
||||
|
||||
open class ReferenceCollector(): JavaRecursiveElementVisitor() {
|
||||
private val myCollectedReferences = ArrayList<PsiReferenceExpression>()
|
||||
|
||||
public open fun getCollectedReferences(): List<PsiReferenceExpression> {
|
||||
return myCollectedReferences
|
||||
}
|
||||
|
||||
public override fun visitReferenceExpression(expression: PsiReferenceExpression?): Unit {
|
||||
super.visitReferenceExpression(expression)
|
||||
if (expression != null) {
|
||||
myCollectedReferences.add(expression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun isReadOnly(element: PsiElement?, container: PsiElement?): Boolean {
|
||||
return countWritingAccesses(element, container) == 0
|
||||
}
|
||||
|
||||
public fun isAnnotatedAsNotNull(modifierList: PsiModifierList?): Boolean {
|
||||
if (modifierList != null) {
|
||||
val annotations: Array<PsiAnnotation> = modifierList.getAnnotations()
|
||||
for (a : PsiAnnotation in annotations) {
|
||||
val qualifiedName: String? = a.getQualifiedName()
|
||||
if (qualifiedName != null && Converter.NOT_NULL_ANNOTATIONS.contains(qualifiedName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public fun isDefinitelyNotNull(element: PsiElement?): Boolean = when(element) {
|
||||
is PsiLiteralExpression -> element.getValue() != null
|
||||
is PsiNewExpression -> true
|
||||
else -> false
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.jet.j2k
|
||||
|
||||
|
||||
public enum class J2KConverterFlags {
|
||||
FULLY_QUALIFIED_TYPE_NAMES
|
||||
SKIP_BODIES
|
||||
SKIP_NON_PUBLIC_MEMBERS
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
//package org.jetbrains.jet.j2k;
|
||||
//
|
||||
//import com.intellij.psi.PsiFile;
|
||||
//import com.intellij.psi.PsiJavaFile;
|
||||
//import org.apache.commons.cli.*;
|
||||
//import org.jetbrains.annotations.NotNull;
|
||||
//import org.jetbrains.annotations.Nullable;
|
||||
//
|
||||
//import java.io.File;
|
||||
//import java.io.FileNotFoundException;
|
||||
//import java.io.IOException;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Arrays;
|
||||
//import java.util.List;
|
||||
//import java.util.logging.Logger;
|
||||
//import java.util.regex.Pattern;
|
||||
//
|
||||
//import static org.apache.commons.io.FileUtils.readFileToString;
|
||||
//import static org.apache.commons.io.FileUtils.writeStringToFile;
|
||||
//
|
||||
//@SuppressWarnings({"CallToPrintStackTrace", "UseOfSystemOutOrSystemErr"})
|
||||
//public class JavaToKotlinCli {
|
||||
// private static final Logger myLogger = Logger.getAnonymousLogger();
|
||||
//
|
||||
// private JavaToKotlinCli() {
|
||||
// }
|
||||
//
|
||||
// public static void main(String[] args) {
|
||||
// CommandLineParser parser = new BasicParser();
|
||||
// Options options = new Options()
|
||||
// .addOption("h", "help", false, "Print usage information")
|
||||
// .addOption("f", "from", true, "Directory with Java sources")
|
||||
// .addOption("t", "to", true, "Directory with Kotlin sources")
|
||||
// .addOption("p", "public-only", false, "Only public and protected members")
|
||||
// .addOption("fqn", "fqn", false, "Full qualified names")
|
||||
// .addOption("d", "declarations-only", false, "Declarations only")
|
||||
// ;
|
||||
//
|
||||
// try {
|
||||
// CommandLine commandLine = parser.parse(options, args);
|
||||
//
|
||||
// if (commandLine.hasOption("help"))
|
||||
// showHelpAndExit();
|
||||
//
|
||||
// if (commandLine.hasOption("from") && commandLine.hasOption("to")) {
|
||||
// String from = commandLine.getOptionValue("from");
|
||||
// String to = commandLine.getOptionValue("to");
|
||||
//
|
||||
// for (Option o : commandLine.getOptions()) {
|
||||
// Converter.addFlag(o.getLongOpt());
|
||||
// }
|
||||
//
|
||||
// if (!from.isEmpty() && !to.isEmpty())
|
||||
// convertSourceTree(from, to);
|
||||
// else
|
||||
// showHelpAndExit();
|
||||
// } else
|
||||
// showHelpAndExit();
|
||||
// } catch (ParseException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
// private static void convertSourceTree(String javaPath, String kotlinPath) {
|
||||
// try {
|
||||
// File javaDir = new File(javaPath);
|
||||
// File kotlinDir = new File(kotlinPath);
|
||||
//
|
||||
// if (kotlinDir.exists())
|
||||
// kotlinDir.delete();
|
||||
//
|
||||
// if (!kotlinDir.exists() && !kotlinDir.mkdir())
|
||||
// myLogger.warning("Creation failed: " + kotlinDir.getAbsolutePath());
|
||||
//
|
||||
// for (File f : getJavaFiles(javaDir.getAbsolutePath())) {
|
||||
// String relative = javaDir.toURI().relativize(f.toURI()).getPath().replace(".java", ".kt");
|
||||
// File file = new File(kotlinPath, relative);
|
||||
//
|
||||
// if (file.exists())
|
||||
// file.delete();
|
||||
//
|
||||
// if (f.isDirectory())
|
||||
// if (!file.exists() && !file.mkdir())
|
||||
// myLogger.warning("Creation failed: " + file.getAbsolutePath());
|
||||
//
|
||||
// if (f.isFile()) {
|
||||
// writeStringToFile(file, fileToKotlin(f));
|
||||
// }
|
||||
// }
|
||||
// } catch (FileNotFoundException e) {
|
||||
// e.printStackTrace();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// private static String fileToKotlin(File f) throws IOException {
|
||||
// final String javaCode = readJavaFileToString(f);
|
||||
// return generateKotlinCode(JavaToKotlinTranslator.createFile(JavaToKotlinTranslator.setUpJavaCoreEnvironment(), javaCode));
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// private static String generateKotlinCode(@Nullable PsiFile file) {
|
||||
// if (file != null && file instanceof PsiJavaFile) {
|
||||
// JavaToKotlinTranslator.setClassIdentifiers(file);
|
||||
// return JavaToKotlinTranslator.prettify(Converter.fileToFile((PsiJavaFile) file).toKotlin());
|
||||
// }
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// private static String readJavaFileToString(@NotNull File javaFile) throws IOException {
|
||||
// return Pattern.compile("\\s*/\\*.*\\*/", Pattern.DOTALL).matcher(readFileToString(javaFile)).replaceAll("");
|
||||
// }
|
||||
//
|
||||
// private static void showHelpAndExit() {
|
||||
// System.err.println("Usage: java -jar java2kotlin.jar -f <from> -t <to>");
|
||||
// System.exit(1);
|
||||
// }
|
||||
//
|
||||
// static public List<File> getJavaFiles(String startDirName) throws FileNotFoundException {
|
||||
// return getJavaFiles(new File(startDirName));
|
||||
// }
|
||||
//
|
||||
// private static List<File> getJavaFiles(File start) throws FileNotFoundException {
|
||||
// List<File> result = new ArrayList<File>();
|
||||
//
|
||||
// if (start.isFile())
|
||||
// return Arrays.asList(start);
|
||||
//
|
||||
// for (File file : Arrays.asList(start.listFiles())) {
|
||||
// if ((file.isFile() && file.getName().endsWith(".java")) || file.isDirectory())
|
||||
// result.add(file);
|
||||
//
|
||||
// if (file.isDirectory()) {
|
||||
// List<File> deeperList = getJavaFiles(file);
|
||||
// result.addAll(deeperList);
|
||||
// }
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.core.JavaCoreApplicationEnvironment;
|
||||
import com.intellij.core.JavaCoreProjectEnvironment;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.j2k.visitors.ClassVisitor;
|
||||
import org.jetbrains.jet.utils.PathUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class JavaToKotlinTranslator {
|
||||
private JavaToKotlinTranslator() {
|
||||
}
|
||||
|
||||
private static final Converter CONVERTER = new Converter();
|
||||
|
||||
@Nullable
|
||||
private static PsiFile createFile(@NotNull String text) {
|
||||
JavaCoreProjectEnvironment javaCoreEnvironment = setUpJavaCoreEnvironment();
|
||||
return PsiFileFactory.getInstance(javaCoreEnvironment.getProject()).createFileFromText(
|
||||
"test.java", JavaLanguage.INSTANCE, text
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiFile createFile(@NotNull JavaCoreProjectEnvironment javaCoreEnvironment, @NotNull String text) {
|
||||
return PsiFileFactory.getInstance(javaCoreEnvironment.getProject()).createFileFromText(
|
||||
"test.java", JavaLanguage.INSTANCE, text
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static JavaCoreProjectEnvironment setUpJavaCoreEnvironment() {
|
||||
Disposable parentDisposable = new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
JavaCoreApplicationEnvironment applicationEnvironment = new JavaCoreApplicationEnvironment(parentDisposable);
|
||||
JavaCoreProjectEnvironment javaCoreEnvironment = new JavaCoreProjectEnvironment(parentDisposable, applicationEnvironment);
|
||||
|
||||
javaCoreEnvironment.addJarToClassPath(PathUtil.findRtJar());
|
||||
File annotations = findAnnotations();
|
||||
if (annotations != null && annotations.exists()) {
|
||||
javaCoreEnvironment.addJarToClassPath(annotations);
|
||||
}
|
||||
return javaCoreEnvironment;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String prettify(@Nullable String code) {
|
||||
if (code == null) {
|
||||
return "";
|
||||
}
|
||||
return code
|
||||
.trim()
|
||||
.replaceAll("\r\n", "\n")
|
||||
.replaceAll(" \n", "\n")
|
||||
.replaceAll("\n ", "\n")
|
||||
.replaceAll("\n+", "\n")
|
||||
.replaceAll(" +", " ")
|
||||
.trim()
|
||||
;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static File findAnnotations() {
|
||||
ClassLoader classLoader = JavaToKotlinTranslator.class.getClassLoader();
|
||||
while (classLoader != null) {
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
URLClassLoader loader = (URLClassLoader) classLoader;
|
||||
for (URL url : loader.getURLs())
|
||||
if ("file".equals(url.getProtocol()) && url.getFile().endsWith("/annotations.jar")) {
|
||||
return new File(url.getFile());
|
||||
}
|
||||
}
|
||||
classLoader = classLoader.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void setClassIdentifiers(@NotNull Converter converter, @NotNull PsiElement psiFile) {
|
||||
ClassVisitor c = new ClassVisitor();
|
||||
psiFile.accept(c);
|
||||
converter.clearClassIdentifiers();
|
||||
converter.setClassIdentifiers(c.getClassIdentifiers());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String generateKotlinCode(@NotNull String javaCode) {
|
||||
PsiFile file = createFile(javaCode);
|
||||
if (file != null && file instanceof PsiJavaFile) {
|
||||
setClassIdentifiers(CONVERTER, file);
|
||||
return prettify(CONVERTER.fileToFile((PsiJavaFile) file).toKotlin());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String generateKotlinCodeWithCompatibilityImport(@NotNull String javaCode) {
|
||||
PsiFile file = createFile(javaCode);
|
||||
if (file != null && file instanceof PsiJavaFile) {
|
||||
setClassIdentifiers(CONVERTER, file);
|
||||
return prettify(CONVERTER.fileToFileWithCompatibilityImport((PsiJavaFile) file).toKotlin());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void main(@NotNull String[] args) throws IOException {
|
||||
//noinspection UseOfSystemOutOrSystemErr
|
||||
final PrintStream out = System.out;
|
||||
if (args.length == 1) {
|
||||
String kotlinCode = "";
|
||||
try {
|
||||
kotlinCode = generateKotlinCode(args[0]);
|
||||
} catch (Exception e) {
|
||||
out.println("EXCEPTION: " + e.getMessage());
|
||||
}
|
||||
if (kotlinCode.isEmpty()) {
|
||||
out.println("EXCEPTION: generated code is empty.");
|
||||
}
|
||||
else {
|
||||
out.println(kotlinCode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.println("EXCEPTION: wrong number of arguments (should be 1).");
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateToKotlin(String code) {
|
||||
return generateKotlinCode(code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.jetbrains.jet.j2k
|
||||
|
||||
|
||||
/*
|
||||
* Copyright 2010-2012 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.
|
||||
*/
|
||||
public open class SetupJavaCoreEnvironmentException(s: String?): RuntimeException() {
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//package org.jetbrains.jet.j2k.actions
|
||||
//
|
||||
//import com.intellij.openapi.actionSystem.AnAction
|
||||
//import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
//import org.jetbrains.jet.j2k.Converter
|
||||
//import com.intellij.openapi.actionSystem.PlatformDataKeys
|
||||
//import com.intellij.openapi.actionSystem.LangDataKeys
|
||||
//import com.intellij.psi.PsiJavaFile
|
||||
//import com.intellij.openapi.util.io.FileUtil
|
||||
//import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
//import com.intellij.psi.PsiDocumentManager
|
||||
//import com.intellij.openapi.command.WriteCommandAction
|
||||
//import com.intellij.openapi.application.ApplicationManager
|
||||
//import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
//
|
||||
//class JavaToKotlinAction(): AnAction() {
|
||||
// public override fun actionPerformed(event : AnActionEvent?) {
|
||||
// val converter = Converter()
|
||||
// val psiFile = event!!.getData(LangDataKeys.PSI_FILE)!!
|
||||
// ApplicationManager.getApplication()?.runWriteAction(object : Runnable {
|
||||
// public override fun run() {
|
||||
// val result = converter.fileToFile(psiFile as PsiJavaFile).toKotlin()
|
||||
// val newName = FileUtil.getNameWithoutExtension(psiFile.getName()) + ".kt"
|
||||
// val newFile = psiFile.getContainingDirectory()?.createFile(newName)!!
|
||||
// val project = psiFile.getProject()
|
||||
// val psiDocumentManager = PsiDocumentManager.getInstance(project)!!
|
||||
// val document = psiDocumentManager.getDocument(newFile)!!
|
||||
// document.setText(result)
|
||||
// psiDocumentManager.doPostponedOperationsAndUnblockDocument(document)
|
||||
// psiDocumentManager.commitDocument(document)
|
||||
// CodeStyleManager.getInstance(project)!!.reformat(newFile)
|
||||
// psiFile.setName(psiFile.getName() + ".old")
|
||||
// newFile.navigate(true)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public override fun update(e : AnActionEvent?) {
|
||||
// val psiFile = e!!.getData(LangDataKeys.PSI_FILE)
|
||||
// e.getPresentation().setEnabled(psiFile is PsiJavaFile)
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import java.util.Collections
|
||||
|
||||
public open class AnonymousClass(converter : Converter, members : List<Node>)
|
||||
: Class(converter,
|
||||
Identifier("anonClass"),
|
||||
arrayList(),
|
||||
Collections.emptySet<Modifier>(),
|
||||
Collections.emptyList<Element>(),
|
||||
Collections.emptyList<Type>(),
|
||||
Collections.emptyList<Expression>(),
|
||||
Collections.emptyList<Type>(), members) {
|
||||
public override fun toKotlin() = bodyToKotlin()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
|
||||
public open class ArrayInitializerExpression(val `type` : Type, val initializers : List<Expression>) : Expression() {
|
||||
public override fun toKotlin() : String {
|
||||
return createArrayFunction() + "(" + createInitializers() + ")"
|
||||
}
|
||||
|
||||
private fun createInitializers(): String {
|
||||
return initializers.map { explicitConvertIfNeeded(it) }.makeString(", ")
|
||||
}
|
||||
|
||||
private fun createArrayFunction() : String {
|
||||
var sType : String? = innerTypeStr()
|
||||
if (Node.PRIMITIVE_TYPES.contains(sType)) {
|
||||
return sType + "Array"
|
||||
}
|
||||
|
||||
return StringUtil.decapitalize(`type`.convertedToNotNull().toKotlin())!!
|
||||
}
|
||||
|
||||
private fun innerTypeStr() : String {
|
||||
return `type`.convertedToNotNull().toKotlin().replace("Array", "").toLowerCase()
|
||||
}
|
||||
|
||||
private fun explicitConvertIfNeeded(i : Expression) : String {
|
||||
val doubleOrFloatTypes = hashSet("double", "float", "java.lang.double", "java.lang.float")
|
||||
val afterReplace : String = innerTypeStr().replace(">", "").replace("<", "").replace("?", "")
|
||||
if (doubleOrFloatTypes.contains(afterReplace))
|
||||
{
|
||||
if (i is LiteralExpression) {
|
||||
if (i.toKotlin().contains(".")) {
|
||||
return i.toKotlin()
|
||||
}
|
||||
|
||||
return i.toKotlin() + ".0"
|
||||
}
|
||||
|
||||
return "(" + i.toKotlin() + ")" + getConversion(afterReplace)
|
||||
}
|
||||
|
||||
return i.toKotlin()
|
||||
}
|
||||
|
||||
class object {
|
||||
private open fun getConversion(afterReplace : String) : String {
|
||||
if (afterReplace.contains("double"))
|
||||
return "." + OperatorConventions.DOUBLE + "()"
|
||||
|
||||
if (afterReplace.contains("float"))
|
||||
return "." + OperatorConventions.FLOAT + "()"
|
||||
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.ArrayType
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import org.jetbrains.jet.j2k.ast.types.PrimitiveType
|
||||
|
||||
public open class ArrayWithoutInitializationExpression(val `type` : Type, val expressions : List<Expression>) : Expression() {
|
||||
public override fun toKotlin() : String {
|
||||
if (`type` is ArrayType) {
|
||||
return constructInnerType(`type`, expressions)
|
||||
}
|
||||
|
||||
return getConstructorName(`type`, expressions.size() != 0)
|
||||
}
|
||||
|
||||
private fun constructInnerType(hostType : ArrayType, expressions: List<Expression>) : String {
|
||||
if (expressions.size() == 1) {
|
||||
return oneDim(hostType, expressions[0])
|
||||
}
|
||||
|
||||
val innerType = hostType.elementType
|
||||
if (expressions.size() > 1 && innerType is ArrayType) {
|
||||
return oneDim(hostType, expressions[0], "{" + constructInnerType(innerType, expressions.subList(1, expressions.size())) + "}")
|
||||
}
|
||||
|
||||
return getConstructorName(hostType, expressions.size() != 0)
|
||||
}
|
||||
|
||||
class object {
|
||||
private open fun oneDim(`type` : Type, size : Expression) : String {
|
||||
return oneDim(`type`, size, "")
|
||||
}
|
||||
|
||||
private open fun oneDim(`type` : Type, size : Expression, init : String) : String {
|
||||
return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin() + init.withPrefix(", ") + ")"
|
||||
}
|
||||
|
||||
private open fun getConstructorName(`type` : Type, hasInit : Boolean) : String {
|
||||
return if (`type` is ArrayType)
|
||||
when (`type`.elementType) {
|
||||
is PrimitiveType ->
|
||||
`type`.convertedToNotNull().toKotlin()
|
||||
is ArrayType ->
|
||||
if (hasInit)
|
||||
`type`.convertedToNotNull().toKotlin()
|
||||
else
|
||||
"arrayOfNulls<" + `type`.elementType.toKotlin() + ">"
|
||||
else ->
|
||||
"arrayOfNulls<" + `type`.elementType.toKotlin() + ">"
|
||||
}
|
||||
else
|
||||
`type`.convertedToNotNull().toKotlin()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public open class AssertStatement(val condition : Expression, val detail : Expression) : Statement() {
|
||||
public override fun toKotlin() : String {
|
||||
var detail : String? = (if (detail != Expression.EMPTY_EXPRESSION)
|
||||
"(" + detail.toKotlin() + ")"
|
||||
else
|
||||
"")
|
||||
return "assert" + detail + " {" + condition.toKotlin() + "}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import java.util.LinkedList
|
||||
|
||||
public open class Block(val statements: List<Element>, val notEmpty: Boolean = false): Statement() {
|
||||
public override fun isEmpty(): Boolean {
|
||||
return !notEmpty && (statements.size() == 0 || statements.all { it == Statement.EMPTY_STATEMENT })
|
||||
}
|
||||
|
||||
public override fun toKotlin(): String {
|
||||
if (!isEmpty()) {
|
||||
return "{\n" + statements.toKotlin("\n") + "\n}"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
class object {
|
||||
public val EMPTY_BLOCK: Block = Block(arrayList())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
public open class CallChainExpression(val expression : Expression, val identifier : Expression) : Expression() {
|
||||
public override fun isNullable() : Boolean {
|
||||
if (!expression.isEmpty() && expression.isNullable()) return true
|
||||
return identifier.isNullable()
|
||||
}
|
||||
|
||||
public override fun toKotlin() : String {
|
||||
if (!expression.isEmpty()) {
|
||||
return expression.toKotlin() + (if (expression.isNullable()) "?." else ".") + identifier.toKotlin()
|
||||
}
|
||||
|
||||
return identifier.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.J2KConverterFlags
|
||||
import org.jetbrains.jet.j2k.ast.types.ClassType
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import java.util.HashSet
|
||||
import java.util.LinkedList
|
||||
import java.util.ArrayList
|
||||
|
||||
public open class Class(converter : Converter,
|
||||
val name : Identifier,
|
||||
val docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
val typeParameters : List<Element>,
|
||||
val extendsTypes : List<Type>,
|
||||
val baseClassParams : List<Expression>,
|
||||
val implementsTypes : List<Type>,
|
||||
members : List<Node>) : Member(modifiers) {
|
||||
val members = getMembers(members, converter)
|
||||
|
||||
open val TYPE: String
|
||||
get() = "class"
|
||||
|
||||
private fun getPrimaryConstructor() : Constructor? {
|
||||
return members.find { it is Constructor && it.isPrimary } as Constructor?
|
||||
}
|
||||
|
||||
open fun primaryConstructorSignatureToKotlin() : String {
|
||||
val maybeConstructor : Constructor? = getPrimaryConstructor()
|
||||
return if (maybeConstructor != null) maybeConstructor.primarySignatureToKotlin() else "()"
|
||||
}
|
||||
|
||||
open fun primaryConstructorBodyToKotlin() : String? {
|
||||
val maybeConstructor : Constructor? = getPrimaryConstructor()
|
||||
if (maybeConstructor != null && !(maybeConstructor.block?.isEmpty() ?: true)) {
|
||||
return maybeConstructor.primaryBodyToKotlin()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun hasWhere() : Boolean = typeParameters.any { it is TypeParameter && it.hasWhere() }
|
||||
|
||||
open fun typeParameterWhereToKotlin() : String {
|
||||
if (hasWhere()) {
|
||||
val wheres = typeParameters.filter { it is TypeParameter }.map { (it as TypeParameter).getWhereToKotlin() }
|
||||
return " where " + wheres.makeString(", ") + " "
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
open fun membersExceptConstructors() : List<Node> = members.filterNot { it is Constructor }
|
||||
|
||||
open fun secondaryConstructorsAsStaticInitFunction() : List<Function> {
|
||||
return members.filter { it is Constructor && !it.isPrimary }.map { constructorToInit(it as Function) }
|
||||
}
|
||||
|
||||
private fun constructorToInit(f: Function): Function {
|
||||
val modifiers = HashSet<Modifier>(f.modifiers)
|
||||
modifiers.add(Modifier.STATIC)
|
||||
val statements = ArrayList<Element>(f.block?.statements ?: listOf())
|
||||
statements.add(ReturnStatement(Identifier("__")))
|
||||
val block = Block(statements)
|
||||
val constructorTypeParameters = ArrayList<Element>()
|
||||
constructorTypeParameters.addAll(typeParameters)
|
||||
constructorTypeParameters.addAll(f.typeParameters)
|
||||
return Function(Identifier("init"), arrayList(), modifiers, ClassType(name, constructorTypeParameters, false),
|
||||
constructorTypeParameters, f.params, block)
|
||||
}
|
||||
|
||||
open fun typeParametersToKotlin() : String = typeParameters.toKotlin(", ", "<", ">")
|
||||
|
||||
open fun baseClassSignatureWithParams() : List<String> {
|
||||
if (TYPE.equals("class") && extendsTypes.size() == 1) {
|
||||
val baseParams = baseClassParams.toKotlin(", ")
|
||||
return arrayList(extendsTypes[0].toKotlin() + "(" + baseParams + ")")
|
||||
}
|
||||
return extendsTypes.map { it.toKotlin() }
|
||||
}
|
||||
|
||||
open fun implementTypesToKotlin() : String {
|
||||
val allTypes = ArrayList<String>()
|
||||
allTypes.addAll(baseClassSignatureWithParams())
|
||||
allTypes.addAll(implementsTypes.map { it.toKotlin() })
|
||||
return if (allTypes.size() == 0)
|
||||
""
|
||||
else
|
||||
" : " + allTypes.makeString(", ")
|
||||
}
|
||||
|
||||
open fun modifiersToKotlin() : String {
|
||||
val modifierList = ArrayList<Modifier>()
|
||||
val modifier = accessModifier()
|
||||
if (modifier != null) {
|
||||
modifierList.add(modifier)
|
||||
}
|
||||
if (needAbstractModifier()) {
|
||||
modifierList.add(Modifier.ABSTRACT)
|
||||
}
|
||||
|
||||
if (needOpenModifier()) {
|
||||
modifierList.add(Modifier.OPEN)
|
||||
}
|
||||
return modifierList.toKotlin()
|
||||
}
|
||||
|
||||
open fun needOpenModifier() = !modifiers.contains(Modifier.FINAL) && !modifiers.contains(Modifier.ABSTRACT)
|
||||
|
||||
open fun needAbstractModifier() = isAbstract()
|
||||
|
||||
open fun bodyToKotlin() : String {
|
||||
return " {\n" + getNonStatic(membersExceptConstructors()).toKotlin("\n") + "\n" + primaryConstructorBodyToKotlin() + "\n" + classObjectToKotlin() + "\n}"
|
||||
}
|
||||
|
||||
private fun classObjectToKotlin() : String {
|
||||
val staticMembers = ArrayList<Node>()
|
||||
staticMembers.addAll(secondaryConstructorsAsStaticInitFunction())
|
||||
staticMembers.addAll(getStatic(membersExceptConstructors()))
|
||||
return staticMembers.toKotlin("\n", "class object {\n", "\n}")
|
||||
}
|
||||
|
||||
public override fun toKotlin() : String =
|
||||
docComments.toKotlin("\n", "", "\n") +
|
||||
modifiersToKotlin() +
|
||||
TYPE + " " + name.toKotlin() +
|
||||
typeParametersToKotlin() +
|
||||
primaryConstructorSignatureToKotlin() +
|
||||
implementTypesToKotlin() +
|
||||
typeParameterWhereToKotlin() +
|
||||
bodyToKotlin()
|
||||
|
||||
class object {
|
||||
open fun getMembers(members : List<Node>, converter : Converter) : List<Node> {
|
||||
if (converter.hasFlag(J2KConverterFlags.SKIP_NON_PUBLIC_MEMBERS)) {
|
||||
return members.filter { it is Comment ||
|
||||
(it as Member).accessModifier() == Modifier.PUBLIC ||
|
||||
(it as Member).accessModifier() == Modifier.PROTECTED }
|
||||
}
|
||||
return members
|
||||
}
|
||||
|
||||
private fun getStatic(members : List<Node>) : List<Node> {
|
||||
return members.filter { it is Member && it.isStatic() }
|
||||
}
|
||||
|
||||
private fun getNonStatic(members : List<Node>) : List<Node> {
|
||||
return members.filterNot { it is Member && it.isStatic() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class Constructor(identifier : Identifier,
|
||||
docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
`type` : Type,
|
||||
typeParameters : List<Element>,
|
||||
params : Element,
|
||||
block : Block,
|
||||
val isPrimary : Boolean) : Function(identifier, docComments, modifiers, `type`, typeParameters, params, block) {
|
||||
|
||||
public open fun primarySignatureToKotlin() : String {
|
||||
return "(" + params.toKotlin() + ")"
|
||||
}
|
||||
|
||||
public open fun primaryBodyToKotlin() : String {
|
||||
return block!!.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public open class DummyStringExpression(val string: String): Expression() {
|
||||
public override fun toKotlin(): String = string
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public abstract class Element(): Node() {
|
||||
public open fun isEmpty(): Boolean = false
|
||||
|
||||
class object {
|
||||
public val EMPTY_ELEMENT: Element = object : Element() {
|
||||
override fun toKotlin() = ""
|
||||
override fun isEmpty() = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Comment(val text: String): Element() {
|
||||
override fun toKotlin() = text
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class Enum(converter : Converter,
|
||||
name : Identifier,
|
||||
docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
typeParameters : List<Element>,
|
||||
extendsTypes : List<Type>,
|
||||
baseClassParams : List<Expression>,
|
||||
implementsTypes : List<Type>,
|
||||
members : List<Node>) : Class(converter, name, docComments, modifiers, typeParameters,
|
||||
extendsTypes, baseClassParams, implementsTypes, members) {
|
||||
|
||||
override fun primaryConstructorSignatureToKotlin() : String {
|
||||
val s : String = super.primaryConstructorSignatureToKotlin()
|
||||
return if (s.equals("()")) "" else s
|
||||
}
|
||||
|
||||
override fun needOpenModifier() = false
|
||||
|
||||
public override fun toKotlin() : String {
|
||||
val primaryConstructorBody = primaryConstructorBodyToKotlin() ?: ""
|
||||
return modifiersToKotlin() +
|
||||
"enum class " + name.toKotlin() +
|
||||
primaryConstructorSignatureToKotlin() +
|
||||
typeParametersToKotlin() +
|
||||
implementTypesToKotlin() +
|
||||
" {\n" + membersExceptConstructors().toKotlin("\n") + "\n" +
|
||||
(if (primaryConstructorBody.isEmpty()) "" else primaryConstructorBody + "\n") +
|
||||
"}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class EnumConstant(identifier : Identifier,
|
||||
docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
`type` : Type,
|
||||
params : Element) : Field(identifier, docComments, modifiers, `type`.convertedToNotNull(), params, 0) {
|
||||
|
||||
public override fun toKotlin() : String {
|
||||
if (initializer.toKotlin().isEmpty()) {
|
||||
return identifier.toKotlin()
|
||||
}
|
||||
|
||||
return identifier.toKotlin() + " : " + `type`.toKotlin() + "(" + initializer.toKotlin() + ")"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public abstract class Expression(): Statement() {
|
||||
public open fun isNullable(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
class object {
|
||||
public val EMPTY_EXPRESSION: Expression = object: Expression() {
|
||||
public override fun toKotlin()= ""
|
||||
public override fun isEmpty() = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class ExpressionList(val expressions: List<Expression>): Expression() {
|
||||
public override fun toKotlin(): String = expressions.map { it.toKotlin() }.makeString(", ")
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class ArrayAccessExpression(val expression: Expression, val index: Expression, val lvalue: Boolean) : Expression() {
|
||||
override fun toKotlin() = expression.toKotlin() +
|
||||
(if (!lvalue && expression.isNullable()) "!!" else "") +
|
||||
"[" + index.toKotlin() + "]"
|
||||
}
|
||||
|
||||
public open class AssignmentExpression(val left : Expression, val right : Expression, val op : String) : Expression() {
|
||||
override fun toKotlin() = left.toKotlin() + " "+ op + " "+ right.toKotlin()
|
||||
}
|
||||
|
||||
public class BangBangExpression(val expr: Expression): Expression() {
|
||||
override fun toKotlin() = expr.toKotlin() + "!!"
|
||||
}
|
||||
|
||||
public open class BinaryExpression(val left: Expression, val right: Expression, val op: String): Expression() {
|
||||
override fun toKotlin() = left.toKotlin() + " " + op + " " + right.toKotlin()
|
||||
}
|
||||
|
||||
public open class ClassObjectAccessExpression(val typeElement: TypeElement): Expression() {
|
||||
override fun toKotlin() = "javaClass<" + typeElement.toKotlinNotNull() + ">()"
|
||||
}
|
||||
|
||||
public open class IsOperator(val expression: Expression, val typeElement: TypeElement): Expression() {
|
||||
override fun toKotlin() = expression.toKotlin() + " is " + typeElement.toKotlinNotNull()
|
||||
}
|
||||
|
||||
public open class TypeCastExpression(val `type` : Type, val expression : Expression) : Expression() {
|
||||
override fun toKotlin() = "(" + expression.toKotlin() + " as " + `type`.toKotlin() + ")"
|
||||
}
|
||||
|
||||
public open class LiteralExpression(val literalText: String): Expression() {
|
||||
override fun toKotlin() = literalText
|
||||
}
|
||||
|
||||
public open class ParenthesizedExpression(val expression : Expression) : Expression() {
|
||||
override fun toKotlin() = "(" + expression.toKotlin() + ")"
|
||||
}
|
||||
|
||||
public open class PrefixOperator(val op: String, val expression: Expression): Expression() {
|
||||
override fun toKotlin() = op + expression.toKotlin()
|
||||
override fun isNullable() = expression.isNullable()
|
||||
}
|
||||
|
||||
public open class PostfixOperator(val op: String, val expression: Expression): Expression() {
|
||||
override fun toKotlin() = expression.toKotlin() + op
|
||||
}
|
||||
|
||||
public open class ThisExpression(val identifier: Identifier) : Expression() {
|
||||
override fun toKotlin() = "this" + identifier.withPrefix("@")
|
||||
}
|
||||
|
||||
public open class SuperExpression(val identifier : Identifier) : Expression() {
|
||||
override fun toKotlin() = "super" + identifier.withPrefix("@")
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import java.util.LinkedList
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import java.util.ArrayList
|
||||
|
||||
public open class Field(val identifier : Identifier,
|
||||
val docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
val `type` : Type,
|
||||
val initializer : Element,
|
||||
val writingAccesses : Int) : Member(modifiers) {
|
||||
|
||||
open fun modifiersToKotlin() : String {
|
||||
val modifierList = ArrayList<Modifier>()
|
||||
if (isAbstract()) {
|
||||
modifierList.add(Modifier.ABSTRACT)
|
||||
}
|
||||
|
||||
val modifier = accessModifier()
|
||||
if (modifier != null) {
|
||||
modifierList.add(modifier)
|
||||
}
|
||||
|
||||
return modifierList.toKotlin() + (if (isVal()) "val " else "var ")
|
||||
}
|
||||
|
||||
public open fun isVal() : Boolean = modifiers.contains(Modifier.FINAL)
|
||||
public override fun isStatic() : Boolean = modifiers.contains(Modifier.STATIC)
|
||||
|
||||
public override fun toKotlin() : String {
|
||||
val declaration : String = docComments.toKotlin("\n", "", "\n") +
|
||||
modifiersToKotlin() + identifier.toKotlin() + " : " + `type`.toKotlin()
|
||||
if (initializer.isEmpty()) {
|
||||
return declaration + ((if (isVal() && !isStatic() && writingAccesses != 0)
|
||||
""
|
||||
else
|
||||
" = " + Converter.getDefaultInitializer(this)))
|
||||
}
|
||||
|
||||
return declaration + " = " + initializer.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
public open class File(val packageName: String,
|
||||
val imports: MutableList<Import>,
|
||||
val body: MutableList<Node>,
|
||||
val mainFunction: String): Node() {
|
||||
|
||||
public override fun toKotlin(): String {
|
||||
val common: String = imports.toKotlin("\n") + "\n\n" + body.toKotlin("\n") + "\n" + mainFunction
|
||||
if (packageName.isEmpty()) {
|
||||
return common
|
||||
}
|
||||
|
||||
return "package " + packageName + "\n" + common
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import java.util.LinkedList
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import java.util.ArrayList
|
||||
|
||||
public open class Function(val name : Identifier,
|
||||
val docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
val `type` : Type,
|
||||
val typeParameters : List<Element>,
|
||||
val params : Element,
|
||||
var block : Block?) : Member(modifiers) {
|
||||
private fun typeParametersToKotlin() : String {
|
||||
return (if (typeParameters.size() > 0)
|
||||
"<" + typeParameters.map { it.toKotlin() }.makeString(", ") + ">"
|
||||
else
|
||||
"")
|
||||
}
|
||||
|
||||
private fun hasWhere() : Boolean = typeParameters.any { it is TypeParameter && it.hasWhere() }
|
||||
|
||||
private fun typeParameterWhereToKotlin() : String {
|
||||
if (hasWhere())
|
||||
{
|
||||
val wheres = typeParameters.filter { it is TypeParameter }.map { ((it as TypeParameter).getWhereToKotlin() )}
|
||||
return " where " + wheres.makeString(", ") + " "
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
open fun modifiersToKotlin() : String {
|
||||
val modifierList = ArrayList<Modifier>()
|
||||
val accessModifier = accessModifier()
|
||||
if (accessModifier != null) {
|
||||
modifierList.add(accessModifier)
|
||||
}
|
||||
|
||||
if (isAbstract()) {
|
||||
modifierList.add(Modifier.ABSTRACT)
|
||||
}
|
||||
|
||||
if (modifiers.contains(Modifier.OVERRIDE)) {
|
||||
modifierList.add(Modifier.OVERRIDE)
|
||||
}
|
||||
|
||||
if (!modifiers.contains(Modifier.ABSTRACT) &&
|
||||
!modifiers.contains(Modifier.OVERRIDE) &&
|
||||
!modifiers.contains(Modifier.FINAL) &&
|
||||
!modifiers.contains(Modifier.PRIVATE)) {
|
||||
modifierList.add(Modifier.OPEN)
|
||||
}
|
||||
|
||||
if (modifiers.contains(Modifier.NOT_OPEN)) {
|
||||
modifierList.remove(Modifier.OPEN)
|
||||
}
|
||||
|
||||
return modifierList.toKotlin()
|
||||
}
|
||||
|
||||
public override fun toKotlin() : String {
|
||||
return docComments.toKotlin("\n", "", "\n") +
|
||||
modifiersToKotlin() +
|
||||
"fun " + name.toKotlin() +
|
||||
typeParametersToKotlin() +
|
||||
"(" + params.toKotlin() + ") : " +
|
||||
`type`.toKotlin() + " "+ typeParameterWhereToKotlin() +
|
||||
block?.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
|
||||
public open class Identifier(val name: String,
|
||||
val myNullable: Boolean = true,
|
||||
val quotingNeeded: Boolean = true): Expression() {
|
||||
public override fun isEmpty() = name.length() == 0
|
||||
|
||||
private open fun ifNeedQuote(): String {
|
||||
if (quotingNeeded && (ONLY_KOTLIN_KEYWORDS.contains(name)) || name.contains("$")) {
|
||||
return quote(name)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
public override fun toKotlin(): String = ifNeedQuote()
|
||||
public override fun isNullable(): Boolean = myNullable
|
||||
|
||||
class object {
|
||||
public val EMPTY_IDENTIFIER: Identifier = Identifier("")
|
||||
private open fun quote(str: String): String {
|
||||
return "`" + str + "`"
|
||||
}
|
||||
|
||||
public val ONLY_KOTLIN_KEYWORDS: Set<String> = hashSet(
|
||||
"package", "as", "type", "val", "var", "fun", "is", "in", "object", "when", "trait", "This"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public open class Import(val name: String): Node() {
|
||||
public override fun toKotlin() = "import " + name
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public open class Initializer(val block : Block, modifiers : Set<Modifier>) : Member(modifiers) {
|
||||
public override fun toKotlin() : String {
|
||||
return block.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class LocalVariable(val identifier: Identifier,
|
||||
val modifiersSet: Set<Modifier>,
|
||||
val `type`: Type,
|
||||
val initializer: Expression): Expression() {
|
||||
|
||||
public open fun hasModifier(modifier: Modifier): Boolean = modifiersSet.contains(modifier)
|
||||
|
||||
public override fun toKotlin(): String {
|
||||
if (initializer.isEmpty()) {
|
||||
return identifier.toKotlin() + " : " + `type`.toKotlin()
|
||||
}
|
||||
|
||||
return identifier.toKotlin() + " : " + `type`.toKotlin() + " = " + initializer.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
public abstract class Member(val modifiers : Set<Modifier>) : Node() {
|
||||
open fun accessModifier() : Modifier? {
|
||||
return modifiers.find { m -> m == Modifier.PUBLIC || m == Modifier.PROTECTED || m == Modifier.PRIVATE }
|
||||
}
|
||||
|
||||
public open fun isAbstract() : Boolean = modifiers.contains(Modifier.ABSTRACT)
|
||||
public open fun isStatic() : Boolean = modifiers.contains(Modifier.STATIC)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class MethodCallExpression(val methodCall: Expression,
|
||||
val arguments: List<Expression>,
|
||||
val typeParameters: List<Type>,
|
||||
val resultIsNullable: Boolean = false): Expression() {
|
||||
public override fun isNullable(): Boolean = methodCall.isNullable() || resultIsNullable
|
||||
|
||||
public override fun toKotlin(): String {
|
||||
val typeParamsToKotlin: String = typeParameters.toKotlin(", ", "<", ">")
|
||||
val argumentsMapped = arguments.map { it.toKotlin() }
|
||||
return methodCall.toKotlin() + typeParamsToKotlin + "(" + argumentsMapped.makeString(", ") + ")"
|
||||
}
|
||||
|
||||
class object {
|
||||
fun build(receiver: Expression, methodName: String, arguments: List<Expression> = arrayList()): MethodCallExpression {
|
||||
return MethodCallExpression(CallChainExpression(receiver, Identifier(methodName, false)),
|
||||
arguments,
|
||||
arrayList(), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
/*
|
||||
* Copyright 2010-2012 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.
|
||||
*/
|
||||
public enum class Modifier(val name: String) {
|
||||
PUBLIC: Modifier("public")
|
||||
PROTECTED: Modifier("protected")
|
||||
PRIVATE: Modifier("private")
|
||||
INTERNAL: Modifier("internal")
|
||||
STATIC: Modifier("static")
|
||||
ABSTRACT: Modifier("abstract")
|
||||
FINAL: Modifier("final")
|
||||
OPEN: Modifier("open")
|
||||
NOT_OPEN: Modifier("not open")
|
||||
OVERRIDE: Modifier("override")
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
public open class NewClassExpression(val name: Element,
|
||||
val arguments: List<Expression>,
|
||||
val qualifier: Expression = Expression.EMPTY_EXPRESSION,
|
||||
val anonymousClass: AnonymousClass? = null): Expression() {
|
||||
public override fun toKotlin(): String {
|
||||
val callOperator: String? = (if (qualifier.isNullable())
|
||||
"?."
|
||||
else
|
||||
".")
|
||||
val qualifier: String? = (if (qualifier.isEmpty())
|
||||
""
|
||||
else
|
||||
qualifier.toKotlin() + callOperator)
|
||||
val appliedArguments: String = arguments.toKotlin(", ")
|
||||
return (if (anonymousClass != null)
|
||||
"object : " + qualifier + name.toKotlin() + "(" + appliedArguments + ")" + anonymousClass.toKotlin()
|
||||
else
|
||||
qualifier + name.toKotlin() + "(" + appliedArguments + ")")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public abstract class Node() {
|
||||
public abstract fun toKotlin(): String
|
||||
|
||||
class object {
|
||||
public val PRIMITIVE_TYPES: Set<String> = hashSet(
|
||||
"double", "float", "long", "int", "short", "byte", "boolean", "char")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import org.jetbrains.jet.j2k.ast.types.VarArg
|
||||
|
||||
public open class Parameter(val identifier : Identifier, val `type` : Type, val readOnly: Boolean = true) : Expression() {
|
||||
public override fun toKotlin() : String {
|
||||
val vararg : String = (if (`type` is VarArg)
|
||||
"vararg "
|
||||
else
|
||||
"")
|
||||
val `var` : String? = (if (readOnly)
|
||||
""
|
||||
else
|
||||
"var ")
|
||||
return vararg + `var` + identifier.toKotlin() + " : " + `type`.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public open class ParameterList(val parameters : List<Parameter>) : Expression() {
|
||||
public override fun toKotlin() = parameters.map { it.toKotlin() }.makeString(", ")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public open class PolyadicExpression(val expressions: List<Expression>, val token: String): Expression() {
|
||||
public override fun toKotlin(): String {
|
||||
val expressionsWithConversions = expressions.map { it.toKotlin() }
|
||||
return expressionsWithConversions.makeString(" " + token + " ")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class ReferenceElement(val reference : Identifier, val types : List<Type>) : Element() {
|
||||
public override fun toKotlin() = reference.toKotlin() + types.toKotlin(", ", "<", ">")
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
public abstract class Statement(): Element() {
|
||||
class object {
|
||||
public val EMPTY_STATEMENT: Statement = object : Statement() {
|
||||
public override fun toKotlin() = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public open class DeclarationStatement(val elements: List<Element>): Statement() {
|
||||
public override fun toKotlin(): String {
|
||||
return elements.filter { it is LocalVariable }.map { convertDeclaration(it as LocalVariable) }.makeString("\n")
|
||||
}
|
||||
|
||||
private fun convertDeclaration(v: LocalVariable): String {
|
||||
val varKeyword: String? = (if (v.hasModifier(Modifier.FINAL))
|
||||
"val"
|
||||
else
|
||||
"var")
|
||||
return varKeyword + " " + v.toKotlin()
|
||||
}
|
||||
}
|
||||
|
||||
public open class ExpressionListStatement(val expressions: List<Expression>): Expression() {
|
||||
public override fun toKotlin() = expressions.toKotlin("\n")
|
||||
}
|
||||
|
||||
public open class LabelStatement(val name: Identifier, val statement: Element): Statement() {
|
||||
public override fun toKotlin(): String = "@" + name.toKotlin() + " " + statement.toKotlin()
|
||||
}
|
||||
|
||||
public open class ReturnStatement(val expression: Expression): Statement() {
|
||||
public override fun toKotlin() = "return " + expression.toKotlin()
|
||||
}
|
||||
|
||||
public open class IfStatement(val condition: Expression,
|
||||
val thenStatement: Element,
|
||||
val elseStatement: Element): Expression() {
|
||||
public override fun toKotlin(): String {
|
||||
val result: String = "if (" + condition.toKotlin() + ")\n" + thenStatement.toKotlin() + "\n"
|
||||
if (elseStatement != Statement.EMPTY_STATEMENT) {
|
||||
return result + "else\n" + elseStatement.toKotlin()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Loops --------------------------------------------------------------------------------------------------
|
||||
|
||||
public open class WhileStatement(val condition: Expression, val body: Element): Statement() {
|
||||
public override fun toKotlin() = "while (" + condition.toKotlin() + ")\n" + body.toKotlin()
|
||||
}
|
||||
|
||||
public open class DoWhileStatement(condition: Expression, body: Element): WhileStatement(condition, body) {
|
||||
public override fun toKotlin() = "do\n" + body.toKotlin() + "\nwhile (" + condition.toKotlin() + ")"
|
||||
}
|
||||
|
||||
public open class ForeachStatement(val variable: Parameter,
|
||||
val expression: Expression,
|
||||
val body: Element): Statement() {
|
||||
public override fun toKotlin() = "for (" + variable.toKotlin() + " in " +
|
||||
expression.toKotlin() + ")\n" + body.toKotlin()
|
||||
}
|
||||
|
||||
public open class ForeachWithRangeStatement(val identifier: Identifier,
|
||||
val start: Expression,
|
||||
val end: Expression,
|
||||
val body: Element): Statement() {
|
||||
public override fun toKotlin() = "for (" + identifier.toKotlin() + " in " +
|
||||
start.toKotlin() + ".." + end.toKotlin() + ") " + body.toKotlin()
|
||||
}
|
||||
|
||||
public open class BreakStatement(val label: Identifier = Identifier.EMPTY_IDENTIFIER) : Statement() {
|
||||
public override fun toKotlin() = "break" + label.withPrefix("@")
|
||||
}
|
||||
|
||||
public open class ContinueStatement(val label: Identifier = Identifier.EMPTY_IDENTIFIER): Statement() {
|
||||
public override fun toKotlin() = "continue" + label.withPrefix("@")
|
||||
}
|
||||
|
||||
// Exceptions ----------------------------------------------------------------------------------------------
|
||||
|
||||
public open class TryStatement(val block: Block, val catches: List<CatchStatement>, val finallyBlock: Block): Statement() {
|
||||
public override fun toKotlin(): String {
|
||||
return "try\n" + block.toKotlin() + "\n" + catches.toKotlin("\n") + "\n" + (if (finallyBlock.isEmpty())
|
||||
""
|
||||
else
|
||||
"finally\n" + finallyBlock.toKotlin())
|
||||
}
|
||||
}
|
||||
|
||||
public open class ThrowStatement(val expression: Expression): Expression() {
|
||||
public override fun toKotlin() = "throw " + expression.toKotlin()
|
||||
}
|
||||
|
||||
public open class CatchStatement(val variable: Parameter, val block: Block): Statement() {
|
||||
public override fun toKotlin(): String = "catch (" + variable.toKotlin() + ") " + block.toKotlin()
|
||||
}
|
||||
|
||||
// Switch --------------------------------------------------------------------------------------------------
|
||||
|
||||
public open class SwitchContainer(val expression: Expression, val caseContainers: List<CaseContainer>): Statement() {
|
||||
public override fun toKotlin() = "when (" + expression.toKotlin() + ") {\n" + caseContainers.toKotlin("\n") + "\n}"
|
||||
}
|
||||
|
||||
public open class CaseContainer(val caseStatement: List<Element>, statements: List<Element>): Statement() {
|
||||
private val myBlock: Block
|
||||
|
||||
{
|
||||
val newStatements = statements.filterNot { it is BreakStatement || it is ContinueStatement }
|
||||
myBlock = Block(newStatements, true)
|
||||
}
|
||||
|
||||
public override fun toKotlin() = caseStatement.toKotlin(", ") + " -> " + myBlock.toKotlin()
|
||||
}
|
||||
|
||||
public open class SwitchLabelStatement(val expression: Expression): Statement() {
|
||||
public override fun toKotlin() = expression.toKotlin()
|
||||
}
|
||||
|
||||
public open class DefaultSwitchLabelStatement(): Statement() {
|
||||
public override fun toKotlin() = "else"
|
||||
}
|
||||
|
||||
// Other ------------------------------------------------------------------------------------------------------
|
||||
|
||||
public open class SynchronizedStatement(val expression: Expression, val block: Block): Statement() {
|
||||
public override fun toKotlin() = "synchronized (" + expression.toKotlin() + ") "+ block.toKotlin()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class Trait(converter : Converter,
|
||||
name : Identifier,
|
||||
docComments: List<Node>,
|
||||
modifiers : Set<Modifier>,
|
||||
typeParameters : List<Element>,
|
||||
extendsTypes : List<Type>,
|
||||
baseClassParams : List<Expression>,
|
||||
implementsTypes : List<Type>,
|
||||
members : List<Node>) : Class(converter, name, docComments, modifiers, typeParameters,
|
||||
extendsTypes, baseClassParams, implementsTypes, members) {
|
||||
|
||||
override val TYPE: String
|
||||
get() = "trait"
|
||||
|
||||
override fun primaryConstructorSignatureToKotlin() = ""
|
||||
override fun needOpenModifier() = false
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class TypeElement(val `type` : Type) : Element() {
|
||||
override fun toKotlin() = `type`.toKotlin()
|
||||
|
||||
public fun toKotlinNotNull(): String = `type`.convertedToNotNull().toKotlin()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class TypeParameter(val name : Identifier, val extendsTypes : List<Type>) : Element() {
|
||||
public open fun hasWhere() : Boolean = extendsTypes.size() > 1
|
||||
public open fun getWhereToKotlin() : String {
|
||||
if (hasWhere()) {
|
||||
return name.toKotlin() + " : " + extendsTypes.get(1).toKotlin()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
public override fun toKotlin() : String {
|
||||
if (extendsTypes.size() > 0) {
|
||||
return name.toKotlin() + " : " + extendsTypes [0].toKotlin()
|
||||
}
|
||||
|
||||
return name.toKotlin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
fun List<Node>.toKotlin(separator: String, prefix: String = "", suffix: String = ""): String {
|
||||
val result = StringBuilder()
|
||||
if (size() > 0) {
|
||||
result.append(prefix)
|
||||
var first = true
|
||||
for(x in this) {
|
||||
if (!first) result.append(separator)
|
||||
first = false
|
||||
result.append(x.toKotlin())
|
||||
}
|
||||
result.append(suffix)
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
fun Collection<Modifier>.toKotlin(separator: String = " "): String {
|
||||
val result = StringBuilder()
|
||||
for(x in this) {
|
||||
result.append(x.name)
|
||||
result.append(separator)
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
fun String.withPrefix(prefix: String) = if (isEmpty()) "" else prefix + this
|
||||
fun Expression.withPrefix(prefix: String) = if (isEmpty()) "" else prefix + toKotlin()
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
public open class ArrayType(val elementType : Type, nullable: Boolean) : Type(nullable) {
|
||||
public override fun toKotlin() : String {
|
||||
if (elementType is PrimitiveType) {
|
||||
return elementType.toKotlin() + "Array" + isNullableStr()
|
||||
}
|
||||
|
||||
return "Array<" + elementType.toKotlin() + ">" + isNullableStr()
|
||||
}
|
||||
|
||||
public override fun convertedToNotNull() : Type = ArrayType(elementType, false)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.Element
|
||||
import org.jetbrains.jet.j2k.ast.Identifier
|
||||
import java.util.Collections
|
||||
import java.util.ArrayList
|
||||
|
||||
public open class ClassType(val `type` : Identifier, val parameters : List<Element>, nullable : Boolean) : Type(nullable) {
|
||||
public override fun toKotlin() : String {
|
||||
// TODO change to map() when KT-2051 is fixed
|
||||
val parametersToKotlin = ArrayList<String>()
|
||||
for(param in parameters) {
|
||||
parametersToKotlin.add(param.toKotlin())
|
||||
}
|
||||
var params : String = if (parametersToKotlin.size() == 0)
|
||||
""
|
||||
else
|
||||
"<" + parametersToKotlin.makeString(", ") + ">"
|
||||
return `type`.toKotlin() + params + isNullableStr()
|
||||
}
|
||||
|
||||
|
||||
public override fun convertedToNotNull() : Type = ClassType(`type`, parameters, false)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
public open class EmptyType() : Type(false) {
|
||||
public override fun toKotlin() : String = "UNRESOLVED_TYPE"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
public open class InProjectionType(val bound : Type) : Type(false) {
|
||||
public override fun toKotlin() : String = "in " + bound.toKotlin()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
public open class OutProjectionType(val bound : Type) : Type(false) {
|
||||
public override fun toKotlin() : String = "out " + bound.toKotlin()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.Identifier
|
||||
|
||||
public open class PrimitiveType(val `type` : Identifier) : Type(false) {
|
||||
public override fun toKotlin() : String = `type`.toKotlin()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
public open class StarProjectionType() : Type(false) {
|
||||
public override fun toKotlin() : String = "*"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.Element
|
||||
|
||||
public abstract class Type(val nullable: Boolean) : Element() {
|
||||
public open fun convertedToNotNull() : Type {
|
||||
if (nullable) throw UnsupportedOperationException("convertedToNotNull must be defined")
|
||||
return this
|
||||
}
|
||||
|
||||
public open fun isNullableStr() : String? {
|
||||
return (if (nullable)
|
||||
"?"
|
||||
else
|
||||
"")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.j2k.ast.types
|
||||
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
|
||||
public open class VarArg(val `type` : Type) : Type(false) {
|
||||
public override fun toKotlin() : String = `type`.toKotlin()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.JavaRecursiveElementVisitor
|
||||
import com.intellij.psi.PsiClass
|
||||
import java.util.HashSet
|
||||
|
||||
public open class ClassVisitor(): JavaRecursiveElementVisitor() {
|
||||
private val myClassIdentifiers = HashSet<String>()
|
||||
|
||||
public open fun getClassIdentifiers(): Set<String> {
|
||||
return HashSet<String>(myClassIdentifiers)
|
||||
}
|
||||
|
||||
public override fun visitClass(aClass: PsiClass?): Unit {
|
||||
val qName = aClass?.getQualifiedName()
|
||||
if (qName != null) {
|
||||
myClassIdentifiers.add(qName)
|
||||
}
|
||||
super.visitClass(aClass)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
|
||||
public open class Dispatcher(converter: Converter) {
|
||||
public var expressionVisitor: ExpressionVisitor = ExpressionVisitor(converter)
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.*
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import org.jetbrains.jet.j2k.isAnnotatedAsNotNull
|
||||
import org.jetbrains.jet.j2k.isDefinitelyNotNull
|
||||
|
||||
public open class ElementVisitor(val myConverter : Converter) : JavaElementVisitor() {
|
||||
protected var myResult : Element = Element.EMPTY_ELEMENT
|
||||
|
||||
public fun getConverter() : Converter {
|
||||
return myConverter
|
||||
}
|
||||
|
||||
public open fun getResult() : Element {
|
||||
return myResult
|
||||
}
|
||||
|
||||
public override fun visitLocalVariable(variable : PsiLocalVariable?) : Unit {
|
||||
val theVariable = variable!!
|
||||
var kType = myConverter.typeToType(theVariable.getType(), isAnnotatedAsNotNull(theVariable.getModifierList()))
|
||||
if (theVariable.hasModifierProperty(PsiModifier.FINAL) && isDefinitelyNotNull(theVariable.getInitializer())) {
|
||||
kType = kType.convertedToNotNull();
|
||||
}
|
||||
myResult = LocalVariable(Identifier(theVariable.getName()!!),
|
||||
Converter.modifiersListToModifiersSet(theVariable.getModifierList()),
|
||||
kType,
|
||||
myConverter.expressionToExpression(theVariable.getInitializer(), theVariable.getType()))
|
||||
}
|
||||
|
||||
public override fun visitExpressionList(list : PsiExpressionList?) : Unit {
|
||||
myResult = ExpressionList(myConverter.expressionsToExpressionList(list!!.getExpressions()))
|
||||
}
|
||||
|
||||
public override fun visitReferenceElement(reference : PsiJavaCodeReferenceElement?) : Unit {
|
||||
val theReference = reference!!
|
||||
val types : List<Type> = myConverter.typesToTypeList(theReference.getTypeParameters())
|
||||
if (!theReference.isQualified()) {
|
||||
myResult = ReferenceElement(Identifier(theReference.getReferenceName()!!), types)
|
||||
}
|
||||
else {
|
||||
var result : String = Identifier(reference.getReferenceName()!!).toKotlin()
|
||||
var qualifier : PsiElement? = theReference.getQualifier()
|
||||
while (qualifier != null)
|
||||
{
|
||||
val p : PsiJavaCodeReferenceElement = (qualifier as PsiJavaCodeReferenceElement)
|
||||
result = Identifier(p.getReferenceName()!!).toKotlin() + "." + result
|
||||
qualifier = p.getQualifier()
|
||||
}
|
||||
myResult = ReferenceElement(Identifier(result), types)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitTypeElement(`type` : PsiTypeElement?) : Unit {
|
||||
myResult = TypeElement(myConverter.typeToType(`type`!!.getType()))
|
||||
}
|
||||
|
||||
public override fun visitTypeParameter(classParameter : PsiTypeParameter?) : Unit {
|
||||
myResult = TypeParameter(Identifier(classParameter!!.getName()!!),
|
||||
classParameter.getExtendsListTypes().map { myConverter.typeToType(it) } )
|
||||
}
|
||||
|
||||
public override fun visitParameterList(list : PsiParameterList?) : Unit {
|
||||
myResult = ParameterList(myConverter.parametersToParameterList(list!!.getParameters()).requireNoNulls())
|
||||
}
|
||||
|
||||
public override fun visitComment(comment: PsiComment?) {
|
||||
myResult = Comment(comment?.getText()!!)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.*
|
||||
import org.jetbrains.jet.j2k.ast.types.EmptyType
|
||||
import org.jetbrains.jet.j2k.ast.types.Type
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import com.intellij.psi.CommonClassNames.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.lang.types.lang.PrimitiveType
|
||||
import org.jetbrains.jet.j2k.isAnnotatedAsNotNull
|
||||
|
||||
public open class ExpressionVisitor(converter: Converter): StatementVisitor(converter) {
|
||||
{
|
||||
myResult = Expression.EMPTY_EXPRESSION
|
||||
}
|
||||
|
||||
public override fun getResult(): Expression {
|
||||
return myResult as Expression
|
||||
}
|
||||
|
||||
public override fun visitArrayAccessExpression(expression: PsiArrayAccessExpression?): Unit {
|
||||
val assignment = PsiTreeUtil.getParentOfType(expression, javaClass<PsiAssignmentExpression>())
|
||||
val lvalue = assignment != null && expression == assignment.getLExpression();
|
||||
myResult = ArrayAccessExpression(getConverter().expressionToExpression(expression?.getArrayExpression()),
|
||||
getConverter().expressionToExpression(expression?.getIndexExpression()),
|
||||
lvalue)
|
||||
}
|
||||
|
||||
public override fun visitArrayInitializerExpression(expression: PsiArrayInitializerExpression?): Unit {
|
||||
myResult = ArrayInitializerExpression(getConverter().typeToType(expression?.getType()),
|
||||
getConverter().expressionsToExpressionList(expression?.getInitializers()!!))
|
||||
}
|
||||
|
||||
public override fun visitAssignmentExpression(expression: PsiAssignmentExpression?): Unit {
|
||||
val tokenType: IElementType = expression?.getOperationSign()?.getTokenType()!!
|
||||
val secondOp: String = when(tokenType) {
|
||||
JavaTokenType.GTGTEQ -> "shr"
|
||||
JavaTokenType.LTLTEQ -> "shl"
|
||||
JavaTokenType.XOREQ -> "xor"
|
||||
JavaTokenType.ANDEQ -> "and"
|
||||
JavaTokenType.OREQ -> "or"
|
||||
JavaTokenType.GTGTGTEQ -> "ushr"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val lhs = getConverter().expressionToExpression(expression?.getLExpression()!!)
|
||||
val rhs = getConverter().expressionToExpression(expression?.getRExpression()!!, expression?.getLExpression()?.getType())
|
||||
if (!secondOp.isEmpty()) {
|
||||
myResult = AssignmentExpression(lhs, BinaryExpression(lhs, rhs, secondOp), "=")
|
||||
}
|
||||
else {
|
||||
myResult = AssignmentExpression(lhs, rhs, expression?.getOperationSign()?.getText()!!)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitBinaryExpression(expression: PsiBinaryExpression?): Unit {
|
||||
val lhs = getConverter().expressionToExpression(expression?.getLOperand()!!, expression?.getType())
|
||||
val rhs = getConverter().expressionToExpression(expression?.getROperand(), expression?.getType())
|
||||
if (expression?.getOperationSign()?.getTokenType() == JavaTokenType.GTGTGT) {
|
||||
myResult = MethodCallExpression.build(lhs, "ushr", arrayList(rhs))
|
||||
}
|
||||
else {
|
||||
myResult = BinaryExpression(lhs, rhs,
|
||||
getOperatorString(expression?.getOperationSign()?.getTokenType()!!))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitClassObjectAccessExpression(expression: PsiClassObjectAccessExpression?): Unit {
|
||||
myResult = ClassObjectAccessExpression(getConverter().typeElementToTypeElement(expression?.getOperand()))
|
||||
}
|
||||
|
||||
public override fun visitConditionalExpression(expression: PsiConditionalExpression?): Unit {
|
||||
val condition: PsiExpression? = expression?.getCondition()
|
||||
val `type`: PsiType? = condition?.getType()
|
||||
val e: Expression = (if (`type` != null)
|
||||
getConverter().expressionToExpression(condition, `type`)
|
||||
else
|
||||
getConverter().expressionToExpression(condition))
|
||||
myResult = ParenthesizedExpression(IfStatement(e,
|
||||
getConverter().expressionToExpression(expression?.getThenExpression()),
|
||||
getConverter().expressionToExpression(expression?.getElseExpression())))
|
||||
}
|
||||
|
||||
public override fun visitExpressionList(list: PsiExpressionList?): Unit {
|
||||
myResult = ExpressionList(getConverter().expressionsToExpressionList(list!!.getExpressions()))
|
||||
}
|
||||
|
||||
public override fun visitInstanceOfExpression(expression: PsiInstanceOfExpression?): Unit {
|
||||
val checkType: PsiTypeElement? = expression?.getCheckType()
|
||||
myResult = IsOperator(getConverter().expressionToExpression(expression?.getOperand()),
|
||||
myConverter.typeElementToTypeElement(checkType))
|
||||
}
|
||||
|
||||
public override fun visitLiteralExpression(expression: PsiLiteralExpression?): Unit {
|
||||
val value: Any? = expression?.getValue()
|
||||
var text: String = expression?.getText()!!
|
||||
val `type`: PsiType? = expression?.getType()
|
||||
if (`type` != null) {
|
||||
val canonicalTypeStr: String? = `type`.getCanonicalText()
|
||||
if (canonicalTypeStr?.equals("double")!! || canonicalTypeStr?.equals(JAVA_LANG_DOUBLE)!!) {
|
||||
text = text.replace("D", "").replace("d", "")
|
||||
if (!text.contains(".")) {
|
||||
text += ".0"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (canonicalTypeStr?.equals("float")!! || canonicalTypeStr?.equals(JAVA_LANG_FLOAT)!!) {
|
||||
text = text.replace("F", "").replace("f", "") + "." + OperatorConventions.FLOAT + "()"
|
||||
}
|
||||
|
||||
if (canonicalTypeStr?.equals("long")!! || canonicalTypeStr?.equals(JAVA_LANG_LONG)!!) {
|
||||
text = text.replace("L", "").replace("l", "")
|
||||
}
|
||||
|
||||
if (canonicalTypeStr?.equals("int")!! || canonicalTypeStr?.equals(JAVA_LANG_INTEGER)!!) {
|
||||
text = (if (value != null) value.toString() else text)
|
||||
}
|
||||
}
|
||||
|
||||
myResult = LiteralExpression(text)
|
||||
}
|
||||
|
||||
public override fun visitMethodCallExpression(expression: PsiMethodCallExpression?): Unit {
|
||||
convertMethodCallExpression(expression!!)
|
||||
}
|
||||
|
||||
protected fun convertMethodCallExpression(expression: PsiMethodCallExpression) {
|
||||
if (!SuperVisitor.isSuper(expression.getMethodExpression()) || !isInsidePrimaryConstructor(expression)) {
|
||||
myResult = MethodCallExpression(getConverter().expressionToExpression(expression.getMethodExpression()),
|
||||
getConverter().argumentsToExpressionList(expression),
|
||||
getConverter().typesToTypeList(expression.getTypeArguments()),
|
||||
getConverter().typeToType(expression.getType()).nullable)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitNewExpression(expression: PsiNewExpression?): Unit {
|
||||
if (expression?.getArrayInitializer() != null)
|
||||
{
|
||||
myResult = createNewEmptyArray(expression)
|
||||
}
|
||||
else
|
||||
if (expression?.getArrayDimensions()?.size!! > 0) {
|
||||
myResult = createNewEmptyArrayWithoutInitialization(expression!!)
|
||||
}
|
||||
else
|
||||
{
|
||||
myResult = createNewClassExpression(expression)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createNewClassExpression(expression: PsiNewExpression?): Expression {
|
||||
val anonymousClass: PsiAnonymousClass? = expression?.getAnonymousClass()
|
||||
val constructor: PsiMethod? = expression?.resolveMethod()
|
||||
var classReference: PsiJavaCodeReferenceElement? = expression?.getClassOrAnonymousClassReference()
|
||||
val isNotConvertedClass: Boolean = classReference != null && !getConverter().getClassIdentifiers().contains(classReference?.getQualifiedName())
|
||||
var argumentList: PsiExpressionList? = expression?.getArgumentList()
|
||||
var arguments: Array<PsiExpression> = (if (argumentList != null)
|
||||
argumentList?.getExpressions()!!
|
||||
else
|
||||
array<PsiExpression>())
|
||||
if (constructor == null || Converter.isConstructorPrimary(constructor) || isNotConvertedClass)
|
||||
{
|
||||
return NewClassExpression(getConverter().elementToElement(classReference),
|
||||
getConverter().argumentsToExpressionList(expression!!),
|
||||
getConverter().expressionToExpression(expression.getQualifier()),
|
||||
(if (anonymousClass != null)
|
||||
getConverter().anonymousClassToAnonymousClass(anonymousClass)
|
||||
else
|
||||
null))
|
||||
}
|
||||
|
||||
val reference: PsiJavaCodeReferenceElement? = expression?.getClassReference()
|
||||
val typeParameters: List<Type> = (if (reference != null)
|
||||
getConverter().typesToTypeList(reference.getTypeParameters())
|
||||
else
|
||||
Collections.emptyList<Type>())
|
||||
return CallChainExpression(Identifier(constructor.getName(), false),
|
||||
MethodCallExpression(Identifier("init"), getConverter().expressionsToExpressionList(arguments), typeParameters, false))
|
||||
}
|
||||
|
||||
private fun createNewEmptyArrayWithoutInitialization(expression: PsiNewExpression): Expression {
|
||||
return ArrayWithoutInitializationExpression(
|
||||
getConverter().typeToType(expression.getType(), true),
|
||||
getConverter().expressionsToExpressionList(expression.getArrayDimensions()))
|
||||
}
|
||||
|
||||
private fun createNewEmptyArray(expression: PsiNewExpression?): Expression {
|
||||
return getConverter().expressionToExpression(expression?.getArrayInitializer())
|
||||
}
|
||||
|
||||
public override fun visitParenthesizedExpression(expression: PsiParenthesizedExpression?): Unit {
|
||||
myResult = ParenthesizedExpression(getConverter().expressionToExpression(expression?.getExpression()))
|
||||
}
|
||||
|
||||
public override fun visitPostfixExpression(expression: PsiPostfixExpression?): Unit {
|
||||
myResult = PostfixOperator(getOperatorString(expression!!.getOperationSign().getTokenType()!!),
|
||||
getConverter().expressionToExpression(expression.getOperand()))
|
||||
}
|
||||
|
||||
public override fun visitPrefixExpression(expression: PsiPrefixExpression?): Unit {
|
||||
val operand = getConverter().expressionToExpression(expression?.getOperand(), expression?.getOperand()!!.getType())
|
||||
val token = expression?.getOperationTokenType()!!
|
||||
if (token == JavaTokenType.TILDE) {
|
||||
myResult = MethodCallExpression.build(ParenthesizedExpression(operand), "inv", arrayList())
|
||||
}
|
||||
else {
|
||||
myResult = PrefixOperator(getOperatorString(token), operand)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitReferenceExpression(expression: PsiReferenceExpression?): Unit {
|
||||
val isFieldReference: Boolean = isFieldReference(expression!!, getContainingClass(expression))
|
||||
val insideSecondaryConstructor: Boolean = isInsideSecondaryConstructor(expression)
|
||||
val hasReceiver: Boolean = isFieldReference && insideSecondaryConstructor
|
||||
val isThis: Boolean = isThisExpression(expression)
|
||||
val notNull = isResolvedToNotNull(expression)
|
||||
val isNullable: Boolean = getConverter().typeToType(expression.getType(), notNull).nullable
|
||||
val className: String = getClassNameWithConstructor(expression)
|
||||
val referencedName = expression.getReferenceName()!!
|
||||
var identifier: Expression = Identifier(referencedName, isNullable)
|
||||
val __: String = "__"
|
||||
val qualifier = expression.getQualifierExpression()
|
||||
if (hasReceiver){
|
||||
identifier = CallChainExpression(Identifier(__, false), Identifier(referencedName, isNullable))
|
||||
}
|
||||
else if (insideSecondaryConstructor && isThis) {
|
||||
identifier = Identifier("val __ = " + className)
|
||||
}
|
||||
else if (qualifier != null && qualifier.getType() is PsiArrayType && referencedName == "length") {
|
||||
identifier = Identifier("size", isNullable)
|
||||
}
|
||||
else if (qualifier == null) {
|
||||
val resolved = expression.getReference()?.resolve()
|
||||
if (resolved is PsiClass) {
|
||||
val clazz = resolved as PsiClass
|
||||
|
||||
if (PrimitiveType.values() any { it.getTypeName().asString() == clazz.getName() }) {
|
||||
myResult = Identifier(clazz.getQualifiedName()!!, false)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (resolved is PsiMember && resolved.hasModifierProperty(PsiModifier.STATIC) &&
|
||||
resolved.getContainingClass() != null &&
|
||||
PsiTreeUtil.getParentOfType(expression, javaClass<PsiClass>()) != resolved.getContainingClass() &&
|
||||
!isStaticallyImported(resolved, expression)) {
|
||||
var member = resolved as PsiMember
|
||||
var result = Identifier(referencedName).toKotlin()
|
||||
while(member.getContainingClass() != null) {
|
||||
result = Identifier(member.getContainingClass()!!.getName()!!).toKotlin() + "." + result
|
||||
member = member.getContainingClass()!!
|
||||
}
|
||||
myResult = Identifier(result, false, false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
myResult = CallChainExpression(getConverter().expressionToExpression(qualifier), identifier)
|
||||
}
|
||||
|
||||
private fun isResolvedToNotNull(expression: PsiReference): Boolean {
|
||||
val target = expression.resolve()
|
||||
if (target is PsiEnumConstant) {
|
||||
return true;
|
||||
}
|
||||
if (target is PsiModifierListOwner) {
|
||||
return isAnnotatedAsNotNull(target.getModifierList());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override fun visitSuperExpression(expression: PsiSuperExpression?): Unit {
|
||||
val qualifier: PsiJavaCodeReferenceElement? = expression?.getQualifier()
|
||||
myResult = SuperExpression((if (qualifier != null)
|
||||
Identifier(qualifier.getQualifiedName()!!)
|
||||
else
|
||||
Identifier.EMPTY_IDENTIFIER))
|
||||
}
|
||||
|
||||
public override fun visitThisExpression(expression: PsiThisExpression?): Unit {
|
||||
val qualifier: PsiJavaCodeReferenceElement? = expression?.getQualifier()
|
||||
myResult = ThisExpression((if (qualifier != null)
|
||||
Identifier(qualifier.getQualifiedName()!!)
|
||||
else
|
||||
Identifier.EMPTY_IDENTIFIER))
|
||||
}
|
||||
|
||||
public override fun visitTypeCastExpression(expression: PsiTypeCastExpression?): Unit {
|
||||
val castType: PsiTypeElement? = expression?.getCastType()
|
||||
if (castType != null) {
|
||||
val operand = expression?.getOperand()
|
||||
val operandType = operand?.getType()
|
||||
val typeText = castType.getType().getCanonicalText()
|
||||
val typeConversion = Converter.PRIMITIVE_TYPE_CONVERSIONS[typeText]
|
||||
if (operandType is PsiPrimitiveType && typeConversion != null) {
|
||||
myResult = MethodCallExpression.build(getConverter().expressionToExpression(operand), typeConversion)
|
||||
}
|
||||
else {
|
||||
myResult = TypeCastExpression(getConverter().typeToType(castType.getType()),
|
||||
getConverter().expressionToExpression(operand))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitPolyadicExpression(expression: PsiPolyadicExpression?): Unit {
|
||||
var parameters = ArrayList<Expression>()
|
||||
for (operand : PsiExpression in expression?.getOperands()!!) {
|
||||
parameters.add(getConverter().expressionToExpression(operand, expression?.getType()))
|
||||
}
|
||||
myResult = PolyadicExpression(parameters, getOperatorString(expression?.getOperationTokenType()!!))
|
||||
}
|
||||
|
||||
class object {
|
||||
private fun getOperatorString(tokenType: IElementType): String {
|
||||
if (tokenType == JavaTokenType.PLUS)
|
||||
return "+"
|
||||
|
||||
if (tokenType == JavaTokenType.MINUS)
|
||||
return "-"
|
||||
|
||||
if (tokenType == JavaTokenType.ASTERISK)
|
||||
return "*"
|
||||
|
||||
if (tokenType == JavaTokenType.DIV)
|
||||
return "/"
|
||||
|
||||
if (tokenType == JavaTokenType.PERC)
|
||||
return "%"
|
||||
|
||||
if (tokenType == JavaTokenType.GTGT)
|
||||
return "shr"
|
||||
|
||||
if (tokenType == JavaTokenType.LTLT)
|
||||
return "shl"
|
||||
|
||||
if (tokenType == JavaTokenType.XOR)
|
||||
return "xor"
|
||||
|
||||
if (tokenType == JavaTokenType.AND)
|
||||
return "and"
|
||||
|
||||
if (tokenType == JavaTokenType.OR)
|
||||
return "or"
|
||||
|
||||
if (tokenType == JavaTokenType.GTGTGT)
|
||||
return "ushr"
|
||||
|
||||
if (tokenType == JavaTokenType.GT)
|
||||
return ">"
|
||||
|
||||
if (tokenType == JavaTokenType.LT)
|
||||
return "<"
|
||||
|
||||
if (tokenType == JavaTokenType.GE)
|
||||
return ">="
|
||||
|
||||
if (tokenType == JavaTokenType.LE)
|
||||
return "<="
|
||||
|
||||
if (tokenType == JavaTokenType.EQEQ)
|
||||
return "=="
|
||||
|
||||
if (tokenType == JavaTokenType.NE)
|
||||
return "!="
|
||||
|
||||
if (tokenType == JavaTokenType.ANDAND)
|
||||
return "&&"
|
||||
|
||||
if (tokenType == JavaTokenType.OROR)
|
||||
return "||"
|
||||
|
||||
if (tokenType == JavaTokenType.PLUSPLUS)
|
||||
return "++"
|
||||
|
||||
if (tokenType == JavaTokenType.MINUSMINUS)
|
||||
return "--"
|
||||
|
||||
if (tokenType == JavaTokenType.EXCL)
|
||||
return "!"
|
||||
|
||||
// System.out.println("UNSUPPORTED TOKEN TYPE: " + tokenType?.toString())
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun getClassNameWithConstructor(expression: PsiReferenceExpression): String {
|
||||
var context: PsiElement? = expression.getContext()
|
||||
while (context != null) {
|
||||
if (context is PsiMethod && ((context as PsiMethod)).isConstructor()) {
|
||||
val containingClass: PsiClass? = ((context as PsiMethod)).getContainingClass()
|
||||
if (containingClass != null) {
|
||||
val identifier: PsiIdentifier? = containingClass.getNameIdentifier()
|
||||
if (identifier != null) {
|
||||
return identifier.getText()!!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context = context?.getContext()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
open fun getClassName(expression: PsiExpression): String {
|
||||
var context: PsiElement? = expression.getContext()
|
||||
while (context != null)
|
||||
{
|
||||
if ((context is PsiClass?)) {
|
||||
val containingClass: PsiClass? = (context as PsiClass?)
|
||||
val identifier: PsiIdentifier? = containingClass?.getNameIdentifier()
|
||||
if (identifier != null) {
|
||||
return identifier.getText()!!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context = context?.getContext()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun isFieldReference(expression: PsiReferenceExpression, currentClass: PsiClass?): Boolean {
|
||||
val reference: PsiReference? = expression.getReference()
|
||||
if (reference != null) {
|
||||
val resolvedReference: PsiElement? = reference.resolve()
|
||||
if (resolvedReference is PsiField) {
|
||||
return (resolvedReference as PsiField).getContainingClass() == currentClass
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isInsideSecondaryConstructor(expression: PsiReferenceExpression): Boolean {
|
||||
var context: PsiElement? = expression.getContext()
|
||||
while (context != null) {
|
||||
if (context is PsiMethod && (context as PsiMethod).isConstructor()) {
|
||||
return !Converter.isConstructorPrimary((context as PsiMethod))
|
||||
}
|
||||
|
||||
context = context?.getContext()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isInsidePrimaryConstructor(expression: PsiExpression): Boolean {
|
||||
var context: PsiElement? = expression.getContext()
|
||||
while (context != null) {
|
||||
if (context is PsiMethod && (context as PsiMethod).isConstructor()) {
|
||||
return Converter.isConstructorPrimary(context as PsiMethod)
|
||||
}
|
||||
|
||||
context = context?.getContext()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getContainingClass(expression: PsiExpression): PsiClass? {
|
||||
var context: PsiElement? = expression.getContext()
|
||||
while (context != null)
|
||||
{
|
||||
if (context is PsiMethod && (context as PsiMethod).isConstructor())
|
||||
{
|
||||
return (context as PsiMethod).getContainingClass()
|
||||
}
|
||||
|
||||
context = context?.getContext()
|
||||
}
|
||||
return null
|
||||
}
|
||||
private fun isThisExpression(expression: PsiReferenceExpression): Boolean {
|
||||
for (r : PsiReference? in expression.getReferences())
|
||||
if (r?.getCanonicalText()?.equals("this")!!)
|
||||
{
|
||||
val res: PsiElement? = r?.resolve()
|
||||
if (res is PsiMethod && res.isConstructor()) {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isStaticallyImported(member: PsiMember, context: PsiElement): Boolean {
|
||||
val containingFile = context.getContainingFile()
|
||||
val targetContainingClass = member.getContainingClass()
|
||||
if (containingFile is PsiJavaFile && targetContainingClass != null) {
|
||||
val importList = containingFile.getImportList();
|
||||
if (importList != null) {
|
||||
val importStatics = importList.getImportStaticStatements();
|
||||
return importStatics.any { importResolvesTo(it, member) }
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun importResolvesTo(stmt: PsiImportStaticStatement?, member: PsiMember): Boolean {
|
||||
val targetContainingClass = member.getContainingClass()
|
||||
var importedClass = stmt?.resolveTargetClass()
|
||||
return importedClass == targetContainingClass && (stmt?.isOnDemand() ?: false ||
|
||||
stmt?.getReferenceName() == member.getName())
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.DummyStringExpression
|
||||
import org.jetbrains.jet.j2k.ast.Identifier
|
||||
import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT
|
||||
import org.jetbrains.jet.j2k.ast.MethodCallExpression
|
||||
|
||||
public open class ExpressionVisitorForDirectObjectInheritors(converter: Converter): ExpressionVisitor(converter) {
|
||||
public override fun visitMethodCallExpression(expression: PsiMethodCallExpression?): Unit {
|
||||
val methodExpression = expression?.getMethodExpression()!!
|
||||
if (superMethodInvocation(methodExpression, "hashCode")) {
|
||||
myResult = MethodCallExpression.build(Identifier("System", false), "identityHashCode", arrayList(Identifier("this")))
|
||||
}
|
||||
else if (superMethodInvocation(methodExpression, "equals")) {
|
||||
myResult = MethodCallExpression.build(Identifier("this", false), "identityEquals", getConverter().argumentsToExpressionList(expression!!))
|
||||
}
|
||||
else if (superMethodInvocation(methodExpression, "toString")) {
|
||||
myResult = DummyStringExpression(java.lang.String.format("getJavaClass<%s>.getName() + '@' + Integer.toHexString(hashCode())",
|
||||
ExpressionVisitor.getClassName(methodExpression)))
|
||||
}
|
||||
else {
|
||||
convertMethodCallExpression(expression!!)
|
||||
}
|
||||
}
|
||||
|
||||
class object {
|
||||
private fun superMethodInvocation(expression: PsiReferenceExpression, methodName: String?): Boolean {
|
||||
val referenceName: String? = expression.getReferenceName()
|
||||
val qualifierExpression: PsiExpression? = expression.getQualifierExpression()
|
||||
if (referenceName == methodName && qualifierExpression is PsiSuperExpression) {
|
||||
val `type`: PsiType? = qualifierExpression.getType()
|
||||
if (`type` != null && `type`.getCanonicalText() == JAVA_LANG_OBJECT) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.ast.*
|
||||
import java.util.Arrays
|
||||
import java.util.Collections
|
||||
import java.util.LinkedList
|
||||
import org.jetbrains.jet.j2k.countWritingAccesses
|
||||
import java.util.ArrayList
|
||||
|
||||
public open class StatementVisitor(converter: Converter): ElementVisitor(converter) {
|
||||
public override fun visitAssertStatement(statement: PsiAssertStatement?): Unit {
|
||||
myResult = AssertStatement(getConverter().expressionToExpression(statement?.getAssertCondition()),
|
||||
getConverter().expressionToExpression(statement?.getAssertDescription()))
|
||||
}
|
||||
|
||||
public override fun visitBlockStatement(statement: PsiBlockStatement?): Unit {
|
||||
myResult = myConverter.blockToBlock(statement?.getCodeBlock(), true)
|
||||
}
|
||||
|
||||
public override fun visitBreakStatement(statement: PsiBreakStatement?): Unit {
|
||||
if (statement?.getLabelIdentifier() == null) {
|
||||
myResult = BreakStatement(Identifier.EMPTY_IDENTIFIER)
|
||||
}
|
||||
else
|
||||
{
|
||||
myResult = BreakStatement(Converter.identifierToIdentifier(statement?.getLabelIdentifier()))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitContinueStatement(statement: PsiContinueStatement?): Unit {
|
||||
if (statement?.getLabelIdentifier() == null)
|
||||
{
|
||||
myResult = ContinueStatement(Identifier.EMPTY_IDENTIFIER)
|
||||
}
|
||||
else
|
||||
{
|
||||
myResult = ContinueStatement(Converter.identifierToIdentifier(statement?.getLabelIdentifier()))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitDeclarationStatement(statement: PsiDeclarationStatement?): Unit {
|
||||
myResult = DeclarationStatement(getConverter().elementsToElementList(statement?.getDeclaredElements()!!))
|
||||
}
|
||||
|
||||
public override fun visitDoWhileStatement(statement: PsiDoWhileStatement?): Unit {
|
||||
val condition: PsiExpression? = statement?.getCondition()
|
||||
val expression: Expression = (if (condition != null && condition.getType() != null)
|
||||
getConverter().expressionToExpression(condition, condition.getType())
|
||||
else
|
||||
getConverter().expressionToExpression(condition))
|
||||
myResult = DoWhileStatement(expression, getConverter().statementToStatement(statement?.getBody()))
|
||||
}
|
||||
|
||||
public override fun visitExpressionStatement(statement: PsiExpressionStatement?): Unit {
|
||||
myResult = getConverter().expressionToExpression(statement?.getExpression())
|
||||
}
|
||||
|
||||
public override fun visitExpressionListStatement(statement: PsiExpressionListStatement?): Unit {
|
||||
myResult = ExpressionListStatement(getConverter().expressionsToExpressionList(
|
||||
statement?.getExpressionList()?.getExpressions()!!))
|
||||
}
|
||||
|
||||
public override fun visitForStatement(statement: PsiForStatement?): Unit {
|
||||
val initialization: PsiStatement? = statement?.getInitialization()
|
||||
val update: PsiStatement? = statement?.getUpdate()
|
||||
val condition: PsiExpression? = statement?.getCondition()
|
||||
val body: PsiStatement? = statement?.getBody()
|
||||
val firstChild: PsiLocalVariable? = (if (initialization != null && (initialization.getFirstChild() is PsiLocalVariable))
|
||||
(initialization.getFirstChild() as PsiLocalVariable)
|
||||
else
|
||||
null)
|
||||
var bodyWriteCount: Int = countWritingAccesses(firstChild, body)
|
||||
var conditionWriteCount: Int = countWritingAccesses(firstChild, condition)
|
||||
var updateWriteCount: Int = countWritingAccesses(firstChild, update)
|
||||
val onceWritableIterator: Boolean = updateWriteCount == 1 && bodyWriteCount + conditionWriteCount == 0
|
||||
val operationTokenType: IElementType? = (if (condition is PsiBinaryExpression)
|
||||
condition.getOperationTokenType()
|
||||
else
|
||||
null)
|
||||
if (initialization is PsiDeclarationStatement && initialization.getFirstChild() == initialization.getLastChild() &&
|
||||
condition != null && update != null && update.getChildren().size == 1 &&
|
||||
(isPlusPlusExpression(update.getChildren()[0])) && (operationTokenType == JavaTokenType.LT || operationTokenType == JavaTokenType.LE) &&
|
||||
initialization.getFirstChild() != null && (initialization.getFirstChild() is PsiLocalVariable) &&
|
||||
firstChild != null && firstChild.getNameIdentifier() != null && onceWritableIterator) {
|
||||
val end: Expression = getConverter().expressionToExpression((condition as PsiBinaryExpression).getROperand())
|
||||
val endExpression: Expression = (if (operationTokenType == JavaTokenType.LT)
|
||||
BinaryExpression(end, Identifier("1"), "-")
|
||||
else
|
||||
end)
|
||||
myResult = ForeachWithRangeStatement(Identifier(firstChild.getName()!!),
|
||||
getConverter().expressionToExpression(firstChild.getInitializer()),
|
||||
endExpression,
|
||||
getConverter().statementToStatement(body))
|
||||
}
|
||||
else {
|
||||
var forStatements = ArrayList<Element>()
|
||||
forStatements.add(getConverter().statementToStatement(initialization))
|
||||
forStatements.add(WhileStatement(
|
||||
if (condition == null)
|
||||
LiteralExpression("true")
|
||||
else
|
||||
getConverter().expressionToExpression(condition),
|
||||
Block(arrayListOf(getConverter().statementToStatement(body),
|
||||
Block(arrayListOf(getConverter().statementToStatement(update)), false)), false)))
|
||||
myResult = Block(forStatements, false)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun visitForeachStatement(statement: PsiForeachStatement?): Unit {
|
||||
val iterator = {
|
||||
val iteratorExpr = getConverter().expressionToExpression(statement?.getIteratedValue())
|
||||
if (iteratorExpr.isNullable())
|
||||
BangBangExpression(iteratorExpr)
|
||||
else
|
||||
iteratorExpr
|
||||
}()
|
||||
myResult = ForeachStatement(getConverter().parameterToParameter(statement?.getIterationParameter()!!),
|
||||
iterator,
|
||||
getConverter().statementToStatement(statement?.getBody()))
|
||||
}
|
||||
|
||||
public override fun visitIfStatement(statement: PsiIfStatement?): Unit {
|
||||
val condition: PsiExpression? = statement?.getCondition()
|
||||
val expression: Expression = getConverter().expressionToExpression(condition, PsiType.BOOLEAN)
|
||||
myResult = IfStatement(expression,
|
||||
getConverter().statementToStatement(statement?.getThenBranch()),
|
||||
getConverter().statementToStatement(statement?.getElseBranch()))
|
||||
}
|
||||
|
||||
public override fun visitLabeledStatement(statement: PsiLabeledStatement?): Unit {
|
||||
myResult = LabelStatement(Converter.identifierToIdentifier(statement?.getLabelIdentifier()),
|
||||
getConverter().statementToStatement(statement?.getStatement()))
|
||||
}
|
||||
|
||||
public override fun visitSwitchLabelStatement(statement: PsiSwitchLabelStatement?): Unit {
|
||||
myResult = (if (statement?.isDefaultCase()!!)
|
||||
DefaultSwitchLabelStatement()
|
||||
else
|
||||
SwitchLabelStatement(getConverter().expressionToExpression(statement?.getCaseValue())))
|
||||
}
|
||||
|
||||
public override fun visitSwitchStatement(statement: PsiSwitchStatement?): Unit {
|
||||
myResult = SwitchContainer(getConverter().expressionToExpression(statement?.getExpression()),
|
||||
switchBodyToCases(statement?.getBody()))
|
||||
}
|
||||
|
||||
private open fun switchBodyToCases(body: PsiCodeBlock?): List<CaseContainer> {
|
||||
val cases: List<List<PsiElement>> = splitToCases(body)
|
||||
val allSwitchStatements = ArrayList<PsiElement>()
|
||||
if (body != null) {
|
||||
// TODO Arrays.asList()
|
||||
for(s in body.getStatements()) allSwitchStatements.add(s)
|
||||
}
|
||||
val result = ArrayList<CaseContainer>()
|
||||
var pendingLabels = ArrayList<Element>()
|
||||
var i: Int = 0
|
||||
var hasDefaultCase: Boolean = false
|
||||
for (ls in cases) {
|
||||
// TODO assert {(ls?.size()).sure() > 0}
|
||||
if (ls.size() > 0) {
|
||||
var label = ls[0]
|
||||
hasDefaultCase = hasDefaultCase || (label as PsiSwitchLabelStatement).isDefaultCase()
|
||||
// TODO assert {(label is PsiSwitchLabelStatement?)}
|
||||
// TODO assert("not a right index") {allSwitchStatements?.get(i) == label}
|
||||
if (ls.size() > 1) {
|
||||
pendingLabels.add(getConverter().statementToStatement(label))
|
||||
val slice: List<PsiElement> = ls.subList(1, (ls.size()))
|
||||
if (!containsBreak(slice)) {
|
||||
val statements = ArrayList(getConverter().statementsToStatementList(slice))
|
||||
statements.addAll(getConverter().statementsToStatementList(getAllToNextBreak(allSwitchStatements, i + ls.size())))
|
||||
result.add(CaseContainer(pendingLabels, statements))
|
||||
pendingLabels = ArrayList()
|
||||
}
|
||||
else {
|
||||
result.add(CaseContainer(pendingLabels, getConverter().statementsToStatementList(slice)))
|
||||
pendingLabels = ArrayList()
|
||||
}
|
||||
}
|
||||
else {
|
||||
pendingLabels.add(getConverter().statementToStatement(label))
|
||||
}
|
||||
i += ls.size()
|
||||
}
|
||||
}
|
||||
if (!hasDefaultCase)
|
||||
result.add(CaseContainer(listOf(DefaultSwitchLabelStatement()), ArrayList()))
|
||||
return result
|
||||
}
|
||||
|
||||
public override fun visitSynchronizedStatement(statement: PsiSynchronizedStatement?): Unit {
|
||||
myResult = SynchronizedStatement(getConverter().expressionToExpression(statement?.getLockExpression()),
|
||||
getConverter().blockToBlock(statement?.getBody()))
|
||||
}
|
||||
|
||||
public override fun visitThrowStatement(statement: PsiThrowStatement?): Unit {
|
||||
myResult = ThrowStatement(getConverter().expressionToExpression(statement?.getException()))
|
||||
}
|
||||
|
||||
public override fun visitTryStatement(statement: PsiTryStatement?): Unit {
|
||||
val catches = ArrayList<CatchStatement>()
|
||||
val catchBlocks = statement?.getCatchBlocks()!!
|
||||
val catchBlockParameters = statement?.getCatchBlockParameters()!!
|
||||
for (i in 0..catchBlocks.size - 1) {
|
||||
catches.add(CatchStatement(getConverter().parameterToParameter(catchBlockParameters[i], true),
|
||||
getConverter().blockToBlock(catchBlocks[i], true)))
|
||||
}
|
||||
myResult = TryStatement(getConverter().blockToBlock(statement?.getTryBlock(), true),
|
||||
catches, getConverter().blockToBlock(statement?.getFinallyBlock(), true))
|
||||
}
|
||||
|
||||
public override fun visitWhileStatement(statement: PsiWhileStatement?): Unit {
|
||||
var condition: PsiExpression? = statement?.getCondition()
|
||||
val expression: Expression = (if (condition != null && condition?.getType() != null)
|
||||
this.getConverter().expressionToExpression(condition, condition?.getType())
|
||||
else
|
||||
getConverter().expressionToExpression(condition))
|
||||
myResult = WhileStatement(expression, getConverter().statementToStatement(statement?.getBody()))
|
||||
}
|
||||
|
||||
public override fun visitReturnStatement(statement: PsiReturnStatement?): Unit {
|
||||
val returnValue: PsiExpression? = statement?.getReturnValue()
|
||||
val methodReturnType: PsiType? = getConverter().methodReturnType
|
||||
val expression: Expression = (if (returnValue != null && methodReturnType != null)
|
||||
this.getConverter().expressionToExpression(returnValue, methodReturnType)
|
||||
else
|
||||
getConverter().expressionToExpression(returnValue))
|
||||
myResult = ReturnStatement(expression)
|
||||
}
|
||||
|
||||
class object {
|
||||
private open fun isPlusPlusExpression(psiElement: PsiElement): Boolean {
|
||||
return (psiElement is PsiPostfixExpression && psiElement.getOperationTokenType() == JavaTokenType.PLUSPLUS) ||
|
||||
(psiElement is PsiPrefixExpression && psiElement.getOperationTokenType() == JavaTokenType.PLUSPLUS)
|
||||
}
|
||||
|
||||
private fun containsBreak(slice: List<PsiElement?>) = slice.any { it is PsiBreakStatement }
|
||||
|
||||
private open fun getAllToNextBreak(allStatements: List<PsiElement>, start: Int): List<PsiElement> {
|
||||
val result = ArrayList<PsiElement>()
|
||||
for (i in start..allStatements.size() - 1) {
|
||||
val s = allStatements.get(i)
|
||||
if (s is PsiBreakStatement || s is PsiReturnStatement) {
|
||||
return result
|
||||
}
|
||||
|
||||
if (!(s is PsiSwitchLabelStatement)) {
|
||||
result.add(s)
|
||||
}
|
||||
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private open fun splitToCases(body: PsiCodeBlock?): List<List<PsiElement>> {
|
||||
val cases = ArrayList<List<PsiElement>>()
|
||||
var currentCaseStatements = ArrayList<PsiElement>()
|
||||
var isFirst: Boolean = true
|
||||
if (body != null) {
|
||||
for (s in body.getChildren()) {
|
||||
if (s !is PsiStatement && s !is PsiComment) continue
|
||||
if (s is PsiSwitchLabelStatement) {
|
||||
if (isFirst) {
|
||||
isFirst = false
|
||||
}
|
||||
else {
|
||||
cases.add(currentCaseStatements)
|
||||
currentCaseStatements = ArrayList()
|
||||
}
|
||||
}
|
||||
|
||||
currentCaseStatements.add(s)
|
||||
}
|
||||
cases.add(currentCaseStatements)
|
||||
}
|
||||
|
||||
return cases
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import java.util.HashSet
|
||||
|
||||
public open class SuperVisitor(): JavaRecursiveElementVisitor() {
|
||||
public val resolvedSuperCallParameters: HashSet<PsiExpressionList> = hashSet()
|
||||
|
||||
public override fun visitMethodCallExpression(expression: PsiMethodCallExpression?): Unit {
|
||||
if (expression != null && isSuper(expression.getMethodExpression())) {
|
||||
resolvedSuperCallParameters.add(expression.getArgumentList())
|
||||
}
|
||||
}
|
||||
class object {
|
||||
open fun isSuper(r: PsiReference): Boolean {
|
||||
if (r.getCanonicalText().equals("super")) {
|
||||
val baseConstructor: PsiElement? = r.resolve()
|
||||
if (baseConstructor != null && baseConstructor is PsiMethod && baseConstructor.isConstructor()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import java.util.LinkedHashSet
|
||||
|
||||
public open class ThisVisitor(): JavaRecursiveElementVisitor() {
|
||||
private val myResolvedConstructors = LinkedHashSet<PsiMethod>()
|
||||
|
||||
public override fun visitReferenceExpression(expression: PsiReferenceExpression?): Unit {
|
||||
for (r : PsiReference? in expression?.getReferences()!!) {
|
||||
if (r?.getCanonicalText() == "this") {
|
||||
val res: PsiElement? = r?.resolve()
|
||||
if (res is PsiMethod && res.isConstructor()) {
|
||||
myResolvedConstructors.add(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public open fun getPrimaryConstructor(): PsiMethod? {
|
||||
if (myResolvedConstructors.size() > 0) {
|
||||
val first: PsiMethod = myResolvedConstructors.iterator().next()
|
||||
for (m in myResolvedConstructors)
|
||||
if (m.hashCode() != first.hashCode()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return first
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package org.jetbrains.jet.j2k.visitors
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.PsiClassReferenceType
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import org.jetbrains.jet.j2k.J2KConverterFlags
|
||||
import org.jetbrains.jet.j2k.ast.*
|
||||
import org.jetbrains.jet.j2k.ast.types.*
|
||||
import java.util.LinkedList
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import java.util.ArrayList
|
||||
|
||||
public open class TypeVisitor(private val myConverter : Converter) : PsiTypeVisitor<Type>() {
|
||||
private var myResult : Type = EmptyType()
|
||||
public open fun getResult() : Type {
|
||||
return myResult
|
||||
}
|
||||
|
||||
public override fun visitPrimitiveType(primitiveType: PsiPrimitiveType?) : Type {
|
||||
val name : String = primitiveType?.getCanonicalText()!!
|
||||
if (name == "void") {
|
||||
myResult = PrimitiveType(Identifier("Unit"))
|
||||
}
|
||||
else if (Node.PRIMITIVE_TYPES.contains(name)) {
|
||||
myResult = PrimitiveType(Identifier(StringUtil.capitalize(name)))
|
||||
}
|
||||
else {
|
||||
myResult = PrimitiveType(Identifier(name))
|
||||
}
|
||||
return myResult
|
||||
}
|
||||
|
||||
public override fun visitArrayType(arrayType: PsiArrayType?) : Type {
|
||||
if (myResult is EmptyType) {
|
||||
myResult = ArrayType(myConverter.typeToType(arrayType?.getComponentType()), true)
|
||||
}
|
||||
|
||||
return myResult
|
||||
}
|
||||
|
||||
public override fun visitClassType(classType : PsiClassType?) : Type {
|
||||
if (classType == null) return myResult
|
||||
val identifier : Identifier = constructClassTypeIdentifier(classType)
|
||||
val resolvedClassTypeParams : List<Type> = createRawTypesForResolvedReference(classType)
|
||||
if (classType.getParameterCount() == 0 && resolvedClassTypeParams.size() > 0) {
|
||||
val starParamList : ArrayList<Type> = ArrayList<Type>()
|
||||
if (resolvedClassTypeParams.size() == 1) {
|
||||
if ((resolvedClassTypeParams.get(0) as ClassType).`type`.name == "Any") {
|
||||
starParamList.add(StarProjectionType())
|
||||
myResult = ClassType(identifier, starParamList, true)
|
||||
}
|
||||
else {
|
||||
myResult = ClassType(identifier, resolvedClassTypeParams, true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
myResult = ClassType(identifier, resolvedClassTypeParams, true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
myResult = ClassType(identifier, myConverter.typesToTypeList(classType.getParameters()), true)
|
||||
}
|
||||
return myResult
|
||||
}
|
||||
|
||||
private fun constructClassTypeIdentifier(classType : PsiClassType) : Identifier {
|
||||
val psiClass : PsiClass? = classType.resolve()
|
||||
if (psiClass != null) {
|
||||
val qualifiedName: String? = psiClass.getQualifiedName()
|
||||
if (qualifiedName != null) {
|
||||
if (!qualifiedName.equals("java.lang.Object") && myConverter.hasFlag(J2KConverterFlags.FULLY_QUALIFIED_TYPE_NAMES)) {
|
||||
return Identifier(qualifiedName)
|
||||
}
|
||||
|
||||
if (qualifiedName.equals(CommonClassNames.JAVA_LANG_ITERABLE)) {
|
||||
return Identifier(CommonClassNames.JAVA_LANG_ITERABLE)
|
||||
}
|
||||
|
||||
if (qualifiedName.equals(CommonClassNames.JAVA_UTIL_ITERATOR)) {
|
||||
return Identifier(CommonClassNames.JAVA_UTIL_ITERATOR)
|
||||
}
|
||||
|
||||
if (qualifiedName.equals(CommonClassNames.JAVA_UTIL_LIST)) {
|
||||
return Identifier("MutableList")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val classTypeName = createQualifiedName(classType)
|
||||
if (classTypeName.isEmpty()) {
|
||||
return Identifier(getClassTypeName(classType))
|
||||
}
|
||||
|
||||
return Identifier(classTypeName)
|
||||
}
|
||||
|
||||
private fun createRawTypesForResolvedReference(classType : PsiClassType) : List<Type> {
|
||||
val typeParams = LinkedList<Type>()
|
||||
if (classType is PsiClassReferenceType) {
|
||||
val reference : PsiJavaCodeReferenceElement? = (classType as PsiClassReferenceType).getReference()
|
||||
val resolve : PsiElement? = reference?.resolve()
|
||||
if (resolve is PsiClass) {
|
||||
for (p : PsiTypeParameter? in (resolve as PsiClass).getTypeParameters()) {
|
||||
val superTypes = p!!.getSuperTypes()
|
||||
val boundType : Type = (if (superTypes.size > 0)
|
||||
ClassType(Identifier(getClassTypeName(superTypes[0])),
|
||||
myConverter.typesToTypeList(superTypes[0].getParameters()),
|
||||
true)
|
||||
else
|
||||
StarProjectionType())
|
||||
typeParams.add(boundType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return typeParams
|
||||
}
|
||||
|
||||
public override fun visitWildcardType(wildcardType : PsiWildcardType?) : Type {
|
||||
if (wildcardType!!.isExtends()) {
|
||||
myResult = OutProjectionType(myConverter.typeToType(wildcardType.getExtendsBound()))
|
||||
}
|
||||
else
|
||||
if (wildcardType.isSuper()) {
|
||||
myResult = InProjectionType(myConverter.typeToType(wildcardType.getSuperBound()))
|
||||
}
|
||||
else {
|
||||
myResult = StarProjectionType()
|
||||
}
|
||||
return myResult
|
||||
}
|
||||
|
||||
public override fun visitEllipsisType(ellipsisType : PsiEllipsisType?) : Type {
|
||||
myResult = VarArg(myConverter.typeToType(ellipsisType?.getComponentType()))
|
||||
return myResult
|
||||
}
|
||||
|
||||
class object {
|
||||
private fun createQualifiedName(classType : PsiClassType) : String {
|
||||
if (classType is PsiClassReferenceType)
|
||||
{
|
||||
val reference : PsiJavaCodeReferenceElement? = (classType as PsiClassReferenceType).getReference()
|
||||
if (reference != null && reference.isQualified()) {
|
||||
var result : String = Identifier(reference.getReferenceName()!!).toKotlin()
|
||||
var qualifier : PsiElement? = reference.getQualifier()
|
||||
while (qualifier != null)
|
||||
{
|
||||
val p : PsiJavaCodeReferenceElement = (qualifier as PsiJavaCodeReferenceElement)
|
||||
result = Identifier(p.getReferenceName()!!).toKotlin() + "." + result
|
||||
qualifier = p.getQualifier()
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun getClassTypeName(classType : PsiClassType) : String {
|
||||
var canonicalTypeStr : String? = classType.getCanonicalText()
|
||||
return when(canonicalTypeStr) {
|
||||
CommonClassNames.JAVA_LANG_OBJECT -> "Any"
|
||||
CommonClassNames.JAVA_LANG_BYTE -> "Byte"
|
||||
CommonClassNames.JAVA_LANG_CHARACTER -> "Char"
|
||||
CommonClassNames.JAVA_LANG_DOUBLE -> "Double"
|
||||
CommonClassNames.JAVA_LANG_FLOAT -> "Float"
|
||||
CommonClassNames.JAVA_LANG_INTEGER -> "Int"
|
||||
CommonClassNames.JAVA_LANG_LONG -> "Long"
|
||||
CommonClassNames.JAVA_LANG_SHORT -> "Short"
|
||||
CommonClassNames.JAVA_LANG_BOOLEAN -> "Boolean"
|
||||
|
||||
else -> (if (classType.getClassName() != null)
|
||||
classType.getClassName()!!
|
||||
else
|
||||
classType.getCanonicalText())!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.core.JavaCoreProjectEnvironment;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class StandaloneJavaToKotlinConverterTest extends TestCase {
|
||||
private final String myDataPath;
|
||||
private final String myName;
|
||||
@NotNull
|
||||
private final static JavaCoreProjectEnvironment myJavaCoreEnvironment = JavaToKotlinTranslator.setUpJavaCoreEnvironment();
|
||||
|
||||
public StandaloneJavaToKotlinConverterTest(String dataPath, String name) {
|
||||
myDataPath = dataPath;
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
Converter converter = new Converter();
|
||||
String javaPath = "tests/testData/" + getTestFilePath();
|
||||
String kotlinPath = javaPath.replace(".jav", ".kt");
|
||||
|
||||
final File kotlinFile = new File(kotlinPath);
|
||||
if (!kotlinFile.exists()) {
|
||||
FileUtil.writeToFile(kotlinFile, "");
|
||||
}
|
||||
final String expected = StringUtil.convertLineSeparators(FileUtil.loadFile(kotlinFile));
|
||||
final File javaFile = new File(javaPath);
|
||||
final String javaCode = FileUtil.loadFile(javaFile);
|
||||
|
||||
String actual = "";
|
||||
String parentFileName = javaFile.getParentFile().getName();
|
||||
if (parentFileName.equals("expression")) {
|
||||
actual = expressionToKotlin(converter, javaCode);
|
||||
}
|
||||
else if (parentFileName.equals("statement")) {
|
||||
actual = statementToKotlin(converter, javaCode);
|
||||
}
|
||||
else if (parentFileName.equals("method")) {
|
||||
actual = methodToKotlin(converter, javaCode);
|
||||
}
|
||||
else if (parentFileName.equals("class")) {
|
||||
actual = fileToKotlin(converter, javaCode);
|
||||
}
|
||||
else if (parentFileName.equals("file")) {
|
||||
actual = fileToKotlin(converter, javaCode);
|
||||
}
|
||||
else if (parentFileName.equals("comp")) actual = fileToFileWithCompatibilityImport(javaCode);
|
||||
|
||||
actual = StringUtil.convertLineSeparators(actual);
|
||||
|
||||
assert !actual.isEmpty() : "Specify what is it: file, class, method, statement or expression: " + javaPath + " parent: " + parentFileName;
|
||||
|
||||
final File tmp = new File(kotlinPath + ".tmp");
|
||||
if (!expected.equals(actual)) FileUtil.writeToFile(tmp, actual);
|
||||
if (expected.equals(actual) && tmp.exists()) //noinspection ResultOfMethodCallIgnored
|
||||
{
|
||||
tmp.delete();
|
||||
}
|
||||
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
String getTestFilePath() {
|
||||
return myDataPath + "/" + myName + ".jav";
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test_" + myName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite();
|
||||
// suite.addTest(new StandaloneJavaToKotlinConverterTest("ast/class/file", "kt-639"));
|
||||
suite.addTest(TestCaseBuilder.suiteForDirectory("tests/testData", "/ast", new TestCaseBuilder.NamedTestFactory() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Test createTest(@NotNull String dataPath, @NotNull String name) {
|
||||
return new StandaloneJavaToKotlinConverterTest(dataPath, name);
|
||||
}
|
||||
}));
|
||||
return suite;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String fileToFileWithCompatibilityImport(@NotNull String text) {
|
||||
return JavaToKotlinTranslator.generateKotlinCodeWithCompatibilityImport(text);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String fileToKotlin(Converter converter, @NotNull String text) {
|
||||
return generateKotlinCode(converter, JavaToKotlinTranslator.createFile(myJavaCoreEnvironment, text));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String generateKotlinCode(@NotNull Converter converter, @Nullable PsiFile file) {
|
||||
if (file != null && file instanceof PsiJavaFile) {
|
||||
JavaToKotlinTranslator.setClassIdentifiers(converter, file);
|
||||
return prettify(converter.elementToKotlin(file));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String methodToKotlin(Converter converter, String text) throws IOException {
|
||||
String result = fileToKotlin(converter, "final class C {" + text + "}")
|
||||
.replaceAll("class C\\(\\) \\{", "");
|
||||
result = result.substring(0, result.lastIndexOf("}"));
|
||||
return prettify(result);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String statementToKotlin(Converter converter, String text) throws Exception {
|
||||
String result = methodToKotlin(converter, "void main() {" + text + "}");
|
||||
int pos = result.lastIndexOf("}");
|
||||
result = result.substring(0, pos).replaceFirst("fun main\\(\\) : Unit \\{", "");
|
||||
return prettify(result);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String expressionToKotlin(Converter converter, String code) throws Exception {
|
||||
String result = statementToKotlin(converter, "Object o =" + code + "}");
|
||||
result = result.replaceFirst("var o : Any\\? =", "");
|
||||
return prettify(result);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String prettify(@Nullable String code) {
|
||||
if (code == null) {
|
||||
return "";
|
||||
}
|
||||
return code
|
||||
.trim()
|
||||
.replaceAll("\r\n", "\n")
|
||||
.replaceAll(" \n", "\n")
|
||||
.replaceAll("\n ", "\n")
|
||||
.replaceAll("\n+", "\n")
|
||||
.replaceAll(" +", " ")
|
||||
.trim()
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.openapi.application.PathManager;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
abstract class TestCaseBuilder {
|
||||
@NotNull
|
||||
private static final FilenameFilter emptyFilter = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File file, String name) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
public static String getTestDataPathBase() {
|
||||
return "testData";
|
||||
}
|
||||
|
||||
public static String getHomeDirectory() {
|
||||
return new File(PathManager.getResourceRoot(TestCaseBuilder.class, "/org/jetbrains/jet/TestCaseBuilder.class")).getParentFile().getParentFile().getParent();
|
||||
}
|
||||
|
||||
public interface NamedTestFactory {
|
||||
@NotNull
|
||||
Test createTest(@NotNull String dataPath, @NotNull String name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static TestSuite suiteForDirectory(String baseDataDir, @NotNull final String dataPath, @NotNull NamedTestFactory factory) {
|
||||
return suiteForDirectory(baseDataDir, dataPath, true, emptyFilter, factory);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TestSuite suiteForDirectory(String baseDataDir, @NotNull final String dataPath, boolean recursive, @NotNull final FilenameFilter filter, @NotNull NamedTestFactory factory) {
|
||||
TestSuite suite = new TestSuite(dataPath);
|
||||
final String extensionJava = ".jav";
|
||||
|
||||
final FilenameFilter extensionFilter = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, @NotNull String name) {
|
||||
return name.endsWith(extensionJava);
|
||||
}
|
||||
};
|
||||
FilenameFilter resultFilter;
|
||||
if (filter != emptyFilter) {
|
||||
resultFilter = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File file, String s) {
|
||||
return extensionFilter.accept(file, s) && filter.accept(file, s);
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
resultFilter = extensionFilter;
|
||||
}
|
||||
File dir = new File(baseDataDir + dataPath);
|
||||
FileFilter dirFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(@NotNull File pathname) {
|
||||
return pathname.isDirectory();
|
||||
}
|
||||
};
|
||||
if (recursive) {
|
||||
File[] files = dir.listFiles(dirFilter);
|
||||
assert files != null : dir;
|
||||
List<File> subdirs = Arrays.asList(files);
|
||||
Collections.sort(subdirs);
|
||||
for (File subdir : subdirs) {
|
||||
suite.addTest(suiteForDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, filter, factory));
|
||||
}
|
||||
}
|
||||
List<File> files = Arrays.asList(dir.listFiles(resultFilter));
|
||||
Collections.sort(files);
|
||||
for (File file : files) {
|
||||
String fileName = file.getName();
|
||||
assert fileName != null;
|
||||
suite.addTest(factory.createTest(dataPath, fileName.substring(0, fileName.length() - extensionJava.length())));
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
int[] a = new int[10]
|
||||
@@ -0,0 +1 @@
|
||||
var a : IntArray? = IntArray(10)
|
||||
@@ -0,0 +1 @@
|
||||
Object[] a = new Object[10]
|
||||
@@ -0,0 +1 @@
|
||||
var a : Array<Any?>? = arrayOfNulls<Any?>(10)
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var d2 : Array<IntArray?>? = Array<IntArray?>(5)
|
||||
var d2 : Array<IntArray?>? = arrayOfNulls<IntArray?>(5)
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var d3 : Array<Array<IntArray?>?>? = Array<Array<IntArray?>?>(5, {Array<IntArray?>(5)})
|
||||
var d3 : Array<Array<IntArray?>?>? = Array<Array<IntArray?>?>(5, {arrayOfNulls<IntArray?>(5)})
|
||||
@@ -1 +1 @@
|
||||
var ss : Array<Array<String?>?>? = Array<Array<String?>?>(5, {Array<String?>(5)})
|
||||
var ss : Array<Array<String?>?>? = Array<Array<String?>?>(5, {arrayOfNulls<String?>(5)})
|
||||
@@ -1 +1 @@
|
||||
var sss : Array<Array<Array<String?>?>?>? = Array<Array<Array<String?>?>?>(5, {Array<Array<String?>?>(5, {Array<String?>(5)})})
|
||||
var sss : Array<Array<Array<String?>?>?>? = Array<Array<Array<String?>?>?>(5, {Array<Array<String?>?>(5, {arrayOfNulls<String?>(5)})})
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.BitSet;
|
||||
|
||||
class Foo {
|
||||
void foo(BitSet o) {
|
||||
BitSet o2 = o;
|
||||
int foo = 0;
|
||||
foo = o2.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.util.BitSet
|
||||
open class Foo() {
|
||||
open fun foo(o : BitSet?) : Unit {
|
||||
var o2 : BitSet? = o
|
||||
var foo : Int = 0
|
||||
foo = o2?.size()!!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class Boxing {
|
||||
void test() {
|
||||
Integer i = 0;
|
||||
Number n = 0.0f;
|
||||
i = 1;
|
||||
int j = i;
|
||||
Integer k = i+2;
|
||||
i = null;
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import java.util.ArrayList
|
||||
open class Boxing() {
|
||||
open fun test() : Unit {
|
||||
var i : Int? = 0
|
||||
var n : Number? = 0.0.toFloat()
|
||||
i = 1
|
||||
var j : Int = i!!
|
||||
var k : Int? = i!! + 2
|
||||
i = null
|
||||
j = i!!
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package demo;
|
||||
class Test {
|
||||
void test() {
|
||||
Integer i = Integer.valueOf(100);
|
||||
Short s = Short.valueOf(100);
|
||||
short s = 3;
|
||||
Short ss = Short.valueOf(s);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package demo
|
||||
open class Test() {
|
||||
open fun test() : Unit {
|
||||
var i : Int? = Integer.valueOf(100)
|
||||
var s : Short? = Short.valueOf(100)
|
||||
var s : Short = 3
|
||||
var ss : Short? = java.lang.Short.valueOf(s)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package test;
|
||||
|
||||
public class Short {
|
||||
public static Short valueOf(String value) {return new Short();}
|
||||
}
|
||||
|
||||
class Test {
|
||||
public static void test() {
|
||||
Short.valueOf("1");
|
||||
test.Short.valueOf("1");
|
||||
java.lang.Short.valueOf("1");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
public open class Short() {
|
||||
class object {
|
||||
public open fun valueOf(value : String?) : Short? {
|
||||
return Short()
|
||||
}
|
||||
}
|
||||
}
|
||||
open class Test() {
|
||||
class object {
|
||||
public open fun test() : Unit {
|
||||
test.Short.valueOf("1")
|
||||
test.Short.valueOf("1")
|
||||
java.lang.Short.valueOf("1")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
public open class MyClass() {
|
||||
private open fun init(arg1 : Int, arg2 : Int, arg3 : Int) : Unit {
|
||||
private fun init(arg1 : Int, arg2 : Int, arg3 : Int) : Unit {
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ return _firstName
|
||||
public open fun getLastName() : String? {
|
||||
return _lastName
|
||||
}
|
||||
private open fun doSmthBefore() : Unit {
|
||||
private fun doSmthBefore() : Unit {
|
||||
}
|
||||
private open fun doSmthAfter() : Unit {
|
||||
private fun doSmthAfter() : Unit {
|
||||
}
|
||||
{
|
||||
doSmthBefore()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
public open class Identifier<T>(_myName : T?, _myHasDollar : Boolean) {
|
||||
private val myName : T? = null
|
||||
private val myName : T?
|
||||
private var myHasDollar : Boolean = false
|
||||
private var myNullable : Boolean = true
|
||||
public open fun getName() : T? {
|
||||
@@ -30,8 +30,8 @@ public open class User() {
|
||||
class object {
|
||||
public open fun main() : Unit {
|
||||
var i1 : Identifier<*>? = Identifier.init<String?>("name", false, true)
|
||||
var i2 : Identifier<Any?>? = Identifier.init<String?>("name", false)
|
||||
var i3 : Identifier<Any?>? = Identifier.init<String?>("name")
|
||||
var i2 : Identifier<*>? = Identifier.init<String?>("name", false)
|
||||
var i3 : Identifier<*>? = Identifier.init<String?>("name")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
public open class Identifier(_myName : String?, _myHasDollar : Boolean) {
|
||||
private val myName : String? = null
|
||||
private val myName : String?
|
||||
private var myHasDollar : Boolean = false
|
||||
private var myNullable : Boolean = true
|
||||
public open fun getName() : String? {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
open class C() {
|
||||
val f : Foo? = Foo(1, 2)
|
||||
val f : Foo = Foo(1, 2)
|
||||
}
|
||||
@@ -4,6 +4,6 @@ open class Test() {
|
||||
open fun test() : Unit {
|
||||
var i : Int? = 10
|
||||
var j : Int? = 10
|
||||
System.out?.println(i + j)
|
||||
System.out?.println(i!! + j!!)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
for (init(); ; update()) body();
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
init()
|
||||
while (true)
|
||||
{
|
||||
body()
|
||||
{
|
||||
update()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
for (; condition() ; update()) body();
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
while (condition())
|
||||
{
|
||||
body()
|
||||
{
|
||||
update()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
for (init(); condition(); ) body();
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
init()
|
||||
while (condition())
|
||||
{
|
||||
body()
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
(c.getType().getName() is String)
|
||||
c.getType().getName() is String
|
||||
@@ -1 +1 @@
|
||||
(a is String)
|
||||
a is String
|
||||
@@ -0,0 +1,5 @@
|
||||
class Test {
|
||||
public static int foo(String[] args) {
|
||||
return args.length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
open class Test() {
|
||||
class object {
|
||||
public open fun foo(args : Array<String?>?) : Int {
|
||||
return args?.size!!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// This is an end-of-line comment
|
||||
|
||||
/*
|
||||
This is a block comment
|
||||
*/
|
||||
|
||||
|
||||
class C {
|
||||
// This is a class comment
|
||||
|
||||
/**
|
||||
* This is a field doc comment.
|
||||
*/
|
||||
private int i;
|
||||
|
||||
/**
|
||||
* This is a function doc comment.
|
||||
*/
|
||||
public void foo() {
|
||||
/* This is a function comment */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// This is an end-of-line comment
|
||||
/*
|
||||
This is a block comment
|
||||
*/
|
||||
open class C() {
|
||||
// This is a class comment
|
||||
/**
|
||||
* This is a field doc comment.
|
||||
*/
|
||||
private var i : Int = 0
|
||||
/**
|
||||
* This is a function doc comment.
|
||||
*/
|
||||
public open fun foo() : Unit {
|
||||
/* This is a function comment */
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ open fun putInt(i : Int?) : Unit {
|
||||
}
|
||||
open fun test() : Unit {
|
||||
var b : Byte = 10
|
||||
putInt((b).toInt())
|
||||
putInt(b.toInt())
|
||||
var b2 : Byte? = 10
|
||||
putInt((b2).toInt())
|
||||
putInt(b2?.toInt())
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,6 @@ open fun putInt(i : Int) : Unit {
|
||||
}
|
||||
open fun test() : Unit {
|
||||
var b : Byte = 10
|
||||
putInt((b).toInt())
|
||||
putInt(b.toInt())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
public open class Identifier<T>(_myName : T?, _myHasDollar : Boolean) {
|
||||
private val myName : T? = null
|
||||
private val myName : T?
|
||||
private var myHasDollar : Boolean = false
|
||||
private var myNullable : Boolean = true
|
||||
public open fun getName() : T? {
|
||||
@@ -30,9 +30,9 @@ public open class User() {
|
||||
class object {
|
||||
public open fun main(args : Array<String?>?) : Unit {
|
||||
var i1 : Identifier<*>? = Identifier.init<String?>("name", false, true)
|
||||
var i2 : Identifier<Any?>? = Identifier.init<String?>("name", false)
|
||||
var i3 : Identifier<Any?>? = Identifier.init<String?>("name")
|
||||
var i2 : Identifier<*>? = Identifier.init<String?>("name", false)
|
||||
var i3 : Identifier<*>? = Identifier.init<String?>("name")
|
||||
}
|
||||
}
|
||||
}
|
||||
fun main(args : Array<String?>?) = User.main(args)
|
||||
fun main(args : Array<String>) = User.main(args as Array<String?>?)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user