001/*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.jetbrains.jet.lang.resolve;
018
019import com.google.common.base.Predicate;
020import com.google.common.base.Predicates;
021import com.google.common.collect.Collections2;
022import com.google.common.collect.Lists;
023import org.jetbrains.annotations.NotNull;
024import org.jetbrains.annotations.Nullable;
025import org.jetbrains.jet.lang.descriptors.*;
026import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
027import org.jetbrains.jet.lang.psi.JetClassOrObject;
028import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
029import org.jetbrains.jet.lang.psi.JetDelegatorByExpressionSpecifier;
030import org.jetbrains.jet.lang.types.JetType;
031import org.jetbrains.jet.lang.types.TypeUtils;
032
033import java.util.Collection;
034import java.util.Collections;
035
036import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
037
038public class DelegationResolver {
039
040    private DelegationResolver() {}
041
042    public static void addDelegatedMembers(@NotNull BindingTrace trace, @NotNull JetClassOrObject jetClass, @NotNull MutableClassDescriptor classDescriptor) {
043        for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
044            if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) {
045                JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
046                JetType type = trace.get(BindingContext.TYPE, specifier.getTypeReference());
047                if (type != null) {
048                    final Collection<CallableMemberDescriptor> membersToSkip = getMembersFromClassSupertype(type);
049                    Collection<CallableMemberDescriptor> descriptorsToDelegate = Collections2.filter(extractCallableMembers(type),
050                         new Predicate<CallableMemberDescriptor>() {
051                             @Override
052                             public boolean apply(@Nullable CallableMemberDescriptor descriptor) {
053                                 for (CallableMemberDescriptor memberToSkip : membersToSkip) {
054                                    if (haveSameSignatures(memberToSkip, descriptor)) {
055                                         return false;
056                                    }
057                                 }
058                                 return true;
059                             }
060                         });
061
062                    Collection<CallableMemberDescriptor> generatedDescriptors = generateDelegatedMembers(classDescriptor, descriptorsToDelegate);
063                    outer:
064                    for (CallableMemberDescriptor descriptor : generatedDescriptors) {
065                        for (CallableMemberDescriptor existingDescriptor : classDescriptor.getAllCallableMembers()) {
066                            if (OverridingUtil.isOverridableBy(existingDescriptor, descriptor).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) {
067                                if (existingDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
068                                    //trying to delegate to many traits with the same methods
069                                    trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(jetClass.getNameIdentifier(), jetClass, existingDescriptor));
070                                }
071                                continue outer;
072                            }
073                        }
074
075                        if (descriptor instanceof PropertyDescriptor) {
076                            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
077                            classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
078                        }
079                        else if (descriptor instanceof SimpleFunctionDescriptor) {
080                            SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor;
081                            classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
082                        }
083                    }
084                }
085            }
086        }
087    }
088
089    private static boolean haveSameSignatures(CallableDescriptor memberOne, CallableDescriptor memberTwo) {
090        return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
091    }
092
093    private static Collection<CallableMemberDescriptor> getMembersFromClassSupertype(JetType type) {
094        JetType classSupertype = null;
095        for (JetType supertype : TypeUtils.getAllSupertypes(type)) {
096            if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) {
097                classSupertype = supertype;
098                break;
099            }
100        }
101
102        return classSupertype != null ? extractCallableMembers(classSupertype) : Collections.<CallableMemberDescriptor>emptyList();
103    }
104
105    @SuppressWarnings("unchecked")
106    private static Collection<CallableMemberDescriptor> extractCallableMembers(JetType type) {
107        return (Collection) Collections2.filter(type.getMemberScope().getAllDescriptors(),
108                                                Predicates.instanceOf(CallableMemberDescriptor.class));
109    }
110
111    private static boolean isNotTrait(DeclarationDescriptor descriptor) {
112        if (descriptor instanceof ClassDescriptor) {
113            ClassKind kind = ((ClassDescriptor) descriptor).getKind();
114            return kind != ClassKind.TRAIT;
115        }
116        return false;
117    }
118
119    public static <T extends CallableMemberDescriptor> Collection<T> generateDelegatedMembers(DeclarationDescriptor newOwner, Collection<T> delegatedDescriptors) {
120        Collection<CallableMemberDescriptor> result = Lists.newArrayList();
121        for (CallableMemberDescriptor memberDescriptor : delegatedDescriptors) {
122            if (memberDescriptor.getModality().isOverridable()) {
123                Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true);
124                CallableMemberDescriptor copy =
125                        memberDescriptor.copy(newOwner, modality, memberDescriptor.getVisibility(), CallableMemberDescriptor.Kind.DELEGATION, false);
126                result.add(copy);
127            }
128        }
129        //noinspection unchecked
130        return (Collection) result;
131    }
132}