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;
|
package org.jetbrains.jet.lang.resolve.java.resolver;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
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 com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
|
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.kotlinSignature.AlternativeMethodSignatureData;
|
||||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass;
|
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass;
|
||||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
|
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 org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver.recordSamAdapter;
|
import static org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver.recordSamAdapter;
|
||||||
@@ -69,83 +73,15 @@ public final class JavaConstructorResolver {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Collection<ConstructorDescriptor> resolveConstructors(@NotNull JavaClass javaClass, @NotNull ClassDescriptor containingClass) {
|
public Collection<ConstructorDescriptor> resolveConstructors(@NotNull JavaClass javaClass, @NotNull ClassDescriptor containingClass) {
|
||||||
PsiClass psiClass = javaClass.getPsi();
|
|
||||||
|
|
||||||
Collection<ConstructorDescriptor> result = Lists.newArrayList();
|
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();
|
Collection<JavaMethod> constructors = javaClass.getConstructors();
|
||||||
|
|
||||||
if (containingClass.getKind() == ClassKind.OBJECT || containingClass.getKind() == ClassKind.CLASS_OBJECT) {
|
if (containingClass.getKind() == ClassKind.OBJECT || containingClass.getKind() == ClassKind.CLASS_OBJECT) {
|
||||||
result.add(DescriptorResolver.createPrimaryConstructorForObject(containingClass));
|
result.add(DescriptorResolver.createPrimaryConstructorForObject(containingClass));
|
||||||
}
|
}
|
||||||
else if (constructors.isEmpty()) {
|
else if (constructors.isEmpty()) {
|
||||||
if (trace.get(BindingContext.CONSTRUCTOR, psiClass) != null) {
|
ContainerUtil.addIfNotNull(result, resolveDefaultConstructor(javaClass, containingClass));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (JavaMethod constructor : constructors) {
|
for (JavaMethod constructor : constructors) {
|
||||||
@@ -162,6 +98,81 @@ public final class JavaConstructorResolver {
|
|||||||
return result;
|
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
|
@NotNull
|
||||||
private static Visibility getConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
|
private static Visibility getConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
|
||||||
Visibility visibility = classDescriptor.getVisibility();
|
Visibility visibility = classDescriptor.getVisibility();
|
||||||
|
|||||||
+10
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.java.structure;
|
package org.jetbrains.jet.lang.resolve.java.structure;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiAnnotationMethod;
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiMethod;
|
import com.intellij.psi.PsiMethod;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -62,4 +63,13 @@ public class JavaMethod extends JavaMemberImpl implements JavaTypeParameterListO
|
|||||||
public Collection<JavaValueParameter> getValueParameters() {
|
public Collection<JavaValueParameter> getValueParameters() {
|
||||||
return valueParameters(getPsi().getParameterList().getParameters());
|
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