001    /*
002     * Copyright 2010-2014 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.lazy.descriptors;
018    
019    import com.google.common.collect.ImmutableSet;
020    import com.google.common.collect.Lists;
021    import kotlin.Function0;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
026    import org.jetbrains.jet.lang.diagnostics.Errors;
027    import org.jetbrains.jet.lang.psi.*;
028    import org.jetbrains.jet.lang.resolve.*;
029    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
030    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
031    import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
032    import org.jetbrains.jet.lang.resolve.name.Name;
033    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034    import org.jetbrains.jet.lang.types.DeferredType;
035    import org.jetbrains.jet.lang.types.JetType;
036    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037    import org.jetbrains.jet.storage.NullableLazyValue;
038    
039    import java.util.*;
040    
041    import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DELEGATION;
042    import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
043    import static org.jetbrains.jet.lang.resolve.DelegationResolver.generateDelegatedMembers;
044    
045    public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescriptor, ClassMemberDeclarationProvider> {
046    
047        @NotNull
048        private static final Set<ClassKind> GENERATE_CONSTRUCTORS_FOR =
049                ImmutableSet.of(ClassKind.CLASS, ClassKind.ANNOTATION_CLASS, ClassKind.OBJECT,
050                                ClassKind.ENUM_CLASS, ClassKind.ENUM_ENTRY, ClassKind.CLASS_OBJECT);
051    
052        private interface MemberExtractor<T extends CallableMemberDescriptor> {
053            MemberExtractor<FunctionDescriptor> EXTRACT_FUNCTIONS = new MemberExtractor<FunctionDescriptor>() {
054                @NotNull
055                @Override
056                public Collection<FunctionDescriptor> extract(@NotNull JetType extractFrom, @NotNull Name name) {
057                    return extractFrom.getMemberScope().getFunctions(name);
058                }
059            };
060    
061            MemberExtractor<PropertyDescriptor> EXTRACT_PROPERTIES = new MemberExtractor<PropertyDescriptor>() {
062                @NotNull
063                @Override
064                public Collection<PropertyDescriptor> extract(@NotNull JetType extractFrom, @NotNull Name name) {
065                    //noinspection unchecked
066                    return (Collection) extractFrom.getMemberScope().getProperties(name);
067                }
068            };
069    
070            @NotNull
071            Collection<T> extract(@NotNull JetType extractFrom, @NotNull Name name);
072        }
073    
074        private final NullableLazyValue<ConstructorDescriptor> primaryConstructor;
075    
076        public LazyClassMemberScope(
077                @NotNull ResolveSession resolveSession,
078                @NotNull ClassMemberDeclarationProvider declarationProvider,
079                @NotNull LazyClassDescriptor thisClass
080        ) {
081            super(resolveSession, declarationProvider, thisClass);
082            this.primaryConstructor = resolveSession.getStorageManager().createNullableLazyValue(new Function0<ConstructorDescriptor>() {
083                @Override
084                public ConstructorDescriptor invoke() {
085                    return resolvePrimaryConstructor();
086                }
087            });
088        }
089    
090        @NotNull
091        @Override
092        protected JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration) {
093            if (declaration instanceof JetProperty) {
094                return thisDescriptor.getScopeForInitializerResolution();
095            }
096            return thisDescriptor.getScopeForMemberDeclarationResolution();
097        }
098    
099        private <D extends CallableMemberDescriptor> void generateFakeOverrides(
100                @NotNull Name name,
101                @NotNull Collection<D> fromSupertypes,
102                @NotNull final Collection<D> result,
103                @NotNull final Class<? extends D> exactDescriptorClass
104        ) {
105            OverridingUtil.generateOverridesInFunctionGroup(
106                    name,
107                    fromSupertypes,
108                    Lists.newArrayList(result),
109                    thisDescriptor,
110                    new OverridingUtil.DescriptorSink() {
111                        @Override
112                        public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
113                            assert exactDescriptorClass.isInstance(fakeOverride) : "Wrong descriptor type in an override: " +
114                                                                                   fakeOverride +
115                                                                                   " while expecting " +
116                                                                                   exactDescriptorClass.getSimpleName();
117                            //noinspection unchecked
118                            result.add((D) fakeOverride);
119                        }
120    
121                        @Override
122                        public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
123                            BindingTrace trace = resolveSession.getTrace();
124                            JetDeclaration declaration = (JetDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(),
125                                                                                                                      fromCurrent);
126                            assert declaration != null : "fromCurrent can not be a fake override";
127                            trace.report(Errors.CONFLICTING_OVERLOADS
128                                                 .on(declaration, fromCurrent, fromCurrent.getContainingDeclaration().getName().asString()));
129                        }
130                    }
131            );
132            OverrideResolver.resolveUnknownVisibilities(result, resolveSession.getTrace());
133        }
134    
135        @NotNull
136        @Override
137        public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
138            // TODO: this should be handled by lazy function descriptors
139            Set<FunctionDescriptor> functions = super.getFunctions(name);
140            for (FunctionDescriptor functionDescriptor : functions) {
141                if (functionDescriptor.getKind() != FAKE_OVERRIDE && functionDescriptor.getKind() != DELEGATION) {
142                    OverrideResolver.resolveUnknownVisibilityForMember(functionDescriptor, resolveSession.getTrace());
143                }
144            }
145            return functions;
146        }
147    
148        @Override
149        protected void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result) {
150            Collection<FunctionDescriptor> fromSupertypes = Lists.newArrayList();
151            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
152                fromSupertypes.addAll(supertype.getMemberScope().getFunctions(name));
153            }
154            result.addAll(generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_FUNCTIONS, result));
155            generateEnumClassObjectMethods(result, name);
156            generateDataClassMethods(result, name);
157            generateFakeOverrides(name, fromSupertypes, result, FunctionDescriptor.class);
158        }
159    
160        private void generateDataClassMethods(@NotNull Collection<FunctionDescriptor> result, @NotNull Name name) {
161            if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return;
162    
163            ConstructorDescriptor constructor = getPrimaryConstructor();
164            if (constructor == null) return;
165    
166            int parameterIndex = 0;
167            for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
168                if (parameter.getType().isError()) continue;
169                Set<VariableDescriptor> properties = getProperties(parameter.getName());
170                if (properties.isEmpty()) continue;
171                assert properties.size() == 1 : "A constructor parameter is resolved to more than one (" + properties.size() + ") property: " + parameter;
172                PropertyDescriptor property = (PropertyDescriptor) properties.iterator().next();
173                if (property == null) continue;
174                ++parameterIndex;
175    
176                if (name.equals(Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + parameterIndex))) {
177                    SimpleFunctionDescriptor functionDescriptor =
178                            DescriptorResolver.createComponentFunctionDescriptor(parameterIndex, property,
179                                                                                 parameter, thisDescriptor, resolveSession.getTrace());
180                    result.add(functionDescriptor);
181                    break;
182                }
183            }
184            if (!constructor.getValueParameters().isEmpty() && name.equals(DescriptorResolver.COPY_METHOD_NAME)) {
185                SimpleFunctionDescriptor copyFunctionDescriptor = DescriptorResolver.createCopyFunctionDescriptor(
186                        constructor.getValueParameters(),
187                        thisDescriptor, resolveSession.getTrace());
188                result.add(copyFunctionDescriptor);
189            }
190        }
191    
192        private void generateEnumClassObjectMethods(@NotNull Collection<? super FunctionDescriptor> result, @NotNull Name name) {
193            if (!DescriptorUtils.isEnumClassObject(thisDescriptor)) return;
194    
195            if (name.equals(DescriptorFactory.VALUES_METHOD_NAME)) {
196                SimpleFunctionDescriptor valuesMethod = DescriptorResolver
197                        .createEnumClassObjectValuesMethod(thisDescriptor, resolveSession.getTrace());
198                result.add(valuesMethod);
199            }
200            else if (name.equals(DescriptorFactory.VALUE_OF_METHOD_NAME)) {
201                SimpleFunctionDescriptor valueOfMethod = DescriptorResolver
202                        .createEnumClassObjectValueOfMethod(thisDescriptor, resolveSession.getTrace());
203                result.add(valueOfMethod);
204            }
205        }
206    
207        @NotNull
208        @Override
209        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
210            // TODO: this should be handled by lazy property descriptors
211            Set<VariableDescriptor> properties = super.getProperties(name);
212            for (VariableDescriptor variableDescriptor : properties) {
213                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
214                if (propertyDescriptor.getKind() == FAKE_OVERRIDE || propertyDescriptor.getKind() == DELEGATION) continue;
215                OverrideResolver.resolveUnknownVisibilityForMember(propertyDescriptor, resolveSession.getTrace());
216            }
217            return properties;
218        }
219    
220        @Override
221        @SuppressWarnings("unchecked")
222        protected void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result) {
223            JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
224    
225            // From primary constructor parameters
226            ConstructorDescriptor primaryConstructor = getPrimaryConstructor();
227            if (primaryConstructor != null) {
228                List<ValueParameterDescriptor> valueParameterDescriptors = primaryConstructor.getValueParameters();
229                List<? extends JetParameter> primaryConstructorParameters = classInfo.getPrimaryConstructorParameters();
230                assert valueParameterDescriptors.size() == primaryConstructorParameters.size() : "From descriptor: " + valueParameterDescriptors.size() + " but from PSI: " + primaryConstructorParameters.size();
231                for (ValueParameterDescriptor valueParameterDescriptor : valueParameterDescriptors) {
232                    JetParameter parameter = primaryConstructorParameters.get(valueParameterDescriptor.getIndex());
233                    if (parameter.getValOrVarNode() != null && name.equals(parameter.getNameAsName())) {
234                        PropertyDescriptor propertyDescriptor =
235                                resolveSession.getDescriptorResolver().resolvePrimaryConstructorParameterToAProperty(
236                                        thisDescriptor,
237                                        valueParameterDescriptor,
238                                        thisDescriptor.getScopeForClassHeaderResolution(),
239                                        parameter, resolveSession.getTrace()
240                                );
241                        result.add(propertyDescriptor);
242                    }
243                }
244            }
245    
246            // Members from supertypes
247            Collection<PropertyDescriptor> fromSupertypes = Lists.newArrayList();
248            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
249                fromSupertypes.addAll((Collection) supertype.getMemberScope().getProperties(name));
250            }
251            result.addAll(generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_PROPERTIES, result));
252            generateFakeOverrides(name, fromSupertypes, (Collection) result, PropertyDescriptor.class);
253        }
254    
255        @NotNull
256        private <T extends CallableMemberDescriptor> Collection<T> generateDelegatingDescriptors(
257                @NotNull final Name name,
258                @NotNull final MemberExtractor<T> extractor,
259                @NotNull Collection<? extends CallableDescriptor> existingDescriptors
260        ) {
261            JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
262            if (classOrObject == null) {
263                // Enum class objects do not have delegated members
264                return Collections.emptySet();
265            }
266    
267            DelegationResolver.TypeResolver lazyTypeResolver = new DelegationResolver.TypeResolver() {
268                @Nullable
269                @Override
270                public JetType resolve(@NotNull JetTypeReference reference) {
271                    return resolveSession.getTypeResolver().resolveType(
272                            thisDescriptor.getScopeForClassHeaderResolution(),
273                            reference,
274                            resolveSession.getTrace(),
275                            false);
276                }
277            };
278            DelegationResolver.MemberExtractor<T> lazyMemberExtractor = new DelegationResolver.MemberExtractor<T>() {
279                @NotNull
280                @Override
281                public Collection<T> getMembersByType(@NotNull JetType type) {
282                    return extractor.extract(type, name);
283                }
284            };
285            return generateDelegatedMembers(classOrObject, thisDescriptor, existingDescriptors, resolveSession.getTrace(), lazyMemberExtractor,
286                                            lazyTypeResolver);
287        }
288    
289        @Override
290        @NotNull
291        protected Collection<DeclarationDescriptor> computeExtraDescriptors() {
292            ArrayList<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>();
293            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
294                for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
295                    if (descriptor instanceof FunctionDescriptor) {
296                        result.addAll(getFunctions(descriptor.getName()));
297                    }
298                    else if (descriptor instanceof PropertyDescriptor) {
299                        result.addAll(getProperties(descriptor.getName()));
300                    }
301                    // Nothing else is inherited
302                }
303            }
304    
305            result.addAll(getFunctions(DescriptorFactory.VALUES_METHOD_NAME));
306            result.addAll(getFunctions(DescriptorFactory.VALUE_OF_METHOD_NAME));
307    
308            addDataClassMethods(result);
309    
310            result.trimToSize();
311            return result;
312        }
313    
314        private void addDataClassMethods(@NotNull Collection<DeclarationDescriptor> result) {
315            if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return;
316    
317            ConstructorDescriptor constructor = getPrimaryConstructor();
318            if (constructor == null) return;
319    
320            // Generate componentN functions until there's no such function for some n
321            int n = 1;
322            while (true) {
323                Name componentName = Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + n);
324                Set<FunctionDescriptor> functions = getFunctions(componentName);
325                if (functions.isEmpty()) break;
326    
327                result.addAll(functions);
328    
329                n++;
330            }
331            result.addAll(getFunctions(Name.identifier("copy")));
332        }
333    
334        @Nullable
335        @Override
336        public PackageViewDescriptor getPackage(@NotNull Name name) {
337            return null;
338        }
339    
340        @NotNull
341        @Override
342        protected ReceiverParameterDescriptor getImplicitReceiver() {
343            return thisDescriptor.getThisAsReceiverParameter();
344        }
345    
346        @NotNull
347        public Set<ConstructorDescriptor> getConstructors() {
348            ConstructorDescriptor constructor = getPrimaryConstructor();
349            return constructor == null ? Collections.<ConstructorDescriptor>emptySet() : Collections.singleton(constructor);
350        }
351    
352        @Nullable
353        public ConstructorDescriptor getPrimaryConstructor() {
354            return primaryConstructor.invoke();
355        }
356    
357        @Nullable
358        private ConstructorDescriptor resolvePrimaryConstructor() {
359            ConstructorDescriptor primaryConstructor = null;
360            if (GENERATE_CONSTRUCTORS_FOR.contains(thisDescriptor.getKind())) {
361                JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
362                if (!thisDescriptor.getKind().isSingleton()) {
363                    JetClass jetClass = (JetClass) classOrObject;
364                    ConstructorDescriptorImpl constructor = resolveSession.getDescriptorResolver()
365                            .resolvePrimaryConstructorDescriptor(thisDescriptor.getScopeForClassHeaderResolution(),
366                                                                 thisDescriptor,
367                                                                 jetClass,
368                                                                 resolveSession.getTrace());
369                    primaryConstructor = constructor;
370                    setDeferredReturnType(constructor);
371                }
372                else {
373                    ConstructorDescriptorImpl constructor =
374                            DescriptorResolver.createAndRecordPrimaryConstructorForObject(classOrObject, thisDescriptor, resolveSession.getTrace());
375                    setDeferredReturnType(constructor);
376                    primaryConstructor = constructor;
377                }
378            }
379            return primaryConstructor;
380        }
381    
382        private void setDeferredReturnType(@NotNull ConstructorDescriptorImpl descriptor) {
383            descriptor.setReturnType(DeferredType.create(resolveSession.getStorageManager(), resolveSession.getTrace(),
384                    new Function0<JetType>() {
385                        @Override
386                        public JetType invoke() {
387                            return thisDescriptor.getDefaultType();
388                        }
389                    })
390            );
391        }
392    
393        @Override
394        public String toString() {
395            // Do not add details here, they may compromise the laziness during debugging
396            return "lazy scope for class " + thisDescriptor.getName();
397        }
398    }