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 com.intellij.psi.PsiElement;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.*;
027 import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
028 import org.jetbrains.jet.lang.psi.JetClassOrObject;
029 import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
030 import org.jetbrains.jet.lang.psi.JetDelegatorByExpressionSpecifier;
031 import org.jetbrains.jet.lang.psi.JetTypeReference;
032 import org.jetbrains.jet.lang.types.JetType;
033 import org.jetbrains.jet.lang.types.TypeUtils;
034
035 import java.util.Collection;
036 import java.util.Collections;
037 import java.util.HashSet;
038 import java.util.Set;
039
040 import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
041 import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
042
043 public final class DelegationResolver<T extends CallableMemberDescriptor> {
044
045 public static void generateDelegatesInAClass(
046 @NotNull MutableClassDescriptor classDescriptor,
047 @NotNull final BindingTrace trace,
048 @NotNull JetClassOrObject jetClassOrObject
049 ) {
050 TypeResolver eagerTypeResolver = new TypeResolver() {
051 @Nullable
052 @Override
053 public JetType resolve(@NotNull JetTypeReference reference) {
054 return trace.get(BindingContext.TYPE, reference);
055 }
056 };
057 MemberExtractor<CallableMemberDescriptor> eagerExtractor = new MemberExtractor<CallableMemberDescriptor>() {
058 @NotNull
059 @Override
060 public Collection<CallableMemberDescriptor> getMembersByType(@NotNull JetType type) {
061 //noinspection unchecked
062 return (Collection) Collections2.filter(type.getMemberScope().getAllDescriptors(),
063 Predicates.instanceOf(CallableMemberDescriptor.class));
064 }
065 };
066 Set<CallableMemberDescriptor> existingMembers = classDescriptor.getAllCallableMembers();
067 Collection<CallableMemberDescriptor> delegatedMembers =
068 generateDelegatedMembers(jetClassOrObject, classDescriptor, existingMembers, trace, eagerExtractor, eagerTypeResolver);
069 for (CallableMemberDescriptor descriptor : delegatedMembers) {
070 if (descriptor instanceof PropertyDescriptor) {
071 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
072 classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
073 }
074 else if (descriptor instanceof SimpleFunctionDescriptor) {
075 SimpleFunctionDescriptor functionDescriptor = (SimpleFunctionDescriptor) descriptor;
076 classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
077 }
078 }
079 }
080
081
082 @NotNull
083 public static <T extends CallableMemberDescriptor> Collection<T> generateDelegatedMembers(
084 @NotNull JetClassOrObject classOrObject,
085 @NotNull ClassDescriptor ownerDescriptor,
086 @NotNull Collection<? extends CallableDescriptor> existingMembers,
087 @NotNull BindingTrace trace,
088 @NotNull MemberExtractor<T> memberExtractor,
089 @NotNull TypeResolver typeResolver
090 ) {
091 return new DelegationResolver<T>(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver)
092 .generateDelegatedMembers();
093 }
094
095 @NotNull private final JetClassOrObject classOrObject;
096 @NotNull private final ClassDescriptor ownerDescriptor;
097 @NotNull private final Collection<? extends CallableDescriptor> existingMembers;
098 @NotNull private final BindingTrace trace;
099 @NotNull private final MemberExtractor<T> memberExtractor;
100 @NotNull private final TypeResolver typeResolver;
101
102 private DelegationResolver(
103 @NotNull JetClassOrObject classOrObject,
104 @NotNull ClassDescriptor ownerDescriptor,
105 @NotNull Collection<? extends CallableDescriptor> existingMembers,
106 @NotNull BindingTrace trace,
107 @NotNull MemberExtractor<T> extractor,
108 @NotNull TypeResolver resolver
109 ) {
110
111 this.classOrObject = classOrObject;
112 this.ownerDescriptor = ownerDescriptor;
113 this.existingMembers = existingMembers;
114 this.trace = trace;
115 this.memberExtractor = extractor;
116 this.typeResolver = resolver;
117 }
118
119 @NotNull
120 private Collection<T> generateDelegatedMembers() {
121 Collection<T> delegatedMembers = new HashSet<T>();
122 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
123 if (!(delegationSpecifier instanceof JetDelegatorByExpressionSpecifier)) {
124 continue;
125 }
126 JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
127 JetTypeReference typeReference = specifier.getTypeReference();
128 if (typeReference == null) {
129 continue;
130 }
131 JetType delegatedTraitType = typeResolver.resolve(typeReference);
132 if (delegatedTraitType == null) {
133 continue;
134 }
135 Collection<T> delegatesForTrait = generateDelegatesForTrait(delegatedMembers, delegatedTraitType);
136 delegatedMembers.addAll(delegatesForTrait);
137 }
138 return delegatedMembers;
139 }
140
141 @NotNull
142 private Collection<T> generateDelegatesForTrait(
143 @NotNull Collection<T> existingDelegates,
144 @NotNull JetType delegatedTraitType
145 ) {
146 Collection<T> result = new HashSet<T>();
147 Collection<T> candidates = generateDelegationCandidates(delegatedTraitType);
148 for (T candidate : candidates) {
149 if (existingMemberOverridesDelegatedMember(candidate, existingMembers)) {
150 continue;
151 }
152 //only leave the first delegated member
153 if (checkClashWithOtherDelegatedMember(existingDelegates, candidate)) {
154 continue;
155 }
156
157 result.add(candidate);
158 }
159 return result;
160 }
161
162 @NotNull
163 private Collection<T> generateDelegationCandidates(@NotNull JetType delegatedTraitType) {
164 Collection<T> descriptorsToDelegate = overridableMembersNotFromSuperClassOfTrait(delegatedTraitType);
165 Collection<T> result = Lists.newArrayList();
166 for (T memberDescriptor : descriptorsToDelegate) {
167 Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true);
168 @SuppressWarnings("unchecked")
169 T copy = (T) memberDescriptor.copy(ownerDescriptor, modality, memberDescriptor.getVisibility(),
170 CallableMemberDescriptor.Kind.DELEGATION, false);
171 result.add(copy);
172 }
173 return result;
174 }
175
176 private static boolean existingMemberOverridesDelegatedMember(
177 @NotNull CallableMemberDescriptor candidate,
178 @NotNull Collection<? extends CallableDescriptor> existingMembers
179 ) {
180 for (CallableDescriptor existingDescriptor : existingMembers) {
181 if (haveSameSignatures(existingDescriptor, candidate)) {
182 return true;
183 }
184 }
185 return false;
186 }
187
188 private boolean checkClashWithOtherDelegatedMember(
189 @NotNull Collection<T> delegatedMembers,
190 @NotNull T candidate
191 ) {
192 for (CallableMemberDescriptor alreadyDelegatedMember : delegatedMembers) {
193 if (haveSameSignatures(alreadyDelegatedMember, candidate)) {
194 //trying to delegate to many traits with the same methods
195 PsiElement nameIdentifier = classOrObject.getNameIdentifier();
196 PsiElement element = nameIdentifier != null ? nameIdentifier : classOrObject;
197 trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(element, classOrObject, alreadyDelegatedMember));
198 return true;
199 }
200 }
201 return false;
202 }
203
204 @NotNull
205 private Collection<T> overridableMembersNotFromSuperClassOfTrait(@NotNull JetType trait) {
206 final Collection<T> membersToSkip = getMembersFromClassSupertypeOfTrait(trait);
207 return Collections2.filter(
208 memberExtractor.getMembersByType(trait),
209 new Predicate<CallableMemberDescriptor>() {
210 @Override
211 public boolean apply(CallableMemberDescriptor descriptor) {
212 if (!descriptor.getModality().isOverridable()) {
213 return false;
214 }
215 for (CallableMemberDescriptor memberToSkip : membersToSkip) {
216 if (haveSameSignatures(memberToSkip, descriptor)) {
217 return false;
218 }
219 }
220 return true;
221 }
222 });
223 }
224
225 private static boolean haveSameSignatures(@NotNull CallableDescriptor memberOne, @NotNull CallableDescriptor memberTwo) {
226 //isOverridableBy ignores return types
227 return OverridingUtil.isOverridableBy(memberOne, memberTwo).getResult() == OVERRIDABLE;
228 }
229
230 @NotNull
231 private Collection<T> getMembersFromClassSupertypeOfTrait(@NotNull JetType traitType) {
232 JetType classSupertype = null;
233 for (JetType supertype : TypeUtils.getAllSupertypes(traitType)) {
234 if (isNotTrait(supertype.getConstructor().getDeclarationDescriptor())) {
235 classSupertype = supertype;
236 break;
237 }
238 }
239 return classSupertype != null ? memberExtractor.getMembersByType(classSupertype) : Collections.<T>emptyList();
240 }
241
242 private static boolean isNotTrait(@Nullable DeclarationDescriptor descriptor) {
243 if (descriptor instanceof ClassDescriptor) {
244 ClassKind kind = ((ClassDescriptor) descriptor).getKind();
245 return kind != ClassKind.TRAIT;
246 }
247 return false;
248 }
249
250 public interface MemberExtractor<T extends CallableMemberDescriptor> {
251 @NotNull
252 Collection<T> getMembersByType(@NotNull JetType type);
253 }
254
255 public interface TypeResolver {
256 @Nullable
257 JetType resolve(@NotNull JetTypeReference reference);
258 }
259 }