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 60619cbd66a..ff85f2143ed 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 @@ -42,6 +42,7 @@ import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSign import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithFlags; import org.jetbrains.jet.lang.resolve.java.resolver.ClassResolver; +import org.jetbrains.jet.lang.resolve.java.resolver.ConstructorResolver; import org.jetbrains.jet.lang.resolve.java.resolver.PropertiesResolver; import org.jetbrains.jet.lang.resolve.java.scope.JavaClassMembersScope; import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScope; @@ -69,7 +70,8 @@ import org.jetbrains.jet.rt.signature.JetSignatureVisitor; import javax.inject.Inject; import java.util.*; -import static org.jetbrains.jet.lang.resolve.DescriptorResolver.*; +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; /** @@ -125,6 +127,7 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes private JavaDescriptorSignatureResolver javaDescriptorSignatureResolver; private PropertiesResolver propertiesResolver = new PropertiesResolver(this); private final ClassResolver classResolver = new ClassResolver(this); + private final ConstructorResolver constructorResolver = new ConstructorResolver(this); @Inject public void setProject(Project project) { @@ -196,142 +199,16 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes @NotNull public Collection resolveConstructors(@NotNull ResolverClassData classData) { - Collection constructors = Lists.newArrayList(); - PsiClass psiClass = classData.getPsiClass(); - - ClassDescriptorFromJvmBytecode containingClass = classData.getClassDescriptor(); - assert psiClass != null; - TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver( - containingClass, "class " + psiClass.getQualifiedName()); - - List typeParameters = containingClass.getTypeConstructor().getParameters(); - - PsiMethod[] psiConstructors = psiClass.getConstructors(); - - boolean isStatic = psiClass.hasModifierProperty(PsiModifier.STATIC); - if (containingClass.getKind() == ClassKind.OBJECT || containingClass.getKind() == ClassKind.CLASS_OBJECT) { - constructors.add(createPrimaryConstructorForObject(containingClass)); - } - else if (psiConstructors.length == 0) { - if (trace.get(BindingContext.CONSTRUCTOR, psiClass) != null) { - constructors.add(trace.get(BindingContext.CONSTRUCTOR, psiClass)); - } - else { - // We need to create default constructors for classes and abstract classes. - // Example: - // class Kotlin() : Java() {} - // abstract public class Java {} - if (!psiClass.isInterface()) { - ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( - containingClass, - Collections.emptyList(), - false); - constructorDescriptor.initialize(typeParameters, Collections.emptyList(), containingClass - .getVisibility(), isStatic); - constructors.add(constructorDescriptor); - trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor); - } - if (psiClass.isAnnotationType()) { - // A constructor for an annotation type takes all the "methods" in the @interface as parameters - ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( - containingClass, - Collections.emptyList(), - false); - - List valueParameters = Lists.newArrayList(); - PsiMethod[] methods = psiClass.getMethods(); - for (int i = 0; i < methods.length; i++) { - PsiMethod method = methods[i]; - if (method instanceof PsiAnnotationMethod) { - PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod) method; - assert annotationMethod.getParameterList().getParameters().length == 0; - - PsiType returnType = annotationMethod.getReturnType(); - - // We take the following heuristical convention: - // if the last method of the @interface is an array, we convert it into a vararg - JetType varargElementType = null; - if (i == methods.length - 1 && (returnType instanceof PsiArrayType)) { - varargElementType = semanticServices.getTypeTransformer().transformToType(((PsiArrayType) returnType).getComponentType(), resolverForTypeParameters); - } - - assert returnType != null; - valueParameters.add(new ValueParameterDescriptorImpl( - constructorDescriptor, - i, - Collections.emptyList(), - Name.identifier(method.getName()), - false, - semanticServices.getTypeTransformer().transformToType(returnType, resolverForTypeParameters), - annotationMethod.getDefaultValue() != null, - varargElementType)); - } - } - - constructorDescriptor.initialize(typeParameters, valueParameters, containingClass.getVisibility(), isStatic); - constructors.add(constructorDescriptor); - trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor); - } - } - } - else { - for (PsiMethod psiConstructor : psiConstructors) { - ConstructorDescriptor constructor = resolveConstructor(psiClass, classData, isStatic, psiConstructor); - if (constructor != null) { - constructors.add(constructor); - } - } - } - - for (ConstructorDescriptor constructor : constructors) { - ((ConstructorDescriptorImpl) constructor).setReturnType(containingClass.getDefaultType()); - } - - return constructors; + return constructorResolver.resolveConstructors(classData); } @Nullable private ConstructorDescriptor resolveConstructor(PsiClass psiClass, ResolverClassData classData, boolean aStatic, PsiMethod psiConstructor) { - PsiMethodWrapper constructor = new PsiMethodWrapper(psiConstructor); //noinspection deprecation - if (constructor.getJetConstructor().hidden()) { - return null; - } - if (trace.get(BindingContext.CONSTRUCTOR, psiConstructor) != null) { - return trace.get(BindingContext.CONSTRUCTOR, psiConstructor); - } - - ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( - classData.getClassDescriptor(), - Collections.emptyList(), // TODO - false); - - String context = "constructor of class " + psiClass.getQualifiedName(); - ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors( - constructorDescriptor, constructor.getParameters(), - TypeVariableResolvers.classTypeVariableResolver(classData.getClassDescriptor(), context)); - - if (valueParameterDescriptors.receiverType != null) { - throw new IllegalStateException(); - } - - AlternativeMethodSignatureData alternativeMethodSignatureData = - new AlternativeMethodSignatureData(constructor, valueParameterDescriptors, null, Collections.emptyList()); - if (alternativeMethodSignatureData.isAnnotated() && !alternativeMethodSignatureData.hasErrors()) { - valueParameterDescriptors = alternativeMethodSignatureData.getValueParameters(); - } - else if (alternativeMethodSignatureData.hasErrors()) { - trace.record(BindingContext.ALTERNATIVE_SIGNATURE_DATA_ERROR, constructorDescriptor, alternativeMethodSignatureData.getError()); - } - - constructorDescriptor.initialize(classData.getClassDescriptor().getTypeConstructor().getParameters(), - valueParameterDescriptors.descriptors, - resolveVisibility(psiConstructor, constructor.getJetConstructor()), aStatic); - trace.record(BindingContext.CONSTRUCTOR, psiConstructor, constructorDescriptor); - return constructorDescriptor; + return constructorResolver.resolveConstructor(psiClass, classData, aStatic, psiConstructor); } public static void checkPsiClassIsNotJet(PsiClass psiClass) { @@ -945,8 +822,10 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes } } - private ValueParameterDescriptors resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, - List parameters, TypeVariableResolver typeVariableResolver) { + public ValueParameterDescriptors resolveParameterDescriptors( + DeclarationDescriptor containingDeclaration, + List parameters, TypeVariableResolver typeVariableResolver + ) { List result = new ArrayList(); JetType receiverType = null; int indexDelta = 0; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/ConstructorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/ConstructorResolver.java new file mode 100644 index 00000000000..b67e8c2bbeb --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/ConstructorResolver.java @@ -0,0 +1,197 @@ +/* + * 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.lang.resolve.java.resolver; + +import com.google.common.collect.Lists; +import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorResolver; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolveData; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; +import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver; +import org.jetbrains.jet.lang.resolve.java.TypeVariableResolvers; +import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; +import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData; +import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class ConstructorResolver { + private final JavaDescriptorResolver javaDescriptorResolver; + + public ConstructorResolver(JavaDescriptorResolver javaDescriptorResolver) { + this.javaDescriptorResolver = javaDescriptorResolver; + } + + @NotNull + public Collection resolveConstructors(@NotNull JavaDescriptorResolveData.ResolverClassData classData) { + Collection constructors = Lists.newArrayList(); + + PsiClass psiClass = classData.getPsiClass(); + + ClassDescriptorFromJvmBytecode containingClass = classData.getClassDescriptor(); + assert psiClass != null; + TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver( + containingClass, "class " + psiClass.getQualifiedName()); + + List typeParameters = containingClass.getTypeConstructor().getParameters(); + + PsiMethod[] psiConstructors = psiClass.getConstructors(); + + boolean isStatic = psiClass.hasModifierProperty(PsiModifier.STATIC); + if (containingClass.getKind() == ClassKind.OBJECT || containingClass.getKind() == ClassKind.CLASS_OBJECT) { + constructors.add(DescriptorResolver.createPrimaryConstructorForObject(containingClass)); + } + else if (psiConstructors.length == 0) { + if (javaDescriptorResolver.getTrace().get(BindingContext.CONSTRUCTOR, psiClass) != null) { + constructors.add(javaDescriptorResolver.getTrace().get(BindingContext.CONSTRUCTOR, psiClass)); + } + else { + // We need to create default constructors for classes and abstract classes. + // Example: + // class Kotlin() : Java() {} + // abstract public class Java {} + if (!psiClass.isInterface()) { + ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( + containingClass, + Collections.emptyList(), + false); + constructorDescriptor.initialize(typeParameters, Collections.emptyList(), containingClass + .getVisibility(), isStatic); + constructors.add(constructorDescriptor); + javaDescriptorResolver.getTrace().record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor); + } + if (psiClass.isAnnotationType()) { + // A constructor for an annotation type takes all the "methods" in the @interface as parameters + ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( + containingClass, + Collections.emptyList(), + false); + + List valueParameters = Lists.newArrayList(); + PsiMethod[] methods = psiClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + PsiMethod method = methods[i]; + if (method instanceof PsiAnnotationMethod) { + PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod) method; + assert annotationMethod.getParameterList().getParameters().length == 0; + + PsiType returnType = annotationMethod.getReturnType(); + + // We take the following heuristical convention: + // if the last method of the @interface is an array, we convert it into a vararg + JetType varargElementType = null; + if (i == methods.length - 1 && (returnType instanceof PsiArrayType)) { + varargElementType = javaDescriptorResolver.getSemanticServices().getTypeTransformer() + .transformToType(((PsiArrayType) returnType).getComponentType(), resolverForTypeParameters); + } + + assert returnType != null; + valueParameters.add(new ValueParameterDescriptorImpl( + constructorDescriptor, + i, + Collections.emptyList(), + Name.identifier(method.getName()), + false, + javaDescriptorResolver.getSemanticServices().getTypeTransformer() + .transformToType(returnType, resolverForTypeParameters), + annotationMethod.getDefaultValue() != null, + varargElementType)); + } + } + + constructorDescriptor.initialize(typeParameters, valueParameters, containingClass.getVisibility(), isStatic); + constructors.add(constructorDescriptor); + javaDescriptorResolver.getTrace().record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor); + } + } + } + else { + for (PsiMethod psiConstructor : psiConstructors) { + ConstructorDescriptor constructor = resolveConstructor(psiClass, classData, isStatic, psiConstructor); + if (constructor != null) { + constructors.add(constructor); + } + } + } + + for (ConstructorDescriptor constructor : constructors) { + ((ConstructorDescriptorImpl) constructor).setReturnType(containingClass.getDefaultType()); + } + + return constructors; + } + + @Nullable + public ConstructorDescriptor resolveConstructor( + PsiClass psiClass, + JavaDescriptorResolveData.ResolverClassData classData, + boolean aStatic, + PsiMethod psiConstructor + ) { + PsiMethodWrapper constructor = new PsiMethodWrapper(psiConstructor); + + //noinspection deprecation + if (constructor.getJetConstructor().hidden()) { + return null; + } + + if (javaDescriptorResolver.getTrace().get(BindingContext.CONSTRUCTOR, psiConstructor) != null) { + return javaDescriptorResolver.getTrace().get(BindingContext.CONSTRUCTOR, psiConstructor); + } + + ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( + classData.getClassDescriptor(), + Collections.emptyList(), // TODO + false); + + String context = "constructor of class " + psiClass.getQualifiedName(); + JavaDescriptorResolver.ValueParameterDescriptors valueParameterDescriptors = javaDescriptorResolver.resolveParameterDescriptors( + constructorDescriptor, constructor.getParameters(), + TypeVariableResolvers.classTypeVariableResolver(classData.getClassDescriptor(), context)); + + if (valueParameterDescriptors.getReceiverType() != null) { + throw new IllegalStateException(); + } + + AlternativeMethodSignatureData alternativeMethodSignatureData = + new AlternativeMethodSignatureData(constructor, valueParameterDescriptors, null, + Collections.emptyList()); + if (alternativeMethodSignatureData.isAnnotated() && !alternativeMethodSignatureData.hasErrors()) { + valueParameterDescriptors = alternativeMethodSignatureData.getValueParameters(); + } + else if (alternativeMethodSignatureData.hasErrors()) { + javaDescriptorResolver.getTrace().record(BindingContext.ALTERNATIVE_SIGNATURE_DATA_ERROR, constructorDescriptor, + alternativeMethodSignatureData.getError()); + } + + constructorDescriptor.initialize(classData.getClassDescriptor().getTypeConstructor().getParameters(), + valueParameterDescriptors.getDescriptors(), + JavaDescriptorResolver.resolveVisibility(psiConstructor, constructor.getJetConstructor()), + aStatic); + javaDescriptorResolver.getTrace().record(BindingContext.CONSTRUCTOR, psiConstructor, constructorDescriptor); + return constructorDescriptor; + } +} \ No newline at end of file