diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index 03274831b944..1777eaf686c1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -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 visited = new HashSet(); - List result = new ArrayList(); - getImplementListsInner(grType, result, visited); - return result.toArray(new PsiClassType[result.size()]); - } - - private static void getImplementListsInner(GrTypeDefinition grType, List result, Set visited) { - if (!visited.add(grType)) return; - + final Collection result = ContainerUtil.newLinkedHashSet(); final PsiClassType[] implementsTypes = getReferenceListTypes(grType.getImplementsClause()); - List 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 getImplementsFromDelegate(@NotNull final GrTypeDefinition grType, final Set visited) { - return RecursionManager.doPreventingRecursion(grType, true, new Computable>() { - @Override - public List compute() { - List result = new ArrayList(); - 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 result, PsiMethod method) { if (method instanceof GrMethod) { final GrReflectedMethod[] reflectedMethods = ((GrMethod)method).getReflectedMethods(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java index 6ff0c74a9f0c..0fd1a84f65b1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ast/DelegatedMethodsContributor.java @@ -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 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 collector) { Set processed = new HashSet(); if (!checkForDelegate(clazz)) return; - + Map signatures = new THashMap(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY); initializeSignatures(clazz, PsiSubstitutor.EMPTY, signatures, processed); @@ -334,4 +343,31 @@ public class DelegatedMethodsContributor extends AstTransformContributor { private static final Set OBJECT_METHODS = ContainerUtil.newHashSet("equals", "hashCode", "getClass", "clone", "toString", "notify", "notifyAll", "wait", "finalize"); private static final Set GROOVY_OBJECT_METHODS = ContainerUtil.newHashSet("invokeMethod", "getProperty", "setProperty", "getMetaClass", "setMetaClass"); + + private static void doCollectImplementsTypes(GrTypeDefinition grType, Collection 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(); + } }