From c1d40f1e1558c48624a5c2f336f1bc0e97eb9f8b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 31 Jul 2013 17:33:46 +0400 Subject: [PATCH] Introduce JavaClassifier JavaClassifier is a common type for JavaClass and JavaTypeParameter. In almost all of the places JavaClass remains to be JavaClass, except for the resolution result of JavaClassType, which can be a type parameter. Add an assertion that JavaClass is created only for a class and not for a type parameter. Delete different creations of JavaClass in 'idea' (where there can be a type parameter) by changing the interface of util functions. Delete JavaModifierListOwnerImpl, extract its methods into JavaElementUtil and use these implementations for every JavaModifierListOwner Continue refactoring JavaTypeTransformer to work with JavaType, not PsiType --- .../resolve/java/DescriptorResolverUtils.java | 15 +- .../java/resolver/JavaNamespaceResolver.java | 6 +- .../java/resolver/JavaSupertypeResolver.java | 6 +- .../java/resolver/JavaTypeTransformer.java | 200 ++++++++++-------- .../java/sam/SingleAbstractMethodUtils.java | 7 +- .../resolve/java/scope/JavaPackageScope.java | 2 +- .../resolve/java/structure/JavaClass.java | 39 +++- .../resolve/java/structure/JavaClassType.java | 4 +- .../java/structure/JavaClassifier.java | 43 ++++ ...istOwnerImpl.java => JavaElementUtil.java} | 55 ++--- .../resolve/java/structure/JavaField.java | 9 - .../java/structure/JavaMemberImpl.java | 42 +++- .../resolve/java/structure/JavaMethod.java | 14 +- .../java/structure/JavaModifierListOwner.java | 5 + .../java/structure/JavaTypeParameter.java | 23 +- .../caches/JetFromJavaDescriptorHelper.java | 3 +- .../completion/DescriptorLookupConverter.java | 5 +- .../completion/JetTypesCompletionHelper.java | 3 +- .../importOptimizer/JetImportOptimizer.java | 3 +- 19 files changed, 303 insertions(+), 181 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassifier.java rename compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/{JavaModifierListOwnerImpl.java => JavaElementUtil.java} (54%) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java index 7282344f297..01aff8833b1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java @@ -43,8 +43,9 @@ public final class DescriptorResolverUtils { private DescriptorResolverUtils() { } - public static boolean isCompiledKotlinPackageClass(@NotNull JavaClass javaClass) { - if (javaClass.getPsi() instanceof ClsClassImpl) { + public static boolean isCompiledKotlinPackageClass(@NotNull PsiClass psiClass) { + if (psiClass instanceof ClsClassImpl) { + JavaClass javaClass = new JavaClass(psiClass); FqName fqName = javaClass.getFqName(); if (fqName != null && PackageClassUtils.isPackageClassFqName(fqName)) { return hasAnnotation(javaClass, JvmAnnotationNames.KOTLIN_PACKAGE.getFqName()); @@ -53,9 +54,9 @@ public final class DescriptorResolverUtils { return false; } - public static boolean isCompiledKotlinClass(@NotNull JavaClass javaClass) { - if (javaClass.getPsi() instanceof ClsClassImpl) { - return hasAnnotation(javaClass, JvmAnnotationNames.KOTLIN_CLASS.getFqName()); + public static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) { + if (psiClass instanceof ClsClassImpl) { + return hasAnnotation(new JavaClass(psiClass), JvmAnnotationNames.KOTLIN_CLASS.getFqName()); } return false; } @@ -64,8 +65,8 @@ public final class DescriptorResolverUtils { return javaClass.findAnnotation(annotationFqName.asString()) != null; } - public static boolean isCompiledKotlinClassOrPackageClass(@NotNull JavaClass javaClass) { - return isCompiledKotlinClass(javaClass) || isCompiledKotlinPackageClass(javaClass); + public static boolean isCompiledKotlinClassOrPackageClass(@NotNull PsiClass psiClass) { + return isCompiledKotlinClass(psiClass) || isCompiledKotlinPackageClass(psiClass); } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java index 1eccaa4dc59..bf13edbd6e7 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java @@ -187,10 +187,10 @@ public final class JavaNamespaceResolver { return null; } - if (DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(javaClass)) { + PsiClass psiClass = javaClass.getPsi(); + if (DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(psiClass)) { return null; } - PsiClass psiClass = javaClass.getPsi(); if (!hasStaticMembers(psiClass)) { return null; } @@ -257,7 +257,7 @@ public final class JavaNamespaceResolver { Collection classes = DescriptorResolverUtils.filterDuplicateClasses(javaPackage.getClasses()); List result = new ArrayList(classes.size()); for (JavaClass javaClass : classes) { - if (DescriptorResolverUtils.isCompiledKotlinClass(javaClass)) { + if (DescriptorResolverUtils.isCompiledKotlinClass(javaClass.getPsi())) { result.add(javaClass.getName()); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaSupertypeResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaSupertypeResolver.java index 0a5b9c0fd66..aedfd65174b 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaSupertypeResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaSupertypeResolver.java @@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.resolve.java.TypeUsage; import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver; import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.java.structure.JavaClassType; +import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifier; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; @@ -116,9 +117,10 @@ public final class JavaSupertypeResolver { ) { List result = new ArrayList(supertypes.size()); for (JavaClassType type : supertypes) { - JavaClass resolved = type.resolve(); + JavaClassifier resolved = type.resolve(); if (resolved != null) { - FqName fqName = resolved.getFqName(); + assert resolved instanceof JavaClass : "Supertype should be a class: " + resolved; + FqName fqName = ((JavaClass) resolved).getFqName(); assert fqName != null : "Unresolved supertype: " + resolved; if (JvmAbi.JET_OBJECT.getFqName().equals(fqName)) { continue; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java index d69b003bb18..aefcb56a71e 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaTypeTransformer.java @@ -19,8 +19,10 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.*; +import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; @@ -89,7 +91,12 @@ public class JavaTypeTransformer { @NotNull TypeVariableResolver typeVariableResolver ) { if (type instanceof JavaClassType) { - return transformClassType((JavaClassType) type, howThisTypeIsUsed, typeVariableResolver); + JavaClassType classType = (JavaClassType) type; + JetType jetType = transformClassType(classType, howThisTypeIsUsed, typeVariableResolver); + if (jetType == null) { + return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText()); + } + return jetType; } else if (type instanceof JavaPrimitiveType) { String canonicalText = ((JavaPrimitiveType) type).getCanonicalText(); @@ -105,125 +112,130 @@ public class JavaTypeTransformer { } } - @NotNull + @Nullable 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()); + JavaClassifier javaClassifier = classType.resolve(); + if (javaClassifier == null) { + return null; + } + if (javaClassifier instanceof JavaTypeParameter) { + return transformTypeParameter((JavaTypeParameter) javaClassifier, howThisTypeIsUsed, typeVariableResolver); + } + else if (javaClassifier instanceof JavaClass) { + FqName fqName = ((JavaClass) javaClassifier).getFqName(); + assert fqName != null : "Class type should have a FQ name: " + javaClassifier; + return transformClassType(fqName, classType, howThisTypeIsUsed, typeVariableResolver); + } + else { + throw new UnsupportedOperationException("Unsupported classifier: " + javaClassifier); + } + } + + @Nullable + private JetType transformTypeParameter( + @NotNull JavaTypeParameter typeParameter, + @NotNull TypeUsage howThisTypeIsUsed, + @NotNull TypeVariableResolver typeVariableResolver + ) { + JavaTypeParameterListOwner owner = typeParameter.getOwner(); + if (owner instanceof JavaMethod && ((JavaMethod) owner).isConstructor()) { + Set supertypesJet = Sets.newHashSet(); + for (JavaClassType supertype : typeParameter.getUpperBounds()) { + supertypesJet.add(transformToType(supertype, UPPER_BOUND, typeVariableResolver)); + } + return TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet); } - PsiClass psiClass = javaClass.getPsi(); + TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName().asString()); - if (psiClass instanceof PsiTypeParameter) { - PsiTypeParameter typeParameter = (PsiTypeParameter) psiClass; + // In Java: ArrayList + // In Kotlin: ArrayList, not ArrayList + // nullability will be taken care of in individual member signatures + boolean nullable = !EnumSet.of(TYPE_ARGUMENT, UPPER_BOUND, SUPERTYPE_ARGUMENT).contains(howThisTypeIsUsed); - PsiTypeParameterListOwner typeParameterListOwner = typeParameter.getOwner(); - if (typeParameterListOwner instanceof PsiMethod) { - PsiMethod psiMethod = (PsiMethod) typeParameterListOwner; - if (psiMethod.isConstructor()) { - Set supertypesJet = Sets.newHashSet(); - for (PsiClassType supertype : typeParameter.getExtendsListTypes()) { - supertypesJet.add(transformToType(JavaType.create(supertype), UPPER_BOUND, typeVariableResolver)); - } - JetType type = TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet); - if (type == null) { - return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText()); - } - return type; - } - } + return TypeUtils.makeNullableIfNeeded(typeParameterDescriptor.getDefaultType(), nullable); + } - TypeParameterDescriptor typeParameterDescriptor = typeVariableResolver.getTypeVariable(typeParameter.getName()); + @Nullable + private JetType transformClassType( + @NotNull FqName fqName, + @NotNull JavaClassType classType, + @NotNull TypeUsage howThisTypeIsUsed, + @NotNull TypeVariableResolver typeVariableResolver + ) { + // 'L extends List' in Java is a List in Kotlin, not a List + boolean nullable = !EnumSet.of(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed); - // In Java: ArrayList - // In Kotlin: ArrayList, not ArrayList - // 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(); + ClassDescriptor classData = JavaToKotlinClassMap.getInstance().mapKotlinClass(fqName, howThisTypeIsUsed); + + if (classData == null) { + classData = classResolver.resolveClass(fqName, INCLUDE_KOTLIN_SOURCES); + } + if (classData == null) { + return null; + } + + List arguments = Lists.newArrayList(); + List 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 {} + // The upper bound is raw here, and we can't compute the projection: it would be infinite: + // C<*> = 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 { - // 'L extends List' in Java is a List in Kotlin, not a List - boolean nullable = !EnumSet.of(TYPE_ARGUMENT, SUPERTYPE_ARGUMENT, SUPERTYPE).contains(howThisTypeIsUsed); + PsiType[] psiArguments = classType.getPsi().getParameters(); - FqName fqName = javaClass.getFqName(); - assert fqName != null : "Class type should have a FQ name: " + javaClass; + 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 fqName: \n" + fqName); - 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()); - } - - List arguments = Lists.newArrayList(); - List 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 {} - // The upper bound is raw here, and we can't compute the projection: it would be infinite: - // C<*> = 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())); + arguments.add(new TypeProjection(ErrorUtils.createErrorType(parameter.getName().asString()))); } } else { - PsiType[] psiArguments = classType.getPsi().getParameters(); + for (int i = 0; i < parameters.size(); i++) { + PsiType psiArgument = psiArguments[i]; + TypeParameterDescriptor typeParameterDescriptor = parameters.get(i); - 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()); + TypeUsage howTheProjectionIsUsed = howThisTypeIsUsed == SUPERTYPE ? SUPERTYPE_ARGUMENT : TYPE_ARGUMENT; + TypeProjection typeProjection = transformToTypeProjection( + JavaType.create(psiArgument), typeParameterDescriptor, typeVariableResolver, + howTheProjectionIsUsed); - for (TypeParameterDescriptor parameter : parameters) { - arguments.add(new TypeProjection(ErrorUtils.createErrorType(parameter.getName().asString()))); + if (typeProjection.getProjectionKind() == typeParameterDescriptor.getVariance()) { + // remove redundant 'out' and 'in' + arguments.add(new TypeProjection(INVARIANT, typeProjection.getType())); } - } - 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( - 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); - } + else { + arguments.add(typeProjection); } } } - - return new JetTypeImpl( - Collections.emptyList(), - classData.getTypeConstructor(), - nullable, - arguments, - classData.getMemberScope(arguments)); } + + return new JetTypeImpl( + Collections.emptyList(), + classData.getTypeConstructor(), + nullable, + arguments, + classData.getMemberScope(arguments)); } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index 99e3eb1fa99..6b4c71c6b6a 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmByte import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil; import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.java.structure.JavaClassType; +import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifier; import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -378,10 +379,12 @@ public class SingleAbstractMethodUtils { private boolean find(@NotNull JavaClassType classType) { PsiClassType.ClassResolveResult classResolveResult = classType.getPsi().resolveGenerics(); PsiSubstitutor classSubstitutor = classResolveResult.getSubstitutor(); - JavaClass javaClass = classType.resolve(); - if (javaClass == null) { + JavaClassifier javaClassifier = classType.resolve(); + if (javaClassifier == null) { return false; // can't resolve class -> not a SAM interface } + assert javaClassifier instanceof JavaClass : "Classifier should be a class here: " + javaClassifier; + JavaClass javaClass = (JavaClass) javaClassifier; if (new FqName(CommonClassNames.JAVA_LANG_OBJECT).equals(javaClass.getFqName())) { return true; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaPackageScope.java index b36949fc1dc..612bda75993 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/JavaPackageScope.java @@ -97,7 +97,7 @@ public final class JavaPackageScope extends JavaBaseScope { } for (JavaClass javaClass : DescriptorResolverUtils.filterDuplicateClasses(javaPackage.getClasses())) { - if (DescriptorResolverUtils.isCompiledKotlinPackageClass(javaClass)) continue; + if (DescriptorResolverUtils.isCompiledKotlinPackageClass(javaClass.getPsi())) continue; if (isKotlinLightClass(javaClass)) continue; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java index 8ebbaf3e638..8b97125f72f 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java @@ -19,11 +19,13 @@ package org.jetbrains.jet.lang.resolve.java.structure; import com.intellij.psi.PsiAnnotation; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiModifierList; +import com.intellij.psi.PsiTypeParameter; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.Modality; +import org.jetbrains.jet.lang.descriptors.Visibility; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -31,15 +33,11 @@ import java.util.Collection; import static org.jetbrains.jet.lang.resolve.java.structure.JavaElementCollectionFromPsiArrayUtil.*; -public class JavaClass extends JavaModifierListOwnerImpl implements JavaNamedElement, JavaTypeParameterListOwner { +public class JavaClass extends JavaClassifier implements JavaNamedElement, JavaTypeParameterListOwner, JavaModifierListOwner { public JavaClass(@NotNull PsiClass psiClass) { super(psiClass); - } - - @NotNull - @Override - public PsiClass getPsi() { - return (PsiClass) super.getPsi(); + assert !(psiClass instanceof PsiTypeParameter) + : "PsiTypeParameter should be wrapped in JavaTypeParameter, not JavaClass: use JavaClassifier.create()"; } @NotNull @@ -136,4 +134,31 @@ public class JavaClass extends JavaModifierListOwnerImpl implements JavaNamedEle public Collection getConstructors() { return methods(getPsi().getConstructors()); } + + @Override + public boolean isAbstract() { + return JavaElementUtil.isAbstract(this); + } + + @Override + public boolean isStatic() { + return JavaElementUtil.isStatic(this); + } + + @Override + public boolean isFinal() { + return JavaElementUtil.isFinal(this); + } + + @NotNull + @Override + public Visibility getVisibility() { + return JavaElementUtil.getVisibility(this); + } + + @NotNull + @Override + public Collection getAnnotations() { + return JavaElementUtil.getAnnotations(this); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassType.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassType.java index 491b592792f..ba9f4f9c028 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassType.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassType.java @@ -39,9 +39,9 @@ public class JavaClassType extends JavaType { } @Nullable - public JavaClass resolve() { + public JavaClassifier resolve() { PsiClass psiClass = getPsi().resolve(); - return psiClass == null ? null : new JavaClass(psiClass); + return psiClass == null ? null : JavaClassifier.create(psiClass); } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassifier.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassifier.java new file mode 100644 index 00000000000..187e9c2a5c6 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClassifier.java @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2013 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.lang.resolve.java.structure; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiTypeParameter; +import org.jetbrains.annotations.NotNull; + +public abstract class JavaClassifier extends JavaElementImpl { + protected JavaClassifier(@NotNull PsiClass psiClass) { + super(psiClass); + } + + @NotNull + @Override + public PsiClass getPsi() { + return (PsiClass) super.getPsi(); + } + + @NotNull + public static JavaClassifier create(@NotNull PsiClass psiClass) { + if (psiClass instanceof PsiTypeParameter) { + return new JavaTypeParameter((PsiTypeParameter) psiClass); + } + else { + return new JavaClass(psiClass); + } + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwnerImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaElementUtil.java similarity index 54% rename from compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwnerImpl.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaElementUtil.java index aebabfd0234..3bf0167e759 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwnerImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaElementUtil.java @@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.java.structure; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierList; -import com.intellij.psi.PsiModifierListOwner; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.Visibilities; import org.jetbrains.jet.lang.descriptors.Visibility; @@ -29,51 +28,39 @@ import java.util.Collections; import static org.jetbrains.jet.lang.resolve.java.structure.JavaElementCollectionFromPsiArrayUtil.annotations; -public abstract class JavaModifierListOwnerImpl extends JavaElementImpl implements JavaModifierListOwner { - protected JavaModifierListOwnerImpl(@NotNull PsiModifierListOwner psiModifierListOwner) { - super(psiModifierListOwner); +/* package */ class JavaElementUtil { + private JavaElementUtil() { + } + + public static boolean isAbstract(@NotNull JavaModifierListOwner owner) { + return owner.getPsi().hasModifierProperty(PsiModifier.ABSTRACT); + } + + public static boolean isStatic(@NotNull JavaModifierListOwner owner) { + return owner.getPsi().hasModifierProperty(PsiModifier.STATIC); + } + + public static boolean isFinal(@NotNull JavaModifierListOwner owner) { + return owner.getPsi().hasModifierProperty(PsiModifier.FINAL); } @NotNull - @Override - public PsiModifierListOwner getPsi() { - return (PsiModifierListOwner) super.getPsi(); - } - - @Override - public boolean isAbstract() { - return getPsi().hasModifierProperty(PsiModifier.ABSTRACT); - } - - @Override - public boolean isStatic() { - return getPsi().hasModifierProperty(PsiModifier.STATIC); - } - - @Override - public boolean isFinal() { - return getPsi().hasModifierProperty(PsiModifier.FINAL); - } - - @NotNull - @Override - public Visibility getVisibility() { - if (getPsi().hasModifierProperty(PsiModifier.PUBLIC)) { + public static Visibility getVisibility(@NotNull JavaModifierListOwner owner) { + if (owner.getPsi().hasModifierProperty(PsiModifier.PUBLIC)) { return Visibilities.PUBLIC; } - if (getPsi().hasModifierProperty(PsiModifier.PRIVATE)) { + if (owner.getPsi().hasModifierProperty(PsiModifier.PRIVATE)) { return Visibilities.PRIVATE; } - if (getPsi().hasModifierProperty(PsiModifier.PROTECTED)) { - return isStatic() ? JavaVisibilities.PROTECTED_STATIC_VISIBILITY : JavaVisibilities.PROTECTED_AND_PACKAGE; + if (owner.getPsi().hasModifierProperty(PsiModifier.PROTECTED)) { + return owner.isStatic() ? JavaVisibilities.PROTECTED_STATIC_VISIBILITY : JavaVisibilities.PROTECTED_AND_PACKAGE; } return JavaVisibilities.PACKAGE_VISIBILITY; } @NotNull - @Override - public Collection getAnnotations() { - PsiModifierList modifierList = getPsi().getModifierList(); + public static Collection getAnnotations(@NotNull JavaModifierListOwner owner) { + PsiModifierList modifierList = owner.getPsi().getModifierList(); if (modifierList != null) { return annotations(modifierList.getAnnotations()); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaField.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaField.java index 00e78c18a37..bdea076189d 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaField.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaField.java @@ -16,11 +16,9 @@ package org.jetbrains.jet.lang.resolve.java.structure; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiEnumConstant; import com.intellij.psi.PsiField; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class JavaField extends JavaMemberImpl { public JavaField(@NotNull PsiField psiField) { @@ -33,13 +31,6 @@ public class JavaField extends JavaMemberImpl { return (PsiField) super.getPsi(); } - @Nullable - @Override - public JavaClass getContainingClass() { - PsiClass psiClass = getPsi().getContainingClass(); - return psiClass == null ? null : new JavaClass(psiClass); - } - public boolean isEnumEntry() { return getPsi() instanceof PsiEnumConstant; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMemberImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMemberImpl.java index 21d8dfd7653..9277c7c6ff0 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMemberImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMemberImpl.java @@ -16,11 +16,16 @@ package org.jetbrains.jet.lang.resolve.java.structure; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMember; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.Visibility; import org.jetbrains.jet.lang.resolve.name.Name; -public abstract class JavaMemberImpl extends JavaModifierListOwnerImpl implements JavaMember { +import java.util.Collection; + +public abstract class JavaMemberImpl extends JavaElementImpl implements JavaMember, JavaModifierListOwner { protected JavaMemberImpl(@NotNull PsiMember psiMember) { super(psiMember); } @@ -38,4 +43,39 @@ public abstract class JavaMemberImpl extends JavaModifierListOwnerImpl implement assert name != null : "Member must have a name: " + getPsi(); return Name.identifier(name); } + + // TODO: NotNull? + @Nullable + @Override + public JavaClass getContainingClass() { + PsiClass psiClass = getPsi().getContainingClass(); + return psiClass == null ? null : new JavaClass(psiClass); + } + + @Override + public boolean isAbstract() { + return JavaElementUtil.isAbstract(this); + } + + @Override + public boolean isStatic() { + return JavaElementUtil.isStatic(this); + } + + @Override + public boolean isFinal() { + return JavaElementUtil.isFinal(this); + } + + @NotNull + @Override + public Visibility getVisibility() { + return JavaElementUtil.getVisibility(this); + } + + @NotNull + @Override + public Collection getAnnotations() { + return JavaElementUtil.getAnnotations(this); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMethod.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMethod.java index 60675098dba..ca695bf71e1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMethod.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaMethod.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.resolve.java.structure; import com.intellij.psi.PsiAnnotationMethod; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; @@ -46,14 +45,6 @@ public class JavaMethod extends JavaMemberImpl implements JavaTypeParameterListO return Name.identifier(getPsi().getName()); } - // TODO: NotNull? - @Nullable - @Override - public JavaClass getContainingClass() { - PsiClass psiClass = getPsi().getContainingClass(); - return psiClass == null ? null : new JavaClass(psiClass); - } - @NotNull @Override public Collection getTypeParameters() { @@ -83,4 +74,9 @@ public class JavaMethod extends JavaMemberImpl implements JavaTypeParameterListO public boolean isVararg() { return getPsi().isVarArgs(); } + + public boolean isConstructor() { + // TODO: class JavaConstructor extends JavaMethod + return getPsi().isConstructor(); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwner.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwner.java index fa51410262a..f508497dab1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwner.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaModifierListOwner.java @@ -16,12 +16,17 @@ package org.jetbrains.jet.lang.resolve.java.structure; +import com.intellij.psi.PsiModifierListOwner; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.Visibility; import java.util.Collection; public interface JavaModifierListOwner extends JavaElement { + @NotNull + @Override + PsiModifierListOwner getPsi(); + boolean isAbstract(); boolean isStatic(); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeParameter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeParameter.java index 67129603884..b1fea7354ea 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeParameter.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeParameter.java @@ -16,15 +16,19 @@ package org.jetbrains.jet.lang.resolve.java.structure; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.PsiTypeParameterListOwner; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.name.Name; import java.util.Collection; import static org.jetbrains.jet.lang.resolve.java.structure.JavaElementCollectionFromPsiArrayUtil.classTypes; -public class JavaTypeParameter extends JavaElementImpl implements JavaNamedElement { +public class JavaTypeParameter extends JavaClassifier implements JavaNamedElement { public JavaTypeParameter(@NotNull PsiTypeParameter psiTypeParameter) { super(psiTypeParameter); } @@ -49,4 +53,21 @@ public class JavaTypeParameter extends JavaElementImpl implements JavaNamedEleme public Collection getUpperBounds() { return classTypes(getPsi().getExtendsList().getReferencedTypes()); } + + @Nullable + public JavaTypeParameterListOwner getOwner() { + PsiTypeParameterListOwner owner = getPsi().getOwner(); + // TODO: a separate factory for such things + if (owner instanceof PsiMethod) { + return new JavaMethod((PsiMethod) owner); + } + else if (owner instanceof PsiClass) { + return new JavaClass((PsiClass) owner); + } + else if (owner != null) { + throw new UnsupportedOperationException("Unsupported type parameter list owner: " + owner); + } + + return null; + } } diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index 92b4831a0a3..59cb0c1e830 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -30,7 +30,6 @@ import org.jetbrains.jet.descriptors.serialization.*; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; import org.jetbrains.jet.lang.resolve.java.resolver.KotlinClassFileHeader; -import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.util.QualifiedNamesUtil; @@ -139,7 +138,7 @@ public class JetFromJavaDescriptorHelper { FqName classFQN = new FqName(qualifiedName); - if (DescriptorResolverUtils.isCompiledKotlinPackageClass(new JavaClass(containingClass))) { + if (DescriptorResolverUtils.isCompiledKotlinPackageClass(containingClass)) { FqName classParentFQN = QualifiedNamesUtil.withoutLastSegment(classFQN); return QualifiedNamesUtil.combine(classParentFQN, Name.identifier(method.getName())); } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java b/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java index d9b34800bed..5c051a6dd4f 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/DescriptorLookupConverter.java @@ -33,7 +33,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; -import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -130,14 +129,14 @@ public final class DescriptorLookupConverter { private static LookupElement createJavaLookupElementIfPossible(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { if (declaration instanceof PsiClass) { PsiClass psiClass = (PsiClass) declaration; - if (!DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(new JavaClass(psiClass))) { + if (!DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(psiClass)) { return setCustomInsertHandler(new JavaPsiClassReferenceElement(psiClass)); } } if (declaration instanceof PsiMember) { PsiClass containingClass = ((PsiMember) declaration).getContainingClass(); - if (containingClass != null && !DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(new JavaClass(containingClass))) { + if (containingClass != null && !DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(containingClass)) { if (declaration instanceof PsiMethod) { InsertHandler handler = getInsertHandler(descriptor); assert handler != null: "Special kotlin handler is expected for function: " + declaration.getText() + " and descriptor" + DescriptorRenderer.TEXT.render(descriptor); diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java b/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java index f1f4ec69b31..c6e5867491d 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java @@ -27,7 +27,6 @@ import org.jetbrains.jet.asJava.KotlinLightClass; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; -import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -93,7 +92,7 @@ public class JetTypesCompletionHelper { return true; } - if (DescriptorResolverUtils.isCompiledKotlinClass(new JavaClass(aClass))) { + if (DescriptorResolverUtils.isCompiledKotlinClass(aClass)) { if (JetFromJavaDescriptorHelper.getCompiledClassKind(aClass) != ClassKind.CLASS_OBJECT) { String qualifiedName = aClass.getQualifiedName(); if (qualifiedName != null) { diff --git a/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java b/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java index a0e06e63333..5976d749118 100644 --- a/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java +++ b/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java @@ -32,7 +32,6 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.ImportPath; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; -import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.Name; @@ -284,7 +283,7 @@ public class JetImportOptimizer implements ImportOptimizer { if (memberName == null) { return null; } - if (DescriptorResolverUtils.isCompiledKotlinPackageClass(new JavaClass(containingClass))) { + if (DescriptorResolverUtils.isCompiledKotlinPackageClass(containingClass)) { return QualifiedNamesUtil.combine(classFQN.parent(), Name.identifier(memberName)); } else {