diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java index c3546641873..47bd0e9a1e4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegationResolver.java @@ -32,173 +32,15 @@ import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED; import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE; -public class DelegationResolver { - - private DelegationResolver() { - } - - @NotNull - public static Collection generateDelegatedMembers( - @NotNull JetClassOrObject classOrObject, - @NotNull ClassDescriptor classDescriptor, - @NotNull Collection existingMembers, - @NotNull BindingTrace trace, - @NotNull Callback callback - ) { - Collection delegatedMembers = new HashSet(); - for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) { - if (!(delegationSpecifier instanceof JetDelegatorByExpressionSpecifier)) { - continue; - } - JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier; - JetTypeReference typeReference = specifier.getTypeReference(); - if (typeReference == null) { - continue; - } - JetType delegatedTraitType = callback.getTypeByTypeReference(typeReference); - if (delegatedTraitType == null) { - continue; - } - Collection delegatesForTrait = generateDelegatesForOneTrait(classOrObject, classDescriptor, existingMembers, - trace, callback, delegatedMembers, delegatedTraitType); - delegatedMembers.addAll(delegatesForTrait); - } - return delegatedMembers; - } - - @NotNull - private static Collection generateDelegatesForOneTrait( - @NotNull JetClassOrObject classOrObject, - @NotNull ClassDescriptor classDescriptor, - @NotNull Collection existingMembers, - @NotNull BindingTrace trace, - @NotNull Callback callback, - @NotNull Collection existingDelegates, - @NotNull JetType delegatedTraitType - ) { - Collection result = new HashSet(); - Collection candidates = generateDelegationCandidates(classDescriptor, delegatedTraitType, callback); - for (T candidate : candidates) { - if (existingMemberOverridesDelegatedMember(candidate, existingMembers)) { - continue; - } - //only leave the first delegated member - if (checkClashWithOtherDelegatedMember(trace, classOrObject, existingDelegates, candidate)) { - continue; - } - - result.add(candidate); - } - return result; - } - - private static boolean checkClashWithOtherDelegatedMember( - @NotNull BindingTrace trace, - @Nullable JetClassOrObject jetClass, - @NotNull Collection delegatedMembers, - @NotNull T candidate - ) { - for (CallableMemberDescriptor alreadyDelegatedMember : delegatedMembers) { - if (haveSameSignatures(alreadyDelegatedMember, candidate)) { - //trying to delegate to many traits with the same methods - if (jetClass != null) { - PsiElement nameIdentifier = jetClass.getNameIdentifier(); - if (nameIdentifier != null) { - trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(nameIdentifier, jetClass, alreadyDelegatedMember)); - } - } - return true; - } - } - return false; - } - - private static boolean existingMemberOverridesDelegatedMember( - @NotNull CallableMemberDescriptor candidate, - @NotNull Collection existingMembers - ) { - for (CallableDescriptor existingDescriptor : existingMembers) { - if (haveSameSignatures(existingDescriptor, candidate)) { - return true; - } - } - return false; - } - - @NotNull - private static Collection generateDelegationCandidates( - @NotNull ClassDescriptor classDescriptor, - @NotNull JetType delegatedTraitType, - @NotNull Callback callback - ) { - Collection membersFromTrait = callback.getMembersByType(delegatedTraitType); - Collection descriptorsToDelegate = filterMembersFromSuperClassOfDelegatedTrait(delegatedTraitType, membersFromTrait, callback); - Collection result = Lists.newArrayList(); - for (T memberDescriptor : descriptorsToDelegate) { - if (memberDescriptor.getModality().isOverridable()) { - Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true); - @SuppressWarnings("unchecked") - T copy = (T) memberDescriptor.copy(classDescriptor, modality, memberDescriptor.getVisibility(), - CallableMemberDescriptor.Kind.DELEGATION, false); - result.add(copy); - } - } - return result; - } - - @NotNull - private static Collection filterMembersFromSuperClassOfDelegatedTrait( - @NotNull JetType delegatedTraitType, - @NotNull Collection membersFromTrait, - @NotNull Callback callback - ) { - final Collection membersToSkip = getMembersFromClassSupertypeOfTrait(delegatedTraitType, callback); - return Collections2.filter( - membersFromTrait, - new Predicate() { - @Override - public boolean apply(@Nullable CallableMemberDescriptor descriptor) { - for (CallableMemberDescriptor memberToSkip : membersToSkip) { - if (haveSameSignatures(memberToSkip, descriptor)) { - return false; - } - } - return true; - } - }); - } - - private static boolean haveSameSignatures(@NotNull CallableDescriptor memberOne, @NotNull CallableDescriptor memberTwo) { - return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OVERRIDABLE; - } - - @NotNull - private static Collection getMembersFromClassSupertypeOfTrait( - @NotNull JetType delegateTraitType, - @NotNull Callback callback - ) { - JetType classSupertype = null; - for (JetType supertype : TypeUtils.getAllSupertypes(delegateTraitType)) { - if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) { - classSupertype = supertype; - break; - } - } - return classSupertype != null ? callback.getMembersByType(classSupertype) : Collections.emptyList(); - } - - private static boolean isNotTrait(DeclarationDescriptor descriptor) { - if (descriptor instanceof ClassDescriptor) { - ClassKind kind = ((ClassDescriptor) descriptor).getKind(); - return kind != ClassKind.TRAIT; - } - return false; - } +public final class DelegationResolver { public static void generateDelegatesInAClass( @NotNull MutableClassDescriptor classDescriptor, @@ -235,6 +77,171 @@ public class DelegationResolver { } } + + @NotNull + public static Collection generateDelegatedMembers( + @NotNull JetClassOrObject classOrObject, + @NotNull ClassDescriptor ownerDescriptor, + @NotNull Collection existingMembers, + @NotNull BindingTrace trace, + @NotNull Callback callback + ) { + return new DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, callback).generateDelegatedMembers(); + } + @NotNull private final JetClassOrObject classOrObject; + @NotNull private final ClassDescriptor ownerDescriptor; + @NotNull private final Collection existingMembers; + @NotNull private final BindingTrace trace; + + @NotNull private final Callback callback; + + private DelegationResolver( + @NotNull JetClassOrObject classOrObject, + @NotNull ClassDescriptor ownerDescriptor, + @NotNull Collection existingMembers, + @NotNull BindingTrace trace, + @NotNull Callback callback + ) { + + this.classOrObject = classOrObject; + this.ownerDescriptor = ownerDescriptor; + this.existingMembers = existingMembers; + this.trace = trace; + this.callback = callback; + } + + @NotNull + private Collection generateDelegatedMembers() { + Collection delegatedMembers = new HashSet(); + for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) { + if (!(delegationSpecifier instanceof JetDelegatorByExpressionSpecifier)) { + continue; + } + JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier; + JetTypeReference typeReference = specifier.getTypeReference(); + if (typeReference == null) { + continue; + } + JetType delegatedTraitType = callback.getTypeByTypeReference(typeReference); + if (delegatedTraitType == null) { + continue; + } + Collection delegatesForTrait = generateDelegatesForOneTrait(delegatedMembers, delegatedTraitType); + delegatedMembers.addAll(delegatesForTrait); + } + return delegatedMembers; + } + + @NotNull + private Collection generateDelegatesForOneTrait( + @NotNull Collection existingDelegates, + @NotNull JetType delegatedTraitType + ) { + Collection result = new HashSet(); + Collection candidates = generateDelegationCandidates(delegatedTraitType); + for (T candidate : candidates) { + if (existingMemberOverridesDelegatedMember(candidate, existingMembers)) { + continue; + } + //only leave the first delegated member + if (checkClashWithOtherDelegatedMember(existingDelegates, candidate)) { + continue; + } + + result.add(candidate); + } + return result; + } + + private boolean checkClashWithOtherDelegatedMember( + @NotNull Collection delegatedMembers, + @NotNull T candidate + ) { + for (CallableMemberDescriptor alreadyDelegatedMember : delegatedMembers) { + if (haveSameSignatures(alreadyDelegatedMember, candidate)) { + //trying to delegate to many traits with the same methods + PsiElement nameIdentifier = classOrObject.getNameIdentifier(); + if (nameIdentifier != null) { + trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(nameIdentifier, classOrObject, alreadyDelegatedMember)); + } + return true; + } + } + return false; + } + + private static boolean existingMemberOverridesDelegatedMember( + @NotNull CallableMemberDescriptor candidate, + @NotNull Collection existingMembers + ) { + for (CallableDescriptor existingDescriptor : existingMembers) { + if (haveSameSignatures(existingDescriptor, candidate)) { + return true; + } + } + return false; + } + + @NotNull + private Collection generateDelegationCandidates(@NotNull JetType delegatedTraitType) { + Collection descriptorsToDelegate = filterMembersFromSuperClassOfDelegatedTrait(delegatedTraitType); + Collection result = Lists.newArrayList(); + for (T memberDescriptor : descriptorsToDelegate) { + if (memberDescriptor.getModality().isOverridable()) { + Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true); + @SuppressWarnings("unchecked") + T copy = (T) memberDescriptor.copy(ownerDescriptor, modality, memberDescriptor.getVisibility(), + CallableMemberDescriptor.Kind.DELEGATION, false); + result.add(copy); + } + } + return result; + } + + @NotNull + private Collection filterMembersFromSuperClassOfDelegatedTrait( + @NotNull JetType delegatedTraitType + ) { + final Collection membersToSkip = getMembersFromClassSupertypeOfTrait(delegatedTraitType); + return Collections2.filter( + callback.getMembersByType(delegatedTraitType), + new Predicate() { + @Override + public boolean apply(@Nullable CallableMemberDescriptor descriptor) { + for (CallableMemberDescriptor memberToSkip : membersToSkip) { + if (haveSameSignatures(memberToSkip, descriptor)) { + return false; + } + } + return true; + } + }); + } + + private static boolean haveSameSignatures(@NotNull CallableDescriptor memberOne, @NotNull CallableDescriptor memberTwo) { + return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OVERRIDABLE; + } + + @NotNull + private Collection getMembersFromClassSupertypeOfTrait(@NotNull JetType delegateTraitType) { + JetType classSupertype = null; + for (JetType supertype : TypeUtils.getAllSupertypes(delegateTraitType)) { + if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) { + classSupertype = supertype; + break; + } + } + return classSupertype != null ? callback.getMembersByType(classSupertype) : Collections.emptyList(); + } + + private static boolean isNotTrait(@NotNull DeclarationDescriptor descriptor) { + if (descriptor instanceof ClassDescriptor) { + ClassKind kind = ((ClassDescriptor) descriptor).getKind(); + return kind != ClassKind.TRAIT; + } + return false; + } + public interface Callback { @Nullable JetType getTypeByTypeReference(@NotNull JetTypeReference reference);