supported two cases for constructor calling
This commit is contained in:
@@ -7,10 +7,7 @@ import org.jetbrains.jet.j2k.ast.*;
|
||||
import org.jetbrains.jet.j2k.ast.Class;
|
||||
import org.jetbrains.jet.j2k.ast.Enum;
|
||||
import org.jetbrains.jet.j2k.ast.Modifier;
|
||||
import org.jetbrains.jet.j2k.visitors.ElementVisitor;
|
||||
import org.jetbrains.jet.j2k.visitors.ExpressionVisitor;
|
||||
import org.jetbrains.jet.j2k.visitors.StatementVisitor;
|
||||
import org.jetbrains.jet.j2k.visitors.TypeVisitor;
|
||||
import org.jetbrains.jet.j2k.visitors.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -40,7 +37,7 @@ public class Converter {
|
||||
}
|
||||
|
||||
public static AnonymousClass anonymousClassToAnonymousClass(PsiAnonymousClass anonymousClass) { // TODO: replace by Block,
|
||||
// use class.getChild() method
|
||||
// use class.getChild() method
|
||||
return new AnonymousClass(
|
||||
classesToClassList(anonymousClass.getAllInnerClasses()),
|
||||
methodsToFunctionList(anonymousClass.getMethods(), true),
|
||||
@@ -121,6 +118,29 @@ public class Converter {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getPrimaryConstructor(PsiClass psiClass) {
|
||||
ThisVisitor tv = new ThisVisitor();
|
||||
psiClass.accept(tv);
|
||||
return tv.getPrimaryConstructor();
|
||||
}
|
||||
|
||||
public static boolean isConstructorPrimary(@Nullable PsiMethod constructor) {
|
||||
if (constructor == null)
|
||||
return false;
|
||||
if (constructor.getParent() instanceof PsiClass) {
|
||||
final PsiClass parent = (PsiClass) constructor.getParent();
|
||||
if (parent.getConstructors().length == 1)
|
||||
return true;
|
||||
else {
|
||||
PsiMethod c = getPrimaryConstructor(parent); // TODO: move up to classToClass() method
|
||||
if (c != null && c.hashCode() == constructor.hashCode())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Function methodToFunction(PsiMethod method, boolean notEmpty) {
|
||||
final IdentifierImpl identifier = new IdentifierImpl(method.getName());
|
||||
@@ -135,11 +155,8 @@ public class Converter {
|
||||
if (method.getParent() instanceof PsiClass && ((PsiClass) method.getParent()).isInterface())
|
||||
modifiers.remove(Modifier.ABSTRACT);
|
||||
|
||||
|
||||
if (method.isConstructor()) {
|
||||
boolean isPrimary = false;
|
||||
if (method.getParent() instanceof PsiClass && ((PsiClass) method.getParent()).getConstructors().length == 1)
|
||||
isPrimary = true;
|
||||
if (method.isConstructor()) { // TODO: simplify
|
||||
boolean isPrimary = isConstructorPrimary(method);
|
||||
|
||||
return new Constructor(
|
||||
identifier,
|
||||
|
||||
@@ -11,6 +11,11 @@ import java.util.List;
|
||||
*/
|
||||
public class Block extends Statement {
|
||||
public final static Block EMPTY_BLOCK = new Block();
|
||||
|
||||
public List<Statement> getStatements() {
|
||||
return myStatements;
|
||||
}
|
||||
|
||||
private List<Statement> myStatements = new LinkedList<Statement>();
|
||||
private boolean myNotEmpty = false;
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public class CallChainExpression extends Expression {
|
||||
private Expression myExpression;
|
||||
private IdentifierImpl myIdentifier;
|
||||
private Expression myIdentifier;
|
||||
|
||||
public CallChainExpression(Expression expression, IdentifierImpl identifier) {
|
||||
public CallChainExpression(Expression expression, Expression identifier) {
|
||||
myExpression = expression;
|
||||
myIdentifier = identifier;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.j2k.util.AstUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -83,6 +84,30 @@ public class Class extends Member {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
List<Function> secondaryConstructorsAsStaticInitFunction() {
|
||||
final LinkedList<Function> result = new LinkedList<Function>();
|
||||
for (Function m : myMethods)
|
||||
if (m.getKind() == Kind.CONSTRUCTOR && !((Constructor) m).isPrimary()) {
|
||||
Set<String> modifiers = new HashSet<String>(m.myModifiers);
|
||||
modifiers.add(Modifier.STATIC);
|
||||
|
||||
final List<Statement> statements = m.getBlock().getStatements();
|
||||
statements.add(new ReturnStatement(new IdentifierImpl("__"))); // TODO: move to one place, find other __ usages
|
||||
final Block block = new Block(statements);
|
||||
|
||||
result.add(new Function(
|
||||
new IdentifierImpl("init"),
|
||||
modifiers,
|
||||
new ClassType(myName, false),
|
||||
m.getTypeParameters(),
|
||||
m.getParams(),
|
||||
block
|
||||
));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String typeParametersToKotlin() {
|
||||
return myTypeParameters.size() > 0 ? "<" + AstUtil.joinNodes(myTypeParameters, COMMA_WITH_SPACE) + ">" : EMPTY;
|
||||
}
|
||||
@@ -124,9 +149,9 @@ public class Class extends Member {
|
||||
|
||||
String bodyToKotlin() {
|
||||
return SPACE + "{" + N +
|
||||
classObjectToKotlin() + N +
|
||||
AstUtil.joinNodes(getNonStatic(myFields), N) + N +
|
||||
primaryConstructorBodyToKotlin() + N +
|
||||
classObjectToKotlin() + N +
|
||||
AstUtil.joinNodes(getNonStatic(methodsExceptConstructors()), N) + N +
|
||||
AstUtil.joinNodes(getNonStatic(myInnerClasses), N) + N +
|
||||
"}";
|
||||
@@ -149,8 +174,9 @@ public class Class extends Member {
|
||||
}
|
||||
|
||||
private String classObjectToKotlin() {
|
||||
final List<Member> staticMethods = new LinkedList<Member>(secondaryConstructorsAsStaticInitFunction());
|
||||
staticMethods.addAll(getStatic(methodsExceptConstructors()));
|
||||
final List<Member> staticFields = getStatic(myFields);
|
||||
final List<Member> staticMethods = getStatic(methodsExceptConstructors());
|
||||
final List<Member> staticInnerClasses = getStatic(myInnerClasses);
|
||||
if (staticFields.size() + staticMethods.size() + staticInnerClasses.size() > 0) {
|
||||
return "class" + SPACE + "object" + SPACE + "{" + N +
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jetbrains.jet.j2k.ast;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.j2k.util.AstUtil;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,12 @@ public class ClassType extends Type {
|
||||
myParameters = parameters;
|
||||
}
|
||||
|
||||
public ClassType(Identifier type, boolean isNullable) {
|
||||
myType = type;
|
||||
myNullable = isNullable;
|
||||
myParameters = new LinkedList<Type>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String toKotlin() {
|
||||
|
||||
@@ -26,6 +26,18 @@ public class Function extends Member {
|
||||
myBlock = block;
|
||||
}
|
||||
|
||||
public List<Element> getTypeParameters() {
|
||||
return myTypeParameters;
|
||||
}
|
||||
|
||||
public Element getParams() {
|
||||
return myParams;
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return myBlock;
|
||||
}
|
||||
|
||||
private String typeParametersToKotlin() {
|
||||
return myTypeParameters.size() > 0 ? "<" + AstUtil.joinNodes(myTypeParameters, COMMA_WITH_SPACE) + ">" : EMPTY;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public abstract class Type extends Element {
|
||||
public static final Type EMPTY_TYPE = new EmptyType();
|
||||
private boolean myNullable = true;
|
||||
boolean myNullable = true;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.j2k.Converter;
|
||||
import org.jetbrains.jet.j2k.ast.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -189,7 +190,7 @@ public class ExpressionVisitor extends StatementVisitor implements Visitor {
|
||||
typeToType(expression.getType()), // TODO: remove
|
||||
new ExpressionList(callExpression)
|
||||
);
|
||||
} else {
|
||||
} else { // new Class(): common case
|
||||
myResult = new NewClassExpression(
|
||||
elementToElement(expression.getClassOrAnonymousClassReference()),
|
||||
elementToElement(expression.getArgumentList()),
|
||||
@@ -197,6 +198,13 @@ public class ExpressionVisitor extends StatementVisitor implements Visitor {
|
||||
anonymousClassToAnonymousClass(expression.getAnonymousClass()) :
|
||||
null
|
||||
);
|
||||
// is constructor secondary
|
||||
final PsiMethod constructor = expression.resolveMethod();
|
||||
if (constructor != null && !isConstructorPrimary(constructor)) {
|
||||
myResult = new CallChainExpression(
|
||||
new IdentifierImpl(constructor.getName(), false),
|
||||
new MethodCallExpression(new IdentifierImpl("init"), elementToElement(expression.getArgumentList()), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,44 +238,92 @@ public class ExpressionVisitor extends StatementVisitor implements Visitor {
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
super.visitReferenceExpression(expression);
|
||||
|
||||
boolean hasDollar = isFinalFieldReference(expression) && isInsideConstructor(expression);
|
||||
boolean isNullable = typeToType(expression.getType()).isNullable();
|
||||
final boolean isFieldReference = isFieldReference(expression);
|
||||
final boolean hasDollar = isFieldReference && isInsidePrimaryConstructor(expression);
|
||||
final boolean insideSecondaryConstructor = isInsideSecondaryConstructor(expression);
|
||||
final boolean hasReceiver = isFieldReference && insideSecondaryConstructor;
|
||||
final boolean isThis = isThisExpression(expression);
|
||||
final boolean isNullable = typeToType(expression.getType()).isNullable();
|
||||
final String className = getClassName(expression);
|
||||
|
||||
Expression identifier = new IdentifierImpl(expression.getReferenceName(), isNullable);
|
||||
|
||||
if (hasDollar)
|
||||
identifier = new IdentifierImpl(expression.getReferenceName(), hasDollar, isNullable);
|
||||
else {
|
||||
final String temporaryObject = "__";
|
||||
if (hasReceiver)
|
||||
identifier = new CallChainExpression(new IdentifierImpl(temporaryObject, false), new IdentifierImpl(expression.getReferenceName(), isNullable));
|
||||
else if (insideSecondaryConstructor && isThis)
|
||||
identifier = new IdentifierImpl("val " + temporaryObject + " = " + className); // TODO: hack
|
||||
}
|
||||
|
||||
final IdentifierImpl identifier = hasDollar ?
|
||||
new IdentifierImpl(expression.getReferenceName(), hasDollar, isNullable) :
|
||||
new IdentifierImpl(expression.getReferenceName(), isNullable);
|
||||
myResult = new CallChainExpression(
|
||||
expressionToExpression(expression.getQualifierExpression()),
|
||||
identifier // TODO: if type exists so identifier is nullable
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isFinalFieldReference(PsiReferenceExpression expression) {
|
||||
@NotNull
|
||||
private String getClassName(PsiReferenceExpression expression) {
|
||||
PsiElement context = expression.getContext();
|
||||
while (context != null) {
|
||||
if (context instanceof PsiMethod && ((PsiMethod) context).isConstructor()) {
|
||||
final PsiClass containingClass = ((PsiMethod) context).getContainingClass();
|
||||
if (containingClass != null) {
|
||||
final PsiIdentifier identifier = containingClass.getNameIdentifier();
|
||||
if (identifier != null)
|
||||
return identifier.getText();
|
||||
}
|
||||
}
|
||||
context = context.getContext();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private boolean isFieldReference(PsiReferenceExpression expression) {
|
||||
final PsiReference reference = expression.getReference();
|
||||
if (reference != null) {
|
||||
final PsiElement resolvedReference = reference.resolve();
|
||||
if (resolvedReference != null) {
|
||||
if (resolvedReference instanceof PsiField) {
|
||||
final PsiModifierList modifierList = ((PsiField) resolvedReference).getModifierList();
|
||||
if (modifierList != null && modifierList.hasExplicitModifier(PsiModifier.FINAL)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isInsideConstructor(PsiReferenceExpression expression) {
|
||||
private boolean isInsideSecondaryConstructor(PsiReferenceExpression expression) {
|
||||
PsiElement context = expression.getContext();
|
||||
while (context != null) {
|
||||
if (context instanceof PsiMethod && ((PsiMethod) context).isConstructor())
|
||||
return true;
|
||||
return !Converter.isConstructorPrimary((PsiMethod) context);
|
||||
context = context.getContext();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isInsidePrimaryConstructor(PsiReferenceExpression expression) {
|
||||
PsiElement context = expression.getContext();
|
||||
while (context != null) {
|
||||
if (context instanceof PsiMethod && ((PsiMethod) context).isConstructor())
|
||||
return Converter.isConstructorPrimary((PsiMethod) context);
|
||||
context = context.getContext();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isThisExpression(PsiReferenceExpression expression) {
|
||||
for (PsiReference r : expression.getReferences())
|
||||
if (r.getCanonicalText().equals("this")) {
|
||||
final PsiElement res = r.resolve();
|
||||
if (res != null && res instanceof PsiMethod && ((PsiMethod) res).isConstructor())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSuperExpression(PsiSuperExpression expression) {
|
||||
super.visitSuperExpression(expression);
|
||||
@@ -288,7 +344,6 @@ public class ExpressionVisitor extends StatementVisitor implements Visitor {
|
||||
new IdentifierImpl(qualifier.getQualifiedName()) :
|
||||
Identifier.EMPTY_IDENTIFIER
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.jetbrains.jet.j2k.visitors;
|
||||
|
||||
import com.intellij.psi.JavaRecursiveElementVisitor;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiReferenceExpression;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @author ignatov
|
||||
*/
|
||||
public class ThisVisitor extends JavaRecursiveElementVisitor {
|
||||
HashSet<PsiMethod> myResolvedConstructors = new HashSet<PsiMethod>();
|
||||
|
||||
public HashSet<PsiMethod> getResult() {
|
||||
return myResolvedConstructors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
for (PsiReference r : expression.getReferences())
|
||||
if (r.getCanonicalText().equals("this"))
|
||||
if (r.resolve() != null && r.resolve() instanceof PsiMethod && ((PsiMethod) r.resolve()).isConstructor())
|
||||
myResolvedConstructors.add((PsiMethod) r.resolve());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiMethod getPrimaryConstructor() {
|
||||
if (myResolvedConstructors.size() > 0) {
|
||||
PsiMethod first = myResolvedConstructors.toArray(new PsiMethod[myResolvedConstructors.size()])[0];
|
||||
for (PsiMethod m : myResolvedConstructors)
|
||||
if (m.hashCode() != first.hashCode())
|
||||
return null;
|
||||
return first;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
class C {
|
||||
C(int arg1, int arg2, int arg3) {
|
||||
}
|
||||
|
||||
C(int arg1, int arg2) {
|
||||
this(arg1, arg2, 0);
|
||||
}
|
||||
|
||||
C(int arg1) {
|
||||
this(arg1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class User {
|
||||
public static void main() {
|
||||
C c1 = new C(100, 100, 100);
|
||||
C c2 = new C(100, 100);
|
||||
C c3 = new C(100);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
open class C(arg1 : Int, arg2 : Int, arg3 : Int) {
|
||||
{
|
||||
}
|
||||
class object {
|
||||
open fun init(arg1 : Int, arg2 : Int) : C {
|
||||
val __ = C(arg1, arg2, 0)
|
||||
return __
|
||||
}
|
||||
open fun init(arg1 : Int) : C {
|
||||
val __ = C(arg1, 0, 0)
|
||||
return __
|
||||
}
|
||||
}
|
||||
}
|
||||
public open class User() {
|
||||
class object {
|
||||
open public fun main() : Unit {
|
||||
var c1 : C? = C(100, 100, 100)
|
||||
var c2 : C? = C.init(100, 100)
|
||||
var c3 : C? = C.init(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
class C {
|
||||
final int myArg1;
|
||||
int myArg2;
|
||||
int myArg3;
|
||||
|
||||
C(int arg1, int arg2, int arg3) {
|
||||
this(arg1);
|
||||
myArg2 = arg2;
|
||||
myArg3 = arg3;
|
||||
}
|
||||
|
||||
C(int arg1, int arg2) {
|
||||
this(arg1);
|
||||
myArg2 = arg2;
|
||||
myArg3 = 0;
|
||||
}
|
||||
|
||||
C(int arg1) {
|
||||
myArg1 = arg1;
|
||||
myArg2 = 0;
|
||||
myArg3 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class User {
|
||||
public static void main() {
|
||||
C c1 = new C(100, 100, 100);
|
||||
C c2 = new C(100, 100);
|
||||
C c3 = new C(100);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
open class C(arg1 : Int) {
|
||||
val myArg1 : Int
|
||||
var myArg2 : Int
|
||||
var myArg3 : Int
|
||||
{
|
||||
$myArg1 = arg1
|
||||
$myArg2 = 0
|
||||
$myArg3 = 0
|
||||
}
|
||||
class object {
|
||||
open fun init(arg1 : Int, arg2 : Int, arg3 : Int) : C {
|
||||
val __ = C(arg1)
|
||||
__.myArg2 = arg2
|
||||
__.myArg3 = arg3
|
||||
return __
|
||||
}
|
||||
open fun init(arg1 : Int, arg2 : Int) : C {
|
||||
val __ = C(arg1)
|
||||
__.myArg2 = arg2
|
||||
__.myArg3 = 0
|
||||
return __
|
||||
}
|
||||
}
|
||||
}
|
||||
public open class User() {
|
||||
class object {
|
||||
open public fun main() : Unit {
|
||||
var c1 : C? = C.init(100, 100, 100)
|
||||
var c2 : C? = C.init(100, 100)
|
||||
var c3 : C? = C(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ YELLOW(24)
|
||||
BLUE(25)
|
||||
private var code : Int
|
||||
open private (c : Int) {
|
||||
code = c
|
||||
$code = c
|
||||
}
|
||||
open public fun getCode() : Int {
|
||||
return code
|
||||
|
||||
Reference in New Issue
Block a user