KT-820 Add explicit conversion in assignment expression

This commit is contained in:
Sergey Ignatov
2011-12-13 19:21:08 +04:00
parent ee2ade0b10
commit f552429fe1
10 changed files with 184 additions and 101 deletions
+111 -4
View File
@@ -26,9 +26,15 @@ public class Converter {
add("javax.annotation.Nonnull");
}
};
@NotNull private static Set<String> ourClassIdentifiers = new HashSet<String>();
@NotNull private static final Dispatcher ourDispatcher = new Dispatcher();
@Nullable private static PsiType ourMethodReturnType = null;
@NotNull
private static Set<String> ourClassIdentifiers = new HashSet<String>();
@NotNull
private static final Dispatcher ourDispatcher = new Dispatcher();
@Nullable
private static PsiType ourMethodReturnType = null;
private Converter() {
}
public static void setClassIdentifiers(@NotNull Set<String> identifiers) {
ourClassIdentifiers = identifiers;
@@ -269,7 +275,8 @@ public class Converter {
new IdentifierImpl(field.getName()), // TODO
modifiers,
typeToType(field.getType()),
expressionToExpression(field.getInitializer()) // TODO: add modifiers
expressionToExpression(field.getInitializer()), // TODO: add modifiers
createConversionForCallChains(field.getInitializer(), field.getType())
);
}
@@ -549,4 +556,104 @@ public class Converter {
}
return modifiersSet;
}
@NotNull
public static List<String> createConversions(@NotNull PsiCallExpression expression) {
List<String> conversions = new LinkedList<String>();
PsiExpressionList argumentList = expression.getArgumentList();
PsiExpression[] arguments = argumentList != null ? argumentList.getExpressions() : new PsiExpression[]{};
//noinspection UnusedDeclaration
for (final PsiExpression a : arguments) {
conversions.add("");
}
PsiMethod resolve = expression.resolveMethod();
if (resolve != null) {
List<PsiType> expectedTypes = new LinkedList<PsiType>();
List<PsiType> actualTypes = new LinkedList<PsiType>();
for (PsiParameter p : resolve.getParameterList().getParameters())
expectedTypes.add(p.getType());
for (PsiExpression e : arguments)
actualTypes.add(e.getType());
assert actualTypes.size() == expectedTypes.size() : "The type list must have the same length";
for (int i = 0; i < actualTypes.size(); i++)
conversions.set(i, createConversionForExpression(arguments[i], expectedTypes.get(i)));
}
return conversions;
}
@NotNull
public static String createConversionForExpression(@Nullable PsiExpression expression, @NotNull PsiType expectedType) {
String conversion = "";
if (expression != null) {
PsiType actualType = expression.getType();
if (actualType != null) {
if (isConversionNeeded(actualType, expectedType))
conversion += getPrimitiveTypeConversion(expectedType.getCanonicalText());
if (expression instanceof PsiReferenceExpression && Node.PRIMITIVE_TYPES.contains(actualType.getCanonicalText()) && ((PsiReferenceExpression) expression).isQualified())
conversion += ".sure()";
}
}
return conversion;
}
public static boolean isConversionNeeded(@Nullable final PsiType actual, @Nullable final PsiType expected) {
if (actual == null || expected == null)
return false;
Map<String, String> typeMap = new 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");
String expectedStr = expected.getCanonicalText();
String actualStr = actual.getCanonicalText();
boolean o1 = AstUtil.getOrElse(typeMap, actualStr, "").equals(expectedStr);
boolean o2 = AstUtil.getOrElse(typeMap, expectedStr, "").equals(actualStr);
return !actualStr.equals(expectedStr) && (!(o1 ^ o2));
}
@NotNull
public static String getPrimitiveTypeConversion(@NotNull String type) {
Map<String, String> conversions = new HashMap<String, String>();
conversions.put("byte", "byt");
conversions.put("short", "sht");
conversions.put("int", "int");
conversions.put("long", "lng");
conversions.put("float", "flt");
conversions.put("double", "dbl");
conversions.put("char", "chr");
conversions.put("java.lang.Byte", "byt");
conversions.put("java.lang.Short", "sht");
conversions.put("java.lang.Integer", "int");
conversions.put("java.lang.Long", "lng");
conversions.put("java.lang.Float", "flt");
conversions.put("java.lang.Double", "dbl");
conversions.put("java.lang.Character", "chr");
if (conversions.containsKey(type))
return "." + conversions.get(type);
return "";
}
// @NotNull
// private static String applyConversion(Expression expression, String conversion) {
// if (conversion.isEmpty())
// return expression.toKotlin();
// return "(" + expression.toKotlin() + ")" + conversion;
// }
@NotNull
public static String createConversionForCallChains(PsiExpression initializer, PsiType type) {
if (initializer != null && initializer instanceof PsiReferenceExpression && ((PsiReferenceExpression) initializer).isQualified())
return createConversionForExpression(initializer, type);
return "";
}
}
+9 -2
View File
@@ -14,16 +14,23 @@ import static org.jetbrains.jet.j2k.Converter.getDefaultInitializer;
*/
public class Field extends Member {
final Identifier myIdentifier;
@NotNull
private final String myConversion;
final Type myType;
final Element myInitializer;
public Field(Identifier identifier, Set<String> modifiers, Type type, Element initializer) {
public Field(Identifier identifier, Set<String> modifiers, Type type, Element initializer, @NotNull String conversionForCallChains) {
myIdentifier = identifier;
myConversion = conversionForCallChains;
myModifiers = modifiers;
myType = type;
myInitializer = initializer;
}
public Field(Identifier identifier, Set<String> modifiers, Type type, Element initializer) {
this(identifier, modifiers, type, initializer, "");
}
public Element getInitializer() {
return myInitializer;
}
@@ -71,6 +78,6 @@ public class Field extends Member {
return modifier + myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin() + SPACE + EQUAL + SPACE + getDefaultInitializer(this);
return modifier + myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin() + SPACE +
EQUAL + SPACE + myInitializer.toKotlin();
EQUAL + SPACE + myInitializer.toKotlin() + myConversion;
}
}
@@ -12,12 +12,14 @@ public class LocalVariable extends Expression {
private final Set<String> myModifiersSet;
private final Type myType;
private final Expression myInitializer;
private final String myConversion;
public LocalVariable(Identifier identifier, Set<String> modifiersSet, Type type, Expression initializer) {
public LocalVariable(Identifier identifier, Set<String> modifiersSet, Type type, Expression initializer, @NotNull String conversionForExpression) {
myIdentifier = identifier;
myModifiersSet = modifiersSet;
myType = type;
myInitializer = initializer;
myConversion = conversionForExpression;
}
public boolean hasModifier(String modifier) {
@@ -31,6 +33,6 @@ public class LocalVariable extends Expression {
return myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin();
return myIdentifier.toKotlin() + SPACE + COLON + SPACE + myType.toKotlin() + SPACE +
EQUAL + SPACE + myInitializer.toKotlin();
EQUAL + SPACE + myInitializer.toKotlin() + myConversion;
}
}
@@ -30,7 +30,8 @@ public class ElementVisitor extends JavaElementVisitor {
new IdentifierImpl(variable.getName()), // TODO
modifiersListToModifiersSet(variable.getModifierList()),
typeToType(variable.getType(), Converter.isNotNull(variable.getModifierList())),
expressionToExpression(variable.getInitializer())
expressionToExpression(variable.getInitializer()),
createConversionForCallChains(variable.getInitializer(), variable.getType())
);
}
@@ -4,9 +4,7 @@ import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.j2k.Converter;
import org.jetbrains.jet.j2k.ast.*;
import org.jetbrains.jet.j2k.util.AstUtil;
import java.util.*;
@@ -16,7 +14,7 @@ import static org.jetbrains.jet.j2k.Converter.*;
* @author ignatov
*/
public class ExpressionVisitor extends StatementVisitor {
@Nullable
@NotNull
Expression myResult = Expression.EMPTY_EXPRESSION;
@Override
@@ -204,92 +202,6 @@ public class ExpressionVisitor extends StatementVisitor {
}
}
@NotNull
private static List<String> createConversions(@NotNull PsiCallExpression expression) {
List<String> conversions = new LinkedList<String>();
PsiExpressionList argumentList = expression.getArgumentList();
PsiExpression[] arguments = argumentList != null ? argumentList.getExpressions() : new PsiExpression[]{};
//noinspection UnusedDeclaration
for (final PsiExpression a : arguments) {
conversions.add("");
}
PsiMethod resolve = expression.resolveMethod();
if (resolve != null) {
List<PsiType> expectedTypes = new LinkedList<PsiType>();
List<PsiType> actualTypes = new LinkedList<PsiType>();
for (PsiParameter p : resolve.getParameterList().getParameters())
expectedTypes.add(p.getType());
for (PsiExpression e : arguments)
actualTypes.add(e.getType());
assert actualTypes.size() == expectedTypes.size() : "The type list must have the same length";
for (int i = 0; i < actualTypes.size(); i++) {
PsiType actual = actualTypes.get(i);
PsiType expected = expectedTypes.get(i);
PsiExpression argument = arguments[i];
String conversion = "";
if (isConversionNeeded(actual, expected))
conversion += getPrimitiveTypeConversion(expected.getCanonicalText());
PsiType type = argument.getType();
if (argument instanceof PsiReferenceExpression &&
type != null && Node.PRIMITIVE_TYPES.contains(type.getCanonicalText()) &&
((PsiReferenceExpression) argument).isQualified())
conversion += ".sure()";
conversions.set(i, conversion);
}
}
return conversions;
}
static boolean isConversionNeeded(@Nullable final PsiType actual, @Nullable final PsiType expected) {
if (actual == null || expected == null)
return false;
Map<String, String> typeMap = new 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");
String expectedStr = expected.getCanonicalText();
String actualStr = actual.getCanonicalText();
boolean o1 = AstUtil.getOrElse(typeMap, actualStr, "").equals(expectedStr);
boolean o2 = AstUtil.getOrElse(typeMap, expectedStr, "").equals(actualStr);
return !actualStr.equals(expectedStr) && (!(o1 ^ o2));
}
@NotNull
static String getPrimitiveTypeConversion(@NotNull String type) {
Map<String, String> conversions = new HashMap<String, String>();
conversions.put("byte", "byt");
conversions.put("short", "sht");
conversions.put("int", "int");
conversions.put("long", "lng");
conversions.put("float", "flt");
conversions.put("double", "dbl");
conversions.put("char", "chr");
conversions.put("java.lang.Byte", "byt");
conversions.put("java.lang.Short", "sht");
conversions.put("java.lang.Integer", "int");
conversions.put("java.lang.Long", "lng");
conversions.put("java.lang.Float", "flt");
conversions.put("java.lang.Double", "dbl");
conversions.put("java.lang.Character", "chr");
if (conversions.containsKey(type))
return "." + conversions.get(type);
return "";
}
@Override
public void visitCallExpression(PsiCallExpression callExpression) {
super.visitCallExpression(callExpression);
@@ -313,7 +225,7 @@ public class ExpressionVisitor extends StatementVisitor {
final PsiAnonymousClass anonymousClass = expression.getAnonymousClass();
final PsiMethod constructor = expression.resolveMethod();
PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
final boolean isNotConvertedClass = classReference != null && !Converter.getClassIdentifiers().contains(classReference.getQualifiedName());
final boolean isNotConvertedClass = classReference != null && !getClassIdentifiers().contains(classReference.getQualifiedName());
PsiExpressionList argumentList = expression.getArgumentList();
PsiExpression[] arguments = argumentList != null ? argumentList.getExpressions() : new PsiExpression[]{};
if (constructor == null || isConstructorPrimary(constructor) || isNotConvertedClass) {
@@ -15,8 +15,8 @@ import java.util.LinkedList;
import java.util.List;
import static org.jetbrains.jet.j2k.Converter.*;
import static org.jetbrains.jet.j2k.visitors.ExpressionVisitor.getPrimitiveTypeConversion;
import static org.jetbrains.jet.j2k.visitors.ExpressionVisitor.isConversionNeeded;
import static org.jetbrains.jet.j2k.Converter.getPrimitiveTypeConversion;
import static org.jetbrains.jet.j2k.Converter.isConversionNeeded;
/**
* @author ignatov
+13
View File
@@ -0,0 +1,13 @@
package demo;
class Container {
int myInt = 1;
}
class One {
static Container myContainer = new Container();
}
class Test {
byte b = One.myContainer.myInt;
}
+12
View File
@@ -0,0 +1,12 @@
namespace demo
open class Container() {
var myInt : Int = 1
}
open class One() {
class object {
var myContainer : Container? = Container()
}
}
open class Test() {
var b : Byte = One.myContainer?.myInt.byt.sure()
}
+15
View File
@@ -0,0 +1,15 @@
package demo;
class Container {
int myInt = 1;
}
class One {
static Container myContainer = new Container();
}
class Test {
void test() {
byte b = One.myContainer.myInt;
}
}
+14
View File
@@ -0,0 +1,14 @@
namespace demo
open class Container() {
var myInt : Int = 1
}
open class One() {
class object {
var myContainer : Container? = Container()
}
}
open class Test() {
open fun test() : Unit {
var b : Byte = One.myContainer?.myInt.byt.sure()
}
}