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    
017    package org.jetbrains.jet.lang.resolve;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.base.Predicates;
021    import com.google.common.collect.Collections2;
022    import com.google.common.collect.Lists;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.jet.lang.descriptors.*;
026    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
027    import org.jetbrains.jet.lang.psi.JetClassOrObject;
028    import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
029    import org.jetbrains.jet.lang.psi.JetDelegatorByExpressionSpecifier;
030    import org.jetbrains.jet.lang.types.JetType;
031    import org.jetbrains.jet.lang.types.TypeUtils;
032    
033    import java.util.Collection;
034    import java.util.Collections;
035    
036    import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
037    
038    public 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    }