diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java index 78e0e13086b..0265534a097 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java @@ -29,11 +29,7 @@ import org.jetbrains.jet.lang.resolve.name.LabelName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Class static of instance members. @@ -51,9 +47,6 @@ public class JavaClassMembersScope extends JavaClassOrPackageScope { if (resolverScopeData.psiClass == null) { throw new IllegalArgumentException("must pass PsiClass here"); } - if (resolverScopeData.staticMembers) { - throw new IllegalArgumentException("static members should be resolved using " + JavaPackageScope.class); - } } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 70f65f60328..13ec0eb09f5 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -35,7 +35,9 @@ import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation; import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithFlags; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.*; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.rt.signature.JetSignatureAdapter; @@ -47,6 +49,8 @@ import org.jetbrains.jet.utils.ExceptionUtils; import javax.inject.Inject; import java.util.*; +import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValueOfMethod; +import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValuesMethod; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName; /** @@ -198,6 +202,18 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes } + + static class ResolverEnumClassObjectClassData extends ResolverClassData { + + protected ResolverEnumClassObjectClassData( + @Nullable PsiClass psiClass, + @NotNull FqName fqName, + @NotNull ClassDescriptorFromJvmBytecode descriptor + ) { + super(psiClass, null, fqName, true, descriptor); + } + } + /** Either package or class with static members */ static class ResolverNamespaceData extends ResolverScopeData { private final NamespaceDescriptor namespaceDescriptor; @@ -540,13 +556,17 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes */ @Nullable private MutableClassDescriptorLite createClassObjectDescriptor(@NotNull ClassDescriptor containing, @NotNull PsiClass psiClass) { + checkPsiClassIsNotJet(psiClass); + + if (psiClass.isEnum()) { + return createClassObjectDescriptorForEnum(containing, psiClass); + } + PsiClass classObjectPsiClass = getInnerClassClassObject(psiClass); if (classObjectPsiClass == null) { return null; } - checkPsiClassIsNotJet(psiClass); - FqName fqName = new FqName(classObjectPsiClass.getQualifiedName()); ResolverClassData classData = new ClassDescriptorFromJvmBytecode( containing, ClassKind.OBJECT, classObjectPsiClass, fqName, this) @@ -554,15 +574,47 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes classDescriptorCache.put(fqName, classData); - classData.classDescriptor.setSupertypes(getSupertypes(new PsiClassWrapper(classObjectPsiClass), classData, new ArrayList(0))); - classData.classDescriptor.setName(getClassObjectName(containing.getName())); - classData.classDescriptor.setModality(Modality.FINAL); - classData.classDescriptor.setVisibility(containing.getVisibility()); - classData.classDescriptor.setTypeParameterDescriptors(new ArrayList(0)); - classData.classDescriptor.createTypeConstructor(); - classData.classDescriptor.setScopeForMemberLookup(new JavaClassMembersScope(semanticServices, classData)); + ClassDescriptorFromJvmBytecode classObjectDescriptor = classData.classDescriptor; + classObjectDescriptor.setSupertypes( + getSupertypes(new PsiClassWrapper(classObjectPsiClass), classData, new ArrayList(0))); + setUpClassObjectDescriptor(containing, fqName, classData, getClassObjectName(containing.getName())); + return classObjectDescriptor; + } - return classData.classDescriptor; + @NotNull + private MutableClassDescriptorLite createClassObjectDescriptorForEnum(@NotNull ClassDescriptor containing, @NotNull PsiClass psiClass) { + String psiClassQualifiedName = psiClass.getQualifiedName(); + assert psiClassQualifiedName != null : "Reading java class with no qualified name"; + FqName fqName = new FqName(psiClassQualifiedName + "." + getClassObjectName(psiClass.getName()).getName()); + ClassDescriptorFromJvmBytecode classObjectDescriptor = new ClassDescriptorFromJvmBytecode( + containing, ClassKind.OBJECT, psiClass, fqName, this); + + ResolverEnumClassObjectClassData data = new ResolverEnumClassObjectClassData(psiClass, fqName, classObjectDescriptor); + setUpClassObjectDescriptor(containing, fqName, data, getClassObjectName(containing.getName().getName())); + + classObjectDescriptor.getBuilder().addFunctionDescriptor(createEnumClassObjectValuesMethod(classObjectDescriptor, trace)); + classObjectDescriptor.getBuilder().addFunctionDescriptor(createEnumClassObjectValueOfMethod(classObjectDescriptor, trace)); + + return classObjectDescriptor; + } + + private void setUpClassObjectDescriptor( + @NotNull ClassDescriptor containing, + @NotNull FqName fqName, + @NotNull ResolverClassData data, + @NotNull Name classObjectName + ) { + ClassDescriptorFromJvmBytecode classDescriptor = data.classDescriptor; + classDescriptorCache.put(fqName, data); + classDescriptor.setName(classObjectName); + classDescriptor.setModality(Modality.FINAL); + classDescriptor.setVisibility(containing.getVisibility()); + classDescriptor.setTypeParameterDescriptors(Collections.emptyList()); + classDescriptor.createTypeConstructor(); + JavaClassMembersScope classMembersScope = new JavaClassMembersScope(semanticServices, data); + WritableScopeImpl writableScope = new WritableScopeImpl(classMembersScope, classDescriptor, RedeclarationHandler.THROW_EXCEPTION, fqName.getFqName()); + writableScope.changeLockLevel(WritableScope.LockLevel.BOTH); + classDescriptor.setScopeForMemberLookup(writableScope); } static boolean isJavaLangObject(JetType type) { @@ -756,7 +808,7 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes } psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE); - if (psiClass != null) { + if (psiClass != null && !psiClass.isEnum()) { trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, ns, JavaNamespaceKind.CLASS_STATICS); break lookingForPsi; } @@ -1106,8 +1158,11 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes visibility = resolveVisibility(anyMember.getMember().psiMember, ((PsiMethodWrapper) members.getter.getMember()).getJetMethod()); } + + DeclarationDescriptor realOwner = getRealOwner(owner, scopeData, anyMember.getMember().isStatic()); + PropertyDescriptor propertyDescriptor = new PropertyDescriptor( - owner, + realOwner, resolveAnnotations(anyMember.getMember().psiMember), resolveModality(anyMember.getMember(), isFinal), visibility, @@ -1194,7 +1249,7 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes propertyDescriptor.setType( propertyType, typeParameters, - DescriptorUtils.getExpectedThisObjectIfNeeded(owner), + DescriptorUtils.getExpectedThisObjectIfNeeded(realOwner), receiverType ); if (getterDescriptor != null) { @@ -1236,6 +1291,21 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes namedMembers.propertyDescriptors = properties; } + @NotNull + private ClassOrNamespaceDescriptor getRealOwner( + @NotNull ClassOrNamespaceDescriptor owner, + @NotNull ResolverScopeData scopeData, + boolean isStatic + ) { + boolean isEnum = scopeData.psiClass.isEnum(); + if (isEnum && isStatic) { + return resolveClass(new FqName(scopeData.psiClass.getQualifiedName())).getClassObjectDescriptor(); + } + else { + return owner; + } + } + private void resolveNamedGroupFunctions(@NotNull ClassOrNamespaceDescriptor owner, PsiClass psiClass, TypeSubstitutor typeSubstitutorForGenericSuperclasses, NamedMembers namedMembers, Name methodName, ResolverScopeData scopeData) { if (namedMembers.functionDescriptors != null) { @@ -1248,9 +1318,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes Set functionsFromCurrent = Sets.newHashSet(); for (PsiMethodWrapper method : namedMembers.methods) { - FunctionDescriptorImpl function = resolveMethodToFunctionDescriptor(psiClass, method, scopeData, tempTrace); + SimpleFunctionDescriptor function = resolveMethodToFunctionDescriptor(psiClass, method, scopeData, tempTrace); if (function != null) { - functionsFromCurrent.add((SimpleFunctionDescriptor) function); + functionsFromCurrent.add(function); } } @@ -1276,6 +1346,14 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes functions.addAll(functionsFromCurrent); + if (isEnumClassObject(owner)) { + for (FunctionDescriptor functionDescriptor : Lists.newArrayList(functions)) { + if (isEnumSpecialMethod(functionDescriptor)) { + functions.remove(functionDescriptor); + } + } + } + try { namedMembers.functionDescriptors = functions; tempTrace.commit(); @@ -1369,7 +1447,7 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes } @Nullable - private FunctionDescriptorImpl resolveMethodToFunctionDescriptor( + private SimpleFunctionDescriptor resolveMethodToFunctionDescriptor( @NotNull final PsiClass psiClass, final PsiMethodWrapper method, @NotNull ResolverScopeData scopeData, BindingTrace tempTrace) { @@ -1432,11 +1510,27 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes BindingContextUtils.recordFunctionDeclarationToDescriptor(tempTrace, method.getPsiMethod(), functionDescriptorImpl); - FunctionDescriptor substitutedFunctionDescriptor = functionDescriptorImpl; if (method.getPsiMethod().getContainingClass() != psiClass && !method.isStatic()) { throw new IllegalStateException("non-static method in subclass"); } - return (FunctionDescriptorImpl) substitutedFunctionDescriptor; + return functionDescriptorImpl; + } + + private boolean isEnumSpecialMethod(@NotNull FunctionDescriptor functionDescriptor) { + List methodTypeParameters = functionDescriptor.getValueParameters(); + String methodName = functionDescriptor.getName().getName(); + JetType nullableString = TypeUtils.makeNullable(JetStandardLibrary.getInstance().getStringType()); + if (methodName.equals("valueOf") && methodTypeParameters.size() == 1 + && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString)) { + return true; + } + return (methodName.equals("values") && methodTypeParameters.isEmpty()); + } + + private static boolean isEnumClassObject(@NotNull DeclarationDescriptor classObjectDescriptor) { + DeclarationDescriptor containingDeclaration = classObjectDescriptor.getContainingDeclaration(); + return ((containingDeclaration instanceof ClassDescriptor) && + ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.ENUM_CLASS); } private List resolveAnnotations(PsiModifierListOwner owner, @NotNull List tasks) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java index a6a7fc17fb7..8587eeaa765 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java @@ -64,6 +64,10 @@ class JavaDescriptorResolverHelper { } private boolean includeMember(PsiMemberWrapper member) { + if (psiClass.getPsiClass().isEnum() && staticMembers) { + return member.isStatic(); + } + if (member.isStatic() != staticMembers) { return false; } @@ -80,20 +84,22 @@ class JavaDescriptorResolverHelper { } private void processFields() { - if (!kotlin) { - for (PsiField field0 : psiClass.getPsiClass().getAllFields()) { - PsiFieldWrapper field = new PsiFieldWrapper(field0); + // Hack to load static members for enum class loaded from class file + if (kotlin && !psiClass.getPsiClass().isEnum()) { + return; + } + for (PsiField field0 : psiClass.getPsiClass().getAllFields()) { + PsiFieldWrapper field = new PsiFieldWrapper(field0); - // group must be created even for excluded field - NamedMembers namedMembers = getNamedMembers(Name.identifier(field.getName())); + // group must be created even for excluded field + NamedMembers namedMembers = getNamedMembers(Name.identifier(field.getName())); - if (!includeMember(field)) { - continue; - } - - TypeSource type = new TypeSource("", field.getType(), field0); - namedMembers.addPropertyAccessor(new PropertyAccessorData(field, type, null)); + if (!includeMember(field)) { + continue; } + + TypeSource type = new TypeSource("", field.getType(), field0); + namedMembers.addPropertyAccessor(new PropertyAccessorData(field, type, null)); } }