Refactor JavaTypeTransformer and ValueParameterResolver
Use an instanceof-chain on a JavaType instance instead of PsiTypeVisitor in TypeTransformer. Add a special method to handle vararg types, use it in ValueParameterResolver
This commit is contained in:
+1
-1
@@ -120,7 +120,7 @@ public class InjectorForJavaDescriptorResolver {
|
|||||||
|
|
||||||
javaValueParameterResolver.setTypeTransformer(javaTypeTransformer);
|
javaValueParameterResolver.setTypeTransformer(javaTypeTransformer);
|
||||||
|
|
||||||
javaTypeTransformer.setResolver(javaClassResolver);
|
javaTypeTransformer.setClassResolver(javaClassResolver);
|
||||||
|
|
||||||
javaSignatureResolver.setTypeTransformer(javaTypeTransformer);
|
javaSignatureResolver.setTypeTransformer(javaTypeTransformer);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -307,7 +307,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
|
|||||||
|
|
||||||
javaValueParameterResolver.setTypeTransformer(javaTypeTransformer);
|
javaValueParameterResolver.setTypeTransformer(javaTypeTransformer);
|
||||||
|
|
||||||
javaTypeTransformer.setResolver(javaClassResolver);
|
javaTypeTransformer.setClassResolver(javaClassResolver);
|
||||||
|
|
||||||
javaSignatureResolver.setTypeTransformer(javaTypeTransformer);
|
javaSignatureResolver.setTypeTransformer(javaTypeTransformer);
|
||||||
|
|
||||||
|
|||||||
+188
-170
@@ -28,7 +28,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
|
|||||||
import org.jetbrains.jet.lang.resolve.java.TypeUsage;
|
import org.jetbrains.jet.lang.resolve.java.TypeUsage;
|
||||||
import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver;
|
import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap;
|
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap;
|
||||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
|
import org.jetbrains.jet.lang.resolve.java.structure.*;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
@@ -48,213 +48,231 @@ public class JavaTypeTransformer {
|
|||||||
|
|
||||||
private static final Logger LOG = Logger.getInstance(JavaTypeTransformer.class);
|
private static final Logger LOG = Logger.getInstance(JavaTypeTransformer.class);
|
||||||
|
|
||||||
private JavaClassResolver resolver;
|
private JavaClassResolver classResolver;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void setResolver(JavaClassResolver resolver) {
|
public void setClassResolver(JavaClassResolver classResolver) {
|
||||||
this.resolver = resolver;
|
this.classResolver = classResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private TypeProjection transformToTypeProjection(@NotNull PsiType javaType,
|
private TypeProjection transformToTypeProjection(
|
||||||
@NotNull final TypeParameterDescriptor typeParameterDescriptor,
|
@NotNull JavaType type,
|
||||||
@NotNull final TypeVariableResolver typeVariableByPsiResolver,
|
@NotNull TypeParameterDescriptor typeParameterDescriptor,
|
||||||
@NotNull final TypeUsage howThisTypeIsUsed
|
@NotNull TypeVariableResolver typeVariableResolver,
|
||||||
|
@NotNull TypeUsage howThisTypeIsUsed
|
||||||
) {
|
) {
|
||||||
return javaType.accept(new PsiTypeVisitor<TypeProjection>() {
|
if (!(type instanceof JavaWildcardType)) {
|
||||||
@Override
|
return new TypeProjection(transformToType(type, howThisTypeIsUsed, typeVariableResolver));
|
||||||
public TypeProjection visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
|
}
|
||||||
throw new UnsupportedOperationException(); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
JavaWildcardType wildcardType = (JavaWildcardType) type;
|
||||||
public TypeProjection visitWildcardType(PsiWildcardType wildcardType) {
|
JavaType bound = wildcardType.getBound();
|
||||||
if (!wildcardType.isBounded()) {
|
if (bound == null) {
|
||||||
return SubstitutionUtils.makeStarProjection(typeParameterDescriptor);
|
return SubstitutionUtils.makeStarProjection(typeParameterDescriptor);
|
||||||
}
|
}
|
||||||
Variance variance = wildcardType.isExtends() ? OUT_VARIANCE : IN_VARIANCE;
|
|
||||||
|
|
||||||
PsiType bound = wildcardType.getBound();
|
Variance variance = wildcardType.isExtends() ? OUT_VARIANCE : IN_VARIANCE;
|
||||||
assert bound != null;
|
|
||||||
return new TypeProjection(variance, transformToType(JavaType.create(bound), UPPER_BOUND, typeVariableByPsiResolver));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
return new TypeProjection(variance, transformToType(bound, UPPER_BOUND, typeVariableResolver));
|
||||||
public TypeProjection visitType(PsiType type) {
|
|
||||||
return new TypeProjection(transformToType(JavaType.create(type), howThisTypeIsUsed, typeVariableByPsiResolver));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetType transformToType(@NotNull JavaType javaType, @NotNull TypeVariableResolver typeVariableResolver) {
|
public JetType transformToType(@NotNull JavaType type, @NotNull TypeVariableResolver typeVariableResolver) {
|
||||||
return transformToType(javaType, TypeUsage.MEMBER_SIGNATURE_INVARIANT, typeVariableResolver);
|
return transformToType(type, TypeUsage.MEMBER_SIGNATURE_INVARIANT, typeVariableResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetType transformToType(@NotNull JavaType javaType, @NotNull final TypeUsage howThisTypeIsUsed,
|
public JetType transformToType(
|
||||||
@NotNull final TypeVariableResolver typeVariableResolver) {
|
@NotNull JavaType type,
|
||||||
return javaType.getPsi().accept(new PsiTypeVisitor<JetType>() {
|
@NotNull TypeUsage howThisTypeIsUsed,
|
||||||
@Override
|
@NotNull TypeVariableResolver typeVariableResolver
|
||||||
public JetType visitClassType(PsiClassType classType) {
|
) {
|
||||||
PsiClass psiClass = classType.resolve();
|
if (type instanceof JavaClassType) {
|
||||||
if (psiClass == null) {
|
return transformClassType((JavaClassType) type, howThisTypeIsUsed, typeVariableResolver);
|
||||||
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
}
|
||||||
}
|
else if (type instanceof JavaPrimitiveType) {
|
||||||
|
String canonicalText = ((JavaPrimitiveType) type).getCanonicalText();
|
||||||
|
JetType jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass(canonicalText);
|
||||||
|
assert jetType != null : "Primitive type is not found: " + canonicalText;
|
||||||
|
return jetType;
|
||||||
|
}
|
||||||
|
else if (type instanceof JavaArrayType) {
|
||||||
|
return transformArrayType((JavaArrayType) type, howThisTypeIsUsed, typeVariableResolver, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("Unsupported type: " + type); // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (psiClass instanceof PsiTypeParameter) {
|
@NotNull
|
||||||
PsiTypeParameter typeParameter = (PsiTypeParameter) psiClass;
|
private JetType transformClassType(
|
||||||
|
@NotNull JavaClassType classType,
|
||||||
|
@NotNull TypeUsage howThisTypeIsUsed,
|
||||||
|
@NotNull TypeVariableResolver typeVariableResolver
|
||||||
|
) {
|
||||||
|
JavaClass javaClass = classType.resolve();
|
||||||
|
if (javaClass == null) {
|
||||||
|
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
||||||
|
}
|
||||||
|
|
||||||
PsiTypeParameterListOwner typeParameterListOwner = typeParameter.getOwner();
|
PsiClass psiClass = javaClass.getPsi();
|
||||||
if (typeParameterListOwner instanceof PsiMethod) {
|
|
||||||
PsiMethod psiMethod = (PsiMethod) typeParameterListOwner;
|
if (psiClass instanceof PsiTypeParameter) {
|
||||||
if (psiMethod.isConstructor()) {
|
PsiTypeParameter typeParameter = (PsiTypeParameter) psiClass;
|
||||||
Set<JetType> supertypesJet = Sets.newHashSet();
|
|
||||||
for (PsiClassType supertype : typeParameter.getExtendsListTypes()) {
|
PsiTypeParameterListOwner typeParameterListOwner = typeParameter.getOwner();
|
||||||
supertypesJet.add(transformToType(JavaType.create(supertype), UPPER_BOUND, typeVariableResolver));
|
if (typeParameterListOwner instanceof PsiMethod) {
|
||||||
}
|
PsiMethod psiMethod = (PsiMethod) typeParameterListOwner;
|
||||||
return TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet);
|
if (psiMethod.isConstructor()) {
|
||||||
}
|
Set<JetType> supertypesJet = Sets.newHashSet();
|
||||||
|
for (PsiClassType supertype : typeParameter.getExtendsListTypes()) {
|
||||||
|
supertypesJet.add(transformToType(JavaType.create(supertype), UPPER_BOUND, typeVariableResolver));
|
||||||
}
|
}
|
||||||
|
JetType type = TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet);
|
||||||
TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName());
|
if (type == null) {
|
||||||
|
|
||||||
// In Java: ArrayList<T>
|
|
||||||
// In Kotlin: ArrayList<T>, not ArrayList<T?>
|
|
||||||
// nullability will be taken care of in individual member signatures
|
|
||||||
boolean nullable = !EnumSet.of(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT).contains(howThisTypeIsUsed);
|
|
||||||
if (nullable) {
|
|
||||||
return TypeUtils.makeNullable(typeParameterDescriptor.getDefaultType());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return typeParameterDescriptor.getDefaultType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 'L extends List<T>' in Java is a List<T> in Kotlin, not a List<T?>
|
|
||||||
boolean nullable = !EnumSet.of(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed);
|
|
||||||
|
|
||||||
String qualifiedName = psiClass.getQualifiedName();
|
|
||||||
assert qualifiedName != null : "Class type should have a FQ name: " + psiClass;
|
|
||||||
FqName fqName = new FqName(qualifiedName);
|
|
||||||
|
|
||||||
ClassDescriptor classData = JavaToKotlinClassMap.getInstance().mapKotlinClass(fqName, howThisTypeIsUsed);
|
|
||||||
|
|
||||||
if (classData == null) {
|
|
||||||
classData = resolver.resolveClass(fqName, INCLUDE_KOTLIN_SOURCES);
|
|
||||||
}
|
|
||||||
if (classData == null) {
|
|
||||||
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
||||||
}
|
}
|
||||||
|
return type;
|
||||||
List<TypeProjection> arguments = Lists.newArrayList();
|
|
||||||
List<TypeParameterDescriptor> parameters = classData.getTypeConstructor().getParameters();
|
|
||||||
if (isRaw(classType, !parameters.isEmpty())) {
|
|
||||||
for (TypeParameterDescriptor parameter : parameters) {
|
|
||||||
// not making a star projection because of this case:
|
|
||||||
// Java:
|
|
||||||
// class C<T extends C> {}
|
|
||||||
// The upper bound is raw here, and we can't compute the projection: it would be infinite:
|
|
||||||
// C<*> = C<out C<out C<...>>>
|
|
||||||
// this way we loose some type information, even when the case is not so bad, but it doesn't seem to matter
|
|
||||||
|
|
||||||
// projections are not allowed in immediate arguments of supertypes
|
|
||||||
Variance projectionKind = parameter.getVariance() == OUT_VARIANCE || howThisTypeIsUsed == SUPERTYPE
|
|
||||||
? INVARIANT
|
|
||||||
: OUT_VARIANCE;
|
|
||||||
arguments.add(new TypeProjection(projectionKind, KotlinBuiltIns.getInstance().getNullableAnyType()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PsiType[] psiArguments = classType.getParameters();
|
|
||||||
|
|
||||||
if (parameters.size() != psiArguments.length) {
|
|
||||||
// Most of the time this means there is an error in the Java code
|
|
||||||
LOG.warn("parameters = " + parameters.size() + ", actual arguments = " + psiArguments.length +
|
|
||||||
" in " + classType.getPresentableText() + "\n PsiClass: \n" + psiClass.getText());
|
|
||||||
|
|
||||||
for (TypeParameterDescriptor parameter : parameters) {
|
|
||||||
arguments.add(new TypeProjection(ErrorUtils.createErrorType(parameter.getName().asString())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < parameters.size(); i++) {
|
|
||||||
PsiType psiArgument = psiArguments[i];
|
|
||||||
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
|
|
||||||
|
|
||||||
TypeUsage howTheProjectionIsUsed = howThisTypeIsUsed == SUPERTYPE ? SUPERTYPE_ARGUMENT : TYPE_ARGUMENT;
|
|
||||||
TypeProjection typeProjection = transformToTypeProjection(
|
|
||||||
psiArgument, typeParameterDescriptor, typeVariableResolver, howTheProjectionIsUsed);
|
|
||||||
|
|
||||||
if (typeProjection.getProjectionKind() == typeParameterDescriptor.getVariance()) {
|
|
||||||
// remove redundant 'out' and 'in'
|
|
||||||
arguments.add(new TypeProjection(INVARIANT, typeProjection.getType()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
arguments.add(typeProjection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JetTypeImpl(
|
|
||||||
Collections.<AnnotationDescriptor>emptyList(),
|
|
||||||
classData.getTypeConstructor(),
|
|
||||||
nullable,
|
|
||||||
arguments,
|
|
||||||
classData.getMemberScope(arguments));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName());
|
||||||
public JetType visitPrimitiveType(PsiPrimitiveType primitiveType) {
|
|
||||||
String canonicalText = primitiveType.getCanonicalText();
|
// In Java: ArrayList<T>
|
||||||
JetType type = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass(canonicalText);
|
// In Kotlin: ArrayList<T>, not ArrayList<T?>
|
||||||
assert type != null : canonicalText;
|
// nullability will be taken care of in individual member signatures
|
||||||
return type;
|
boolean nullable = !EnumSet.of(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT).contains(howThisTypeIsUsed);
|
||||||
|
if (nullable) {
|
||||||
|
return TypeUtils.makeNullable(typeParameterDescriptor.getDefaultType());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return typeParameterDescriptor.getDefaultType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 'L extends List<T>' in Java is a List<T> in Kotlin, not a List<T?>
|
||||||
|
boolean nullable = !EnumSet.of(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed);
|
||||||
|
|
||||||
|
FqName fqName = javaClass.getFqName();
|
||||||
|
assert fqName != null : "Class type should have a FQ name: " + javaClass;
|
||||||
|
|
||||||
|
ClassDescriptor classData = JavaToKotlinClassMap.getInstance().mapKotlinClass(fqName, howThisTypeIsUsed);
|
||||||
|
|
||||||
|
if (classData == null) {
|
||||||
|
classData = classResolver.resolveClass(fqName, INCLUDE_KOTLIN_SOURCES);
|
||||||
|
}
|
||||||
|
if (classData == null) {
|
||||||
|
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
List<TypeProjection> arguments = Lists.newArrayList();
|
||||||
public JetType visitArrayType(PsiArrayType arrayType) {
|
List<TypeParameterDescriptor> parameters = classData.getTypeConstructor().getParameters();
|
||||||
PsiType componentType = arrayType.getComponentType();
|
if (isRaw(classType, !parameters.isEmpty())) {
|
||||||
if (componentType instanceof PsiPrimitiveType) {
|
for (TypeParameterDescriptor parameter : parameters) {
|
||||||
JetType jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass("[" + componentType.getCanonicalText());
|
// not making a star projection because of this case:
|
||||||
if (jetType != null)
|
// Java:
|
||||||
return TypeUtils.makeNullable(jetType);
|
// class C<T extends C> {}
|
||||||
|
// The upper bound is raw here, and we can't compute the projection: it would be infinite:
|
||||||
|
// C<*> = C<out C<out C<...>>>
|
||||||
|
// this way we loose some type information, even when the case is not so bad, but it doesn't seem to matter
|
||||||
|
|
||||||
|
// projections are not allowed in immediate arguments of supertypes
|
||||||
|
Variance projectionKind = parameter.getVariance() == OUT_VARIANCE || howThisTypeIsUsed == SUPERTYPE
|
||||||
|
? INVARIANT
|
||||||
|
: OUT_VARIANCE;
|
||||||
|
arguments.add(new TypeProjection(projectionKind, KotlinBuiltIns.getInstance().getNullableAnyType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean vararg = arrayType instanceof PsiEllipsisType;
|
|
||||||
|
|
||||||
Variance projectionKind = arrayElementTypeProjectionKind(vararg);
|
|
||||||
TypeUsage howArgumentTypeIsUsed = vararg ? MEMBER_SIGNATURE_CONTRAVARIANT : TYPE_ARGUMENT;
|
|
||||||
|
|
||||||
JetType type = transformToType(JavaType.create(componentType), howArgumentTypeIsUsed, typeVariableResolver);
|
|
||||||
return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, type));
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
PsiType[] psiArguments = classType.getPsi().getParameters();
|
||||||
|
|
||||||
private Variance arrayElementTypeProjectionKind(boolean vararg) {
|
if (parameters.size() != psiArguments.length) {
|
||||||
Variance variance;
|
// Most of the time this means there is an error in the Java code
|
||||||
if (howThisTypeIsUsed == MEMBER_SIGNATURE_CONTRAVARIANT && !vararg) {
|
LOG.warn("parameters = " + parameters.size() + ", actual arguments = " + psiArguments.length +
|
||||||
variance = OUT_VARIANCE;
|
" in " + classType.getPresentableText() + "\n PsiClass: \n" + psiClass.getText());
|
||||||
|
|
||||||
|
for (TypeParameterDescriptor parameter : parameters) {
|
||||||
|
arguments.add(new TypeProjection(ErrorUtils.createErrorType(parameter.getName().asString())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
variance = INVARIANT;
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
|
PsiType psiArgument = psiArguments[i];
|
||||||
|
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
|
||||||
|
|
||||||
|
TypeUsage howTheProjectionIsUsed = howThisTypeIsUsed == SUPERTYPE ? SUPERTYPE_ARGUMENT : TYPE_ARGUMENT;
|
||||||
|
TypeProjection typeProjection = transformToTypeProjection(
|
||||||
|
JavaType.create(psiArgument), typeParameterDescriptor, typeVariableResolver,
|
||||||
|
howTheProjectionIsUsed);
|
||||||
|
|
||||||
|
if (typeProjection.getProjectionKind() == typeParameterDescriptor.getVariance()) {
|
||||||
|
// remove redundant 'out' and 'in'
|
||||||
|
arguments.add(new TypeProjection(INVARIANT, typeProjection.getType()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arguments.add(typeProjection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return variance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
return new JetTypeImpl(
|
||||||
public JetType visitType(PsiType type) {
|
Collections.<AnnotationDescriptor>emptyList(),
|
||||||
throw new UnsupportedOperationException("Unsupported type: " + type.getPresentableText()); // TODO
|
classData.getTypeConstructor(),
|
||||||
}
|
nullable,
|
||||||
});
|
arguments,
|
||||||
|
classData.getMemberScope(arguments));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isRaw(@NotNull PsiClassType classType, boolean argumentsExpected) {
|
@NotNull
|
||||||
|
private JetType transformArrayType(
|
||||||
|
@NotNull JavaArrayType arrayType,
|
||||||
|
@NotNull TypeUsage howThisTypeIsUsed,
|
||||||
|
@NotNull TypeVariableResolver typeVariableResolver,
|
||||||
|
boolean vararg
|
||||||
|
) {
|
||||||
|
JavaType componentType = arrayType.getComponentType();
|
||||||
|
if (componentType instanceof JavaPrimitiveType) {
|
||||||
|
JetType jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass(
|
||||||
|
"[" + ((JavaPrimitiveType) componentType).getCanonicalText());
|
||||||
|
if (jetType != null) {
|
||||||
|
return TypeUtils.makeNullable(jetType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variance projectionKind = arrayElementTypeProjectionKind(howThisTypeIsUsed, vararg);
|
||||||
|
TypeUsage howArgumentTypeIsUsed = vararg ? MEMBER_SIGNATURE_CONTRAVARIANT : TYPE_ARGUMENT;
|
||||||
|
|
||||||
|
JetType type = transformToType(componentType, howArgumentTypeIsUsed, typeVariableResolver);
|
||||||
|
return TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getArrayType(projectionKind, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static Variance arrayElementTypeProjectionKind(@NotNull TypeUsage howThisTypeIsUsed, boolean vararg) {
|
||||||
|
if (howThisTypeIsUsed == MEMBER_SIGNATURE_CONTRAVARIANT && !vararg) {
|
||||||
|
return OUT_VARIANCE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return INVARIANT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType transformVarargType(
|
||||||
|
@NotNull JavaArrayType type,
|
||||||
|
@NotNull TypeUsage howThisTypeIsUsed,
|
||||||
|
@NotNull TypeVariableResolver typeVariableResolver
|
||||||
|
) {
|
||||||
|
return transformArrayType(type, howThisTypeIsUsed, typeVariableResolver, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isRaw(@NotNull JavaClassType classType, boolean argumentsExpected) {
|
||||||
// The second option is needed because sometimes we get weird versions of JDK classes in the class path,
|
// The second option is needed because sometimes we get weird versions of JDK classes in the class path,
|
||||||
// such as collections with no generics, so the Java types are not raw, formally, but they don't match with
|
// such as collections with no generics, so the Java types are not raw, formally, but they don't match with
|
||||||
// their Kotlin analogs, so we treat them as raw to avoid exceptions
|
// their Kotlin analogs, so we treat them as raw to avoid exceptions
|
||||||
return classType.isRaw() || argumentsExpected && classType.getParameterCount() == 0;
|
return classType.getPsi().isRaw() || argumentsExpected && classType.getPsi().getParameterCount() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeUsage adjustTypeUsageWithMutabilityAnnotations(PsiModifierListOwner owner, TypeUsage originalTypeUsage) {
|
public static TypeUsage adjustTypeUsageWithMutabilityAnnotations(PsiModifierListOwner owner, TypeUsage originalTypeUsage) {
|
||||||
|
|||||||
+22
-17
@@ -26,7 +26,9 @@ import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
|||||||
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
|
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
|
||||||
import org.jetbrains.jet.lang.resolve.java.TypeUsage;
|
import org.jetbrains.jet.lang.resolve.java.TypeUsage;
|
||||||
import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver;
|
import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.java.structure.JavaArrayType;
|
||||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
|
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
|
||||||
|
import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
|
||||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaValueParameter;
|
import org.jetbrains.jet.lang.resolve.java.structure.JavaValueParameter;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
@@ -50,38 +52,41 @@ public final class JavaValueParameterResolver {
|
|||||||
@NotNull TypeVariableResolver typeVariableResolver,
|
@NotNull TypeVariableResolver typeVariableResolver,
|
||||||
boolean isVararg
|
boolean isVararg
|
||||||
) {
|
) {
|
||||||
// TODO: must be very slow, make it lazy?
|
|
||||||
Name name = getParameterName(i, parameter);
|
|
||||||
|
|
||||||
TypeUsage typeUsage = JavaTypeTransformer
|
TypeUsage typeUsage = JavaTypeTransformer
|
||||||
.adjustTypeUsageWithMutabilityAnnotations(parameter.getPsi(), TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT);
|
.adjustTypeUsageWithMutabilityAnnotations(parameter.getPsi(), TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT);
|
||||||
JetType outType = typeTransformer.transformToType(parameter.getType(), typeUsage, typeVariableResolver);
|
|
||||||
|
JavaType parameterType = parameter.getType();
|
||||||
|
|
||||||
JetType varargElementType;
|
JetType varargElementType;
|
||||||
|
JetType outType;
|
||||||
if (isVararg) {
|
if (isVararg) {
|
||||||
// TODO: test this code
|
// TODO: test this code
|
||||||
varargElementType = KotlinBuiltIns.getInstance().getArrayElementType(TypeUtils.makeNotNullable(outType));
|
assert parameterType instanceof JavaArrayType : "Vararg parameter should be an array: " + parameterType;
|
||||||
outType = TypeUtils.makeNotNullable(outType);
|
JetType arrayType = typeTransformer.transformVarargType(((JavaArrayType) parameterType), typeUsage, typeVariableResolver);
|
||||||
|
|
||||||
|
outType = TypeUtils.makeNotNullable(arrayType);
|
||||||
|
varargElementType = KotlinBuiltIns.getInstance().getArrayElementType(outType);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
JetType transformedType = typeTransformer.transformToType(parameterType, typeUsage, typeVariableResolver);
|
||||||
|
if (transformedType.isNullable()) {
|
||||||
|
PsiAnnotation notNullAnnotation = JavaAnnotationResolver.findAnnotationWithExternal(
|
||||||
|
parameter.getPsi(), JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
|
||||||
|
if (notNullAnnotation != null) {
|
||||||
|
transformedType = TypeUtils.makeNotNullable(transformedType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outType = transformedType;
|
||||||
varargElementType = null;
|
varargElementType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
JetType transformedType;
|
|
||||||
PsiAnnotation notNullAnnotation = JavaAnnotationResolver
|
|
||||||
.findAnnotationWithExternal(parameter.getPsi(), JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
|
|
||||||
if (notNullAnnotation != null) {
|
|
||||||
transformedType = TypeUtils.makeNullableAsSpecified(outType, false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
transformedType = outType;
|
|
||||||
}
|
|
||||||
return new ValueParameterDescriptorImpl(
|
return new ValueParameterDescriptorImpl(
|
||||||
containingDeclaration,
|
containingDeclaration,
|
||||||
i,
|
i,
|
||||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||||
name,
|
getParameterName(i, parameter), // TODO: must be very slow, make it lazy?
|
||||||
transformedType,
|
outType,
|
||||||
false,
|
false,
|
||||||
varargElementType
|
varargElementType
|
||||||
);
|
);
|
||||||
|
|||||||
+5
@@ -57,4 +57,9 @@ public class JavaClassType extends JavaType {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public String getPresentableText() {
|
||||||
|
return getPsi().getPresentableText();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -29,4 +29,9 @@ public class JavaPrimitiveType extends JavaType {
|
|||||||
public PsiPrimitiveType getPsi() {
|
public PsiPrimitiveType getPsi() {
|
||||||
return (PsiPrimitiveType) super.getPsi();
|
return (PsiPrimitiveType) super.getPsi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public String getCanonicalText() {
|
||||||
|
return getPsi().getCanonicalText();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.java.structure;
|
package org.jetbrains.jet.lang.resolve.java.structure;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiType;
|
||||||
import com.intellij.psi.PsiWildcardType;
|
import com.intellij.psi.PsiWildcardType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class JavaWildcardType extends JavaType {
|
public class JavaWildcardType extends JavaType {
|
||||||
public JavaWildcardType(@NotNull PsiWildcardType psiWildcardType) {
|
public JavaWildcardType(@NotNull PsiWildcardType psiWildcardType) {
|
||||||
@@ -29,4 +31,14 @@ public class JavaWildcardType extends JavaType {
|
|||||||
public PsiWildcardType getPsi() {
|
public PsiWildcardType getPsi() {
|
||||||
return (PsiWildcardType) super.getPsi();
|
return (PsiWildcardType) super.getPsi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public JavaType getBound() {
|
||||||
|
PsiType bound = getPsi().getBound();
|
||||||
|
return bound == null ? null : JavaType.create(bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExtends() {
|
||||||
|
return getPsi().isExtends();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user