TypeVisitor to Kotlin

This commit is contained in:
Dmitry Jemerov
2012-05-22 16:10:14 +02:00
committed by Pavel V. Talanov
parent 3130b750d3
commit 85755df615
5 changed files with 171 additions and 221 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ import java.util.*;
import static org.jetbrains.jet.j2k.ConverterUtil.countWritingAccesses;
import static org.jetbrains.jet.j2k.ConverterUtil.createMainFunction;
import static org.jetbrains.jet.j2k.visitors.TypeVisitor.*;
import static com.intellij.psi.CommonClassNames.*;
import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*;
/**
@@ -29,7 +29,7 @@ import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.j2k.Converter.isConstructorPrimary;
import static org.jetbrains.jet.j2k.visitors.TypeVisitor.*;
import static com.intellij.psi.CommonClassNames.*;
/**
* @author ignatov
@@ -23,7 +23,7 @@ import org.jetbrains.jet.j2k.ast.DummyMethodCallExpression;
import org.jetbrains.jet.j2k.ast.DummyStringExpression;
import org.jetbrains.jet.j2k.ast.IdentifierImpl;
import static org.jetbrains.jet.j2k.visitors.TypeVisitor.JAVA_LANG_OBJECT;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT;
/**
* @author ignatov
@@ -1,218 +0,0 @@
/*
* 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.visitors;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import org.jetbrains.annotations.NotNull;
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 org.jetbrains.jet.j2k.util.AstUtil;
import java.util.LinkedList;
import java.util.List;
/**
* @author ignatov
*/
public class TypeVisitor extends PsiTypeVisitor<Type> implements J2KVisitor {
public static final String JAVA_LANG_BYTE = "java.lang.Byte";
public static final String JAVA_LANG_CHARACTER = "java.lang.Character";
public static final String JAVA_LANG_DOUBLE = "java.lang.Double";
public static final String JAVA_LANG_FLOAT = "java.lang.Float";
public static final String JAVA_LANG_INTEGER = "java.lang.Integer";
public static final String JAVA_LANG_LONG = "java.lang.Long";
public static final String JAVA_LANG_SHORT = "java.lang.Short";
private static final String JAVA_LANG_BOOLEAN = "java.lang.Boolean";
public static final String JAVA_LANG_OBJECT = "java.lang.Object";
public static final String JAVA_LANG_STRING = "java.lang.String";
private static final String JAVA_LANG_ITERABLE = "java.lang.Iterable";
private static final String JAVA_UTIL_ITERATOR = "java.util.Iterator";
private final Converter myConverter;
private Type myResult = new EmptyType();
public TypeVisitor(@NotNull Converter myConverter) {
this.myConverter = myConverter;
}
@NotNull
public Type getResult() {
return myResult;
}
@Override
public Type visitPrimitiveType(@NotNull PsiPrimitiveType primitiveType) {
final String name = primitiveType.getCanonicalText();
final IdentifierImpl identifier = new IdentifierImpl(name);
if (name.equals("void")) {
myResult = new PrimitiveType(new IdentifierImpl("Unit"));
}
else if (Node.PRIMITIVE_TYPES.contains(name)) {
myResult = new PrimitiveType(new IdentifierImpl(AstUtil.upperFirstCharacter(name)));
}
else {
myResult = new PrimitiveType(identifier);
}
return super.visitPrimitiveType(primitiveType);
}
@Override
public Type visitArrayType(@NotNull PsiArrayType arrayType) {
if (myResult instanceof EmptyType) {
myResult = new ArrayType(getConverter().typeToType(arrayType.getComponentType()), true);
}
return super.visitArrayType(arrayType);
}
@Override
public Type visitClassType(@NotNull PsiClassType classType) {
final IdentifierImpl identifier = constructClassTypeIdentifier(classType);
final List<Type> resolvedClassTypeParams = createRawTypesForResolvedReference(classType);
if (classType.getParameterCount() == 0 && resolvedClassTypeParams.size() > 0) {
myResult = new ClassType(identifier, resolvedClassTypeParams, true);
}
else {
myResult = new ClassType(identifier, getConverter().typesToTypeList(classType.getParameters()), true);
}
return super.visitClassType(classType);
}
@NotNull
private IdentifierImpl constructClassTypeIdentifier(@NotNull PsiClassType classType) {
final PsiClass psiClass = classType.resolve();
if (psiClass != null) {
String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName != null) {
if (!qualifiedName.equals("java.lang.Object") && getConverter().hasFlag(J2KConverterFlags.FULLY_QUALIFIED_TYPE_NAMES)) {
return new IdentifierImpl(qualifiedName);
}
if (qualifiedName.equals(JAVA_LANG_ITERABLE)) {
return new IdentifierImpl(JAVA_LANG_ITERABLE);
}
if (qualifiedName.equals(JAVA_UTIL_ITERATOR)) {
return new IdentifierImpl(JAVA_UTIL_ITERATOR);
}
}
}
final String classTypeName = createQualifiedName(classType);
if (classTypeName.isEmpty()) {
return new IdentifierImpl(getClassTypeName(classType));
}
return new IdentifierImpl(classTypeName);
}
@NotNull
private static String createQualifiedName(@NotNull PsiClassType classType) {
String classTypeName = "";
if (classType instanceof PsiClassReferenceType) {
final PsiJavaCodeReferenceElement reference = ((PsiClassReferenceType) classType).getReference();
if (reference.isQualified()) {
String result = new IdentifierImpl(reference.getReferenceName()).toKotlin();
PsiElement qualifier = reference.getQualifier();
while (qualifier != null) {
final PsiJavaCodeReferenceElement p = (PsiJavaCodeReferenceElement) qualifier;
result = new IdentifierImpl(p.getReferenceName()).toKotlin() + "." + result; // TODO: maybe need to replace by safe call?
qualifier = p.getQualifier();
}
classTypeName = result;
}
}
return classTypeName;
}
@NotNull
private List<Type> createRawTypesForResolvedReference(@NotNull PsiClassType classType) {
final List<Type> typeParams = new LinkedList<Type>();
if (classType instanceof PsiClassReferenceType) {
final PsiJavaCodeReferenceElement reference = ((PsiClassReferenceType) classType).getReference();
final PsiElement resolve = reference.resolve();
if (resolve != null) {
if (resolve instanceof PsiClass)
//noinspection UnusedDeclaration
{
for (PsiTypeParameter p : ((PsiClass) resolve).getTypeParameters()) {
Type boundType = p.getSuperTypes().length > 0 ?
new ClassType(new IdentifierImpl(getClassTypeName(p.getSuperTypes()[0])), getConverter().typesToTypeList(p.getSuperTypes()[0].getParameters()), true)
:
new StarProjectionType();
typeParams.add(boundType);
}
}
}
}
return typeParams;
}
@NotNull
private static String getClassTypeName(@NotNull PsiClassType classType) {
String canonicalTypeStr = classType.getCanonicalText();
if (canonicalTypeStr.equals(JAVA_LANG_OBJECT)) return "Any";
if (canonicalTypeStr.equals(JAVA_LANG_BYTE)) return "Byte";
if (canonicalTypeStr.equals(JAVA_LANG_CHARACTER)) return "Char";
if (canonicalTypeStr.equals(JAVA_LANG_DOUBLE)) return "Double";
if (canonicalTypeStr.equals(JAVA_LANG_FLOAT)) return "Float";
if (canonicalTypeStr.equals(JAVA_LANG_INTEGER)) return "Int";
if (canonicalTypeStr.equals(JAVA_LANG_LONG)) return "Long";
if (canonicalTypeStr.equals(JAVA_LANG_SHORT)) return "Short";
if (canonicalTypeStr.equals(JAVA_LANG_BOOLEAN)) return "Boolean";
return classType.getClassName() != null ? classType.getClassName() : classType.getCanonicalText();
}
@Override
public Type visitWildcardType(@NotNull PsiWildcardType wildcardType) {
if (wildcardType.isExtends()) {
myResult = new OutProjectionType(getConverter().typeToType(wildcardType.getExtendsBound()));
}
else if (wildcardType.isSuper()) {
myResult = new InProjectionType(getConverter().typeToType(wildcardType.getSuperBound()));
}
else {
myResult = new StarProjectionType();
}
return super.visitWildcardType(wildcardType);
}
@Override
public Type visitEllipsisType(@NotNull PsiEllipsisType ellipsisType) {
myResult = new VarArg(getConverter().typeToType(ellipsisType.getComponentType()));
return super.visitEllipsisType(ellipsisType);
}
@Override
public Type visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
return super.visitCapturedWildcardType(capturedWildcardType);
}
@Override
public Type visitDisjunctionType(PsiDisjunctionType disjunctionType) {
return super.visitDisjunctionType(disjunctionType);
}
@NotNull
@Override
public Converter getConverter() {
return myConverter;
}
}
@@ -0,0 +1,168 @@
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 org.jetbrains.jet.j2k.util.AstUtil
import java.util.LinkedList
import java.util.List
public open class TypeVisitor(private val myConverter : Converter) : PsiTypeVisitor<Type?>(), J2KVisitor {
private var myResult : Type = EmptyType()
public open fun getResult() : Type {
return myResult
}
public override fun visitPrimitiveType(primitiveType: PsiPrimitiveType?) : Type? {
val name : String = primitiveType?.getCanonicalText()!!
val identifier : IdentifierImpl = IdentifierImpl(name)
if (name == "void") {
myResult = PrimitiveType(IdentifierImpl("Unit"))
}
else if (Node.PRIMITIVE_TYPES.contains(name)) {
myResult = PrimitiveType(IdentifierImpl(AstUtil.upperFirstCharacter(name)))
}
else {
myResult = PrimitiveType(identifier)
}
return null
}
public override fun visitArrayType(arrayType: PsiArrayType?) : Type? {
if (myResult is EmptyType) {
myResult = ArrayType(myConverter.typeToType(arrayType?.getComponentType()), true)
}
return null
}
public override fun visitClassType(classType : PsiClassType?) : Type? {
if (classType == null) return null
val identifier : IdentifierImpl = constructClassTypeIdentifier(classType)
val resolvedClassTypeParams : List<Type> = createRawTypesForResolvedReference(classType)
if (classType.getParameterCount() == 0 && resolvedClassTypeParams.size() > 0) {
myResult = ClassType(identifier, resolvedClassTypeParams, true)
}
else {
myResult = ClassType(identifier, myConverter.typesToTypeList(classType.getParameters()).requireNoNulls(), true)
}
return null
}
private fun constructClassTypeIdentifier(classType : PsiClassType) : IdentifierImpl {
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 IdentifierImpl(qualifiedName)
}
if (qualifiedName.equals(CommonClassNames.JAVA_LANG_ITERABLE)) {
return IdentifierImpl(CommonClassNames.JAVA_LANG_ITERABLE)
}
if (qualifiedName.equals(CommonClassNames.JAVA_UTIL_ITERATOR)) {
return IdentifierImpl(CommonClassNames.JAVA_UTIL_ITERATOR)
}
}
}
val classTypeName : String? = createQualifiedName(classType)
if (classTypeName?.isEmpty().sure())
{
return IdentifierImpl(getClassTypeName(classType))
}
return IdentifierImpl(classTypeName)
}
private fun createRawTypesForResolvedReference(classType : PsiClassType) : List<Type> {
val typeParams : List<Type> = 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(IdentifierImpl(getClassTypeName(superTypes[0]!!)),
myConverter.typesToTypeList(superTypes[0]!!.getParameters()).requireNoNulls(),
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 null
}
public override fun visitEllipsisType(ellipsisType : PsiEllipsisType?) : Type? {
myResult = VarArg(myConverter.typeToType(ellipsisType?.getComponentType()))
return null
}
public override fun getConverter() : Converter = myConverter
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 = IdentifierImpl(reference.getReferenceName()).toKotlin()
var qualifier : PsiElement? = reference.getQualifier()
while (qualifier != null)
{
val p : PsiJavaCodeReferenceElement = (qualifier as PsiJavaCodeReferenceElement)
result = IdentifierImpl(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())!!
}
}
}
}