[groovy] contribute to implements list while processing @Delegate transformation (simultaneously with contributing to methods)

This commit is contained in:
Daniil Ovchinnikov
2015-08-19 15:22:44 +03:00
parent 94d53572d5
commit 0fbb1674fa
2 changed files with 44 additions and 61 deletions
@@ -51,7 +51,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
@@ -59,6 +58,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.GrTypeDefin
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrScriptField;
import org.jetbrains.plugins.groovy.lang.resolve.CollectClassMembersUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ast.AstTransformContributor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
import java.util.*;
@@ -137,63 +137,15 @@ public class GrClassImplUtil {
@NotNull
public static PsiClassType[] getImplementsListTypes(GrTypeDefinition grType) {
Set<PsiClass> visited = new HashSet<PsiClass>();
List<PsiClassType> result = new ArrayList<PsiClassType>();
getImplementListsInner(grType, result, visited);
return result.toArray(new PsiClassType[result.size()]);
}
private static void getImplementListsInner(GrTypeDefinition grType, List<PsiClassType> result, Set<PsiClass> visited) {
if (!visited.add(grType)) return;
final Collection<PsiClassType> result = ContainerUtil.newLinkedHashSet();
final PsiClassType[] implementsTypes = getReferenceListTypes(grType.getImplementsClause());
List<PsiClassType> fromDelegates = getImplementsFromDelegate(grType, visited);
if (fromDelegates != null) {
result.addAll(fromDelegates);
}
final PsiClassType[] extendsTypes = getReferenceListTypes(grType.getExtendsClause());
result.addAll(Arrays.asList(implementsTypes));
if (!grType.isInterface() &&
!ContainerUtil.or(implementsTypes, IS_GROOVY_OBJECT) &&
!ContainerUtil.or(getReferenceListTypes(grType.getExtendsClause()), IS_GROOVY_OBJECT)) {
result.addAll(AstTransformContributor.runContributors(grType).getImplementsTypes());
if (!grType.isInterface() && !ContainerUtil.or(implementsTypes, IS_GROOVY_OBJECT) && !ContainerUtil.or(extendsTypes, IS_GROOVY_OBJECT)) {
result.add(getGroovyObjectType(grType));
}
}
@Nullable
private static List<PsiClassType> getImplementsFromDelegate(@NotNull final GrTypeDefinition grType, final Set<PsiClass> visited) {
return RecursionManager.doPreventingRecursion(grType, true, new Computable<List<PsiClassType>>() {
@Override
public List<PsiClassType> compute() {
List<PsiClassType> result = new ArrayList<PsiClassType>();
final GrField[] fields = grType.getCodeFields();
for (GrField field : fields) {
final PsiAnnotation delegate = PsiImplUtil.getAnnotation(field, GroovyCommonClassNames.GROOVY_LANG_DELEGATE);
if (delegate == null) continue;
final boolean shouldImplement = shouldImplementDelegatedInterfaces(delegate);
if (!shouldImplement) continue;
final PsiType type = field.getDeclaredType();
if (!(type instanceof PsiClassType)) continue;
final PsiClass psiClass = ((PsiClassType)type).resolve();
if (psiClass == null) continue;
if (psiClass instanceof GrTypeDefinition) {
getImplementListsInner((GrTypeDefinition)psiClass, result, visited);
}
else {
result.addAll(Arrays.asList(psiClass.getImplementsListTypes()));
}
if (psiClass.isInterface()) {
result.add((PsiClassType)type);
}
}
return result;
}
});
return result.toArray(new PsiClassType[result.size()]);
}
public static PsiClassType getGroovyObjectType(@NotNull PsiElement context) {
@@ -641,11 +593,6 @@ public class GrClassImplUtil {
return PsiClassImplUtil.isClassEquivalentTo(definition, another);
}
private static boolean shouldImplementDelegatedInterfaces(PsiAnnotation delegate) {
final Boolean result = GrAnnotationUtil.inferBooleanAttribute(delegate, "interfaces");
return result == null || result.booleanValue();
}
public static void addExpandingReflectedMethods(Collection<PsiMethod> result, PsiMethod method) {
if (method instanceof GrMethod) {
final GrReflectedMethod[] reflectedMethods = ((GrMethod)method).getReflectedMethods();
@@ -49,12 +49,21 @@ import java.util.*;
* @author Max Medvedev
*/
public class DelegatedMethodsContributor extends AstTransformContributor {
@NotNull
@Override
public void collectMethods(@NotNull final GrTypeDefinition clazz, @NotNull Collection<PsiMethod> collector) {
public Members collect(@NotNull GrTypeDefinition clazz) {
final Members result = Members.create();
doCollectMethods(clazz, result.getMethods());
doCollectImplementsTypes(clazz, result.getImplementsTypes());
return result;
}
private static void doCollectMethods(@NotNull final GrTypeDefinition clazz, @NotNull Collection<PsiMethod> collector) {
Set<PsiClass> processed = new HashSet<PsiClass>();
if (!checkForDelegate(clazz)) return;
Map<MethodSignature, PsiMethod> signatures = new THashMap<MethodSignature, PsiMethod>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
initializeSignatures(clazz, PsiSubstitutor.EMPTY, signatures, processed);
@@ -334,4 +343,31 @@ public class DelegatedMethodsContributor extends AstTransformContributor {
private static final Set<String> OBJECT_METHODS = ContainerUtil.newHashSet("equals", "hashCode", "getClass", "clone", "toString", "notify", "notifyAll", "wait", "finalize");
private static final Set<String> GROOVY_OBJECT_METHODS = ContainerUtil.newHashSet("invokeMethod", "getProperty", "setProperty", "getMetaClass", "setMetaClass");
private static void doCollectImplementsTypes(GrTypeDefinition grType, Collection<PsiClassType> result) {
final GrField[] fields = grType.getCodeFields();
for (GrField field : fields) {
final PsiAnnotation delegate = PsiImplUtil.getAnnotation(field, GroovyCommonClassNames.GROOVY_LANG_DELEGATE);
if (delegate == null) continue;
final boolean shouldImplement = shouldImplementDelegatedInterfaces(delegate);
if (!shouldImplement) continue;
final PsiType type = field.getDeclaredType();
if (!(type instanceof PsiClassType)) continue;
final PsiClass psiClass = ((PsiClassType)type).resolve();
if (psiClass == null) continue;
result.addAll(Arrays.asList(psiClass.getImplementsListTypes()));
if (psiClass.isInterface()) {
result.add((PsiClassType)type);
}
}
}
private static boolean shouldImplementDelegatedInterfaces(PsiAnnotation delegate) {
final Boolean result = GrAnnotationUtil.inferBooleanAttribute(delegate, "interfaces");
return result == null || result.booleanValue();
}
}