001    /*
002     * Copyright 2010-2015 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.kotlin.resolve;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.collect.Collections2;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.psi.KtClassOrObject;
025    import org.jetbrains.kotlin.psi.KtDelegationSpecifier;
026    import org.jetbrains.kotlin.psi.KtDelegatorByExpressionSpecifier;
027    import org.jetbrains.kotlin.psi.KtTypeReference;
028    import org.jetbrains.kotlin.types.KotlinType;
029    import org.jetbrains.kotlin.types.TypeUtils;
030    
031    import java.util.ArrayList;
032    import java.util.Collection;
033    import java.util.Collections;
034    import java.util.HashSet;
035    
036    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION;
037    import static org.jetbrains.kotlin.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
038    import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
039    
040    public final class DelegationResolver<T extends CallableMemberDescriptor> {
041    
042        @NotNull
043        public static <T extends CallableMemberDescriptor> Collection<T> generateDelegatedMembers(
044                @NotNull KtClassOrObject classOrObject,
045                @NotNull ClassDescriptor ownerDescriptor,
046                @NotNull Collection<? extends CallableDescriptor> existingMembers,
047                @NotNull BindingTrace trace,
048                @NotNull MemberExtractor<T> memberExtractor,
049                @NotNull TypeResolver typeResolver
050        ) {
051            return new DelegationResolver<T>(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver)
052                    .generateDelegatedMembers();
053        }
054    
055        @NotNull private final KtClassOrObject classOrObject;
056        @NotNull private final ClassDescriptor ownerDescriptor;
057        @NotNull private final Collection<? extends CallableDescriptor> existingMembers;
058        @NotNull private final BindingTrace trace;
059        @NotNull private final MemberExtractor<T> memberExtractor;
060        @NotNull private final TypeResolver typeResolver;
061    
062        private DelegationResolver(
063                @NotNull KtClassOrObject classOrObject,
064                @NotNull ClassDescriptor ownerDescriptor,
065                @NotNull Collection<? extends CallableDescriptor> existingMembers,
066                @NotNull BindingTrace trace,
067                @NotNull MemberExtractor<T> extractor,
068                @NotNull TypeResolver resolver
069        ) {
070    
071            this.classOrObject = classOrObject;
072            this.ownerDescriptor = ownerDescriptor;
073            this.existingMembers = existingMembers;
074            this.trace = trace;
075            this.memberExtractor = extractor;
076            this.typeResolver = resolver;
077        }
078    
079        @NotNull
080        private Collection<T> generateDelegatedMembers() {
081            Collection<T> delegatedMembers = new HashSet<T>();
082            for (KtDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
083                if (!(delegationSpecifier instanceof KtDelegatorByExpressionSpecifier)) {
084                    continue;
085                }
086                KtDelegatorByExpressionSpecifier specifier = (KtDelegatorByExpressionSpecifier) delegationSpecifier;
087                KtTypeReference typeReference = specifier.getTypeReference();
088                if (typeReference == null) {
089                    continue;
090                }
091                KotlinType delegatedTraitType = typeResolver.resolve(typeReference);
092                if (delegatedTraitType == null || delegatedTraitType.isError()) {
093                    continue;
094                }
095                Collection<T> delegatesForTrait = generateDelegatesForTrait(delegatedMembers, delegatedTraitType);
096                delegatedMembers.addAll(delegatesForTrait);
097            }
098            return delegatedMembers;
099        }
100    
101        @NotNull
102        private Collection<T> generateDelegatesForTrait(
103                @NotNull Collection<T> existingDelegates,
104                @NotNull KotlinType delegatedTraitType
105        ) {
106            Collection<T> result = new HashSet<T>();
107            Collection<T> candidates = generateDelegationCandidates(delegatedTraitType);
108            for (T candidate : candidates) {
109                if (existingMemberOverridesDelegatedMember(candidate, existingMembers)) {
110                    continue;
111                }
112                //only leave the first delegated member
113                if (checkClashWithOtherDelegatedMember(existingDelegates, candidate)) {
114                    continue;
115                }
116    
117                result.add(candidate);
118            }
119            return result;
120        }
121    
122        @NotNull
123        private Collection<T> generateDelegationCandidates(@NotNull KotlinType delegatedTraitType) {
124            Collection<T> descriptorsToDelegate = overridableMembersNotFromSuperClassOfTrait(delegatedTraitType);
125            Collection<T> result = new ArrayList<T>(descriptorsToDelegate.size());
126            for (T memberDescriptor : descriptorsToDelegate) {
127                Modality newModality = memberDescriptor.getModality() == Modality.ABSTRACT ? Modality.OPEN : memberDescriptor.getModality();
128                @SuppressWarnings("unchecked")
129                T copy = (T) memberDescriptor.copy(ownerDescriptor, newModality, Visibilities.INHERITED, DELEGATION, false);
130                result.add(copy);
131            }
132            return result;
133        }
134    
135        private static boolean existingMemberOverridesDelegatedMember(
136                @NotNull CallableMemberDescriptor candidate,
137                @NotNull Collection<? extends CallableDescriptor> existingMembers
138        ) {
139            for (CallableDescriptor existingDescriptor : existingMembers) {
140                if (haveSameSignatures(existingDescriptor, candidate)) {
141                    return true;
142                }
143            }
144            return false;
145        }
146    
147        private boolean checkClashWithOtherDelegatedMember(@NotNull Collection<T> delegatedMembers, @NotNull T candidate) {
148            for (CallableMemberDescriptor alreadyDelegatedMember : delegatedMembers) {
149                if (haveSameSignatures(alreadyDelegatedMember, candidate)) {
150                    //trying to delegate to many traits with the same methods
151                    trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(classOrObject, classOrObject, alreadyDelegatedMember));
152                    return true;
153                }
154            }
155            return false;
156        }
157    
158        @NotNull
159        private Collection<T> overridableMembersNotFromSuperClassOfTrait(@NotNull KotlinType trait) {
160            final Collection<T> membersToSkip = getMembersFromClassSupertypeOfTrait(trait);
161            return Collections2.filter(
162                    memberExtractor.getMembersByType(trait),
163                    new Predicate<CallableMemberDescriptor>() {
164                        @Override
165                        public boolean apply(CallableMemberDescriptor descriptor) {
166                            if (!descriptor.getModality().isOverridable()) {
167                                return false;
168                            }
169                            for (CallableMemberDescriptor memberToSkip : membersToSkip) {
170                                if (haveSameSignatures(memberToSkip, descriptor)) {
171                                    return false;
172                                }
173                            }
174                            return true;
175                        }
176                    });
177        }
178    
179        private static boolean haveSameSignatures(@NotNull CallableDescriptor memberOne, @NotNull CallableDescriptor memberTwo) {
180            //isOverridableBy ignores return types
181            return OverridingUtil.DEFAULT.isOverridableBy(memberOne, memberTwo).getResult() == OVERRIDABLE;
182        }
183    
184        @NotNull
185        private Collection<T> getMembersFromClassSupertypeOfTrait(@NotNull KotlinType traitType) {
186            KotlinType classSupertype = null;
187            for (KotlinType supertype : TypeUtils.getAllSupertypes(traitType)) {
188                if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) {
189                    classSupertype = supertype;
190                    break;
191                }
192            }
193            return classSupertype != null ? memberExtractor.getMembersByType(classSupertype) : Collections.<T>emptyList();
194        }
195    
196        private static boolean isNotTrait(@Nullable DeclarationDescriptor descriptor) {
197            if (descriptor instanceof ClassDescriptor) {
198                ClassKind kind = ((ClassDescriptor) descriptor).getKind();
199                return kind != ClassKind.INTERFACE;
200            }
201            return false;
202        }
203    
204        public interface MemberExtractor<T extends CallableMemberDescriptor> {
205            @NotNull
206            Collection<T> getMembersByType(@NotNull KotlinType type);
207        }
208    
209        public interface TypeResolver {
210            @Nullable
211            KotlinType resolve(@NotNull KtTypeReference reference);
212        }
213    }