Refactor JavaConstructorResolver
Extract methods, fix warnings, use JavaClass/JavaMethod instead of Psi
This commit is contained in:
+83
-72
@@ -17,7 +17,8 @@
|
||||
package org.jetbrains.jet.lang.resolve.java.resolver;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiArrayType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -28,16 +29,19 @@ import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaBindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaVisibilities;
|
||||
import org.jetbrains.jet.lang.resolve.java.TypeVariableResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver.recordSamAdapter;
|
||||
@@ -69,83 +73,15 @@ public final class JavaConstructorResolver {
|
||||
|
||||
@NotNull
|
||||
public Collection<ConstructorDescriptor> resolveConstructors(@NotNull JavaClass javaClass, @NotNull ClassDescriptor containingClass) {
|
||||
PsiClass psiClass = javaClass.getPsi();
|
||||
|
||||
Collection<ConstructorDescriptor> result = Lists.newArrayList();
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = containingClass.getTypeConstructor().getParameters();
|
||||
|
||||
TypeVariableResolver typeVariableResolver =
|
||||
new TypeVariableResolver(typeParameters, containingClass, "class " + javaClass.getFqName());
|
||||
|
||||
Collection<JavaMethod> constructors = javaClass.getConstructors();
|
||||
|
||||
if (containingClass.getKind() == ClassKind.OBJECT || containingClass.getKind() == ClassKind.CLASS_OBJECT) {
|
||||
result.add(DescriptorResolver.createPrimaryConstructorForObject(containingClass));
|
||||
}
|
||||
else if (constructors.isEmpty()) {
|
||||
if (trace.get(BindingContext.CONSTRUCTOR, psiClass) != null) {
|
||||
result.add(trace.get(BindingContext.CONSTRUCTOR, psiClass));
|
||||
}
|
||||
else {
|
||||
Visibility constructorVisibility = getConstructorVisibility(containingClass);
|
||||
// We need to create default constructors for classes and abstract classes.
|
||||
// Example:
|
||||
// class Kotlin() : Java() {}
|
||||
// abstract public class Java {}
|
||||
if (!javaClass.isInterface()) {
|
||||
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
|
||||
containingClass,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
true);
|
||||
constructorDescriptor
|
||||
.initialize(typeParameters, Collections.<ValueParameterDescriptor>emptyList(), constructorVisibility,
|
||||
javaClass.isStatic());
|
||||
result.add(constructorDescriptor);
|
||||
trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
|
||||
}
|
||||
if (javaClass.isAnnotationType()) {
|
||||
// A constructor for an annotation type takes all the "methods" in the @interface as parameters
|
||||
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
|
||||
containingClass,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
true);
|
||||
|
||||
List<ValueParameterDescriptor> 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 = typeTransformer
|
||||
.transformToType(((PsiArrayType) returnType).getComponentType(), typeVariableResolver);
|
||||
}
|
||||
|
||||
assert returnType != null;
|
||||
valueParameters.add(new ValueParameterDescriptorImpl(
|
||||
constructorDescriptor,
|
||||
i,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Name.identifier(method.getName()),
|
||||
typeTransformer.transformToType(returnType, typeVariableResolver),
|
||||
annotationMethod.getDefaultValue() != null,
|
||||
varargElementType));
|
||||
}
|
||||
}
|
||||
|
||||
constructorDescriptor.initialize(typeParameters, valueParameters, constructorVisibility, javaClass.isStatic());
|
||||
result.add(constructorDescriptor);
|
||||
trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
|
||||
}
|
||||
}
|
||||
ContainerUtil.addIfNotNull(result, resolveDefaultConstructor(javaClass, containingClass));
|
||||
}
|
||||
else {
|
||||
for (JavaMethod constructor : constructors) {
|
||||
@@ -162,6 +98,81 @@ public final class JavaConstructorResolver {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ConstructorDescriptor resolveDefaultConstructor(@NotNull JavaClass javaClass, @NotNull ClassDescriptor containingClass) {
|
||||
ConstructorDescriptor alreadyResolved = trace.get(BindingContext.CONSTRUCTOR, javaClass.getPsi());
|
||||
if (alreadyResolved != null) {
|
||||
return alreadyResolved;
|
||||
}
|
||||
|
||||
boolean isAnnotation = javaClass.isAnnotationType();
|
||||
|
||||
if (javaClass.isInterface() && !isAnnotation) return null;
|
||||
|
||||
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
|
||||
containingClass,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
true);
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = containingClass.getTypeConstructor().getParameters();
|
||||
|
||||
List<ValueParameterDescriptor> valueParameters;
|
||||
if (isAnnotation) {
|
||||
TypeVariableResolver typeVariableResolver =
|
||||
new TypeVariableResolver(typeParameters, containingClass, "class " + javaClass.getFqName());
|
||||
valueParameters = resolveAnnotationParameters(javaClass, constructorDescriptor, typeVariableResolver);
|
||||
}
|
||||
else {
|
||||
valueParameters = Collections.emptyList();
|
||||
}
|
||||
|
||||
constructorDescriptor.initialize(typeParameters, valueParameters, getConstructorVisibility(containingClass), javaClass.isStatic());
|
||||
|
||||
trace.record(BindingContext.CONSTRUCTOR, javaClass.getPsi(), constructorDescriptor);
|
||||
|
||||
return constructorDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<ValueParameterDescriptor> resolveAnnotationParameters(
|
||||
@NotNull JavaClass javaClass,
|
||||
@NotNull ConstructorDescriptor constructorDescriptor,
|
||||
@NotNull TypeVariableResolver typeVariableResolver
|
||||
) {
|
||||
// A constructor for an annotation type takes all the "methods" in the @interface as parameters
|
||||
List<ValueParameterDescriptor> result = Lists.newArrayList();
|
||||
|
||||
int index = 0;
|
||||
for (Iterator<JavaMethod> iterator = javaClass.getMethods().iterator(); iterator.hasNext(); ) {
|
||||
JavaMethod method = iterator.next();
|
||||
assert method.getValueParameters().isEmpty() : "Annotation method can't have parameters: " + method;
|
||||
|
||||
PsiType returnType = method.getPsi().getReturnType();
|
||||
assert returnType != null : "Annotation method has no return type: " + method;
|
||||
|
||||
// We take the following heuristic convention:
|
||||
// if the last method of the @interface is an array, we convert it into a vararg
|
||||
JetType varargElementType = null;
|
||||
if (!iterator.hasNext() && returnType instanceof PsiArrayType) {
|
||||
PsiType componentType = ((PsiArrayType) returnType).getComponentType();
|
||||
varargElementType = typeTransformer.transformToType(componentType, typeVariableResolver);
|
||||
}
|
||||
|
||||
result.add(new ValueParameterDescriptorImpl(
|
||||
constructorDescriptor,
|
||||
index,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
method.getName(),
|
||||
typeTransformer.transformToType(returnType, typeVariableResolver),
|
||||
method.getAnnotationParameterDefaultValue() != null,
|
||||
varargElementType));
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Visibility getConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
|
||||
Visibility visibility = classDescriptor.getVisibility();
|
||||
|
||||
+10
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.java.structure;
|
||||
|
||||
import com.intellij.psi.PsiAnnotationMethod;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -62,4 +63,13 @@ public class JavaMethod extends JavaMemberImpl implements JavaTypeParameterListO
|
||||
public Collection<JavaValueParameter> getValueParameters() {
|
||||
return valueParameters(getPsi().getParameterList().getParameters());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getAnnotationParameterDefaultValue() {
|
||||
PsiMethod psiMethod = getPsi();
|
||||
if (psiMethod instanceof PsiAnnotationMethod) {
|
||||
return ((PsiAnnotationMethod) psiMethod).getDefaultValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user