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                @NotNull BindingTrace trace
081        ) {
082            super(resolveSession, declarationProvider, thisClass, trace);
083            this.primaryConstructor = resolveSession.getStorageManager().createNullableLazyValue(new Function0<ConstructorDescriptor>() {
084                @Override
085                public ConstructorDescriptor invoke() {
086                    return resolvePrimaryConstructor();
087                }
088            });
089        }
090    
091        @NotNull
092        @Override
093        protected JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration) {
094            if (declaration instanceof JetProperty) {
095                return thisDescriptor.getScopeForInitializerResolution();
096            }
097            return thisDescriptor.getScopeForMemberDeclarationResolution();
098        }
099    
100        private <D extends CallableMemberDescriptor> void generateFakeOverrides(
101                @NotNull Name name,
102                @NotNull Collection<D> fromSupertypes,
103                @NotNull final Collection<D> result,
104                @NotNull final Class<? extends D> exactDescriptorClass
105        ) {
106            OverridingUtil.generateOverridesInFunctionGroup(
107                    name,
108                    fromSupertypes,
109                    Lists.newArrayList(result),
110                    thisDescriptor,
111                    new OverridingUtil.DescriptorSink() {
112                        @Override
113                        public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
114                            assert exactDescriptorClass.isInstance(fakeOverride) : "Wrong descriptor type in an override: " +
115                                                                                   fakeOverride +
116                                                                                   " while expecting " +
117                                                                                   exactDescriptorClass.getSimpleName();
118                            //noinspection unchecked
119                            result.add((D) fakeOverride);
120                        }
121    
122                        @Override
123                        public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
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, trace);
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            resolveUnknownVisibilitiesForMembers(functions);
141            return functions;
142        }
143    
144        @Override
145        protected void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result) {
146            Collection<FunctionDescriptor> fromSupertypes = Lists.newArrayList();
147            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
148                fromSupertypes.addAll(supertype.getMemberScope().getFunctions(name));
149            }
150            result.addAll(generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_FUNCTIONS, result));
151            generateEnumClassObjectMethods(result, name);
152            generateDataClassMethods(result, name);
153            generateFakeOverrides(name, fromSupertypes, result, FunctionDescriptor.class);
154        }
155    
156        private void generateDataClassMethods(@NotNull Collection<FunctionDescriptor> result, @NotNull Name name) {
157            if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return;
158    
159            ConstructorDescriptor constructor = getPrimaryConstructor();
160            if (constructor == null) return;
161    
162            int parameterIndex = 0;
163            for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
164                if (parameter.getType().isError()) continue;
165                Set<VariableDescriptor> properties = getProperties(parameter.getName());
166                if (properties.isEmpty()) continue;
167                assert properties.size() == 1 : "A constructor parameter is resolved to more than one (" + properties.size() + ") property: " + parameter;
168                PropertyDescriptor property = (PropertyDescriptor) properties.iterator().next();
169                if (property == null) continue;
170                ++parameterIndex;
171    
172                if (name.equals(Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + parameterIndex))) {
173                    SimpleFunctionDescriptor functionDescriptor =
174                            DescriptorResolver.createComponentFunctionDescriptor(parameterIndex, property,
175                                                                                 parameter, thisDescriptor, trace);
176                    result.add(functionDescriptor);
177                    break;
178                }
179            }
180            if (!constructor.getValueParameters().isEmpty() && name.equals(DescriptorResolver.COPY_METHOD_NAME)) {
181                SimpleFunctionDescriptor copyFunctionDescriptor = DescriptorResolver.createCopyFunctionDescriptor(
182                        constructor.getValueParameters(),
183                        thisDescriptor, trace);
184                result.add(copyFunctionDescriptor);
185            }
186        }
187    
188        private void generateEnumClassObjectMethods(@NotNull Collection<? super FunctionDescriptor> result, @NotNull Name name) {
189            if (!DescriptorUtils.isEnumClassObject(thisDescriptor)) return;
190    
191            if (name.equals(DescriptorFactory.VALUES_METHOD_NAME)) {
192                SimpleFunctionDescriptor valuesMethod = DescriptorResolver
193                        .createEnumClassObjectValuesMethod(thisDescriptor, trace);
194                result.add(valuesMethod);
195            }
196            else if (name.equals(DescriptorFactory.VALUE_OF_METHOD_NAME)) {
197                SimpleFunctionDescriptor valueOfMethod = DescriptorResolver
198                        .createEnumClassObjectValueOfMethod(thisDescriptor, trace);
199                result.add(valueOfMethod);
200            }
201        }
202    
203        @NotNull
204        @Override
205        @SuppressWarnings("unchecked")
206        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
207            // TODO: this should be handled by lazy property descriptors
208            Set<VariableDescriptor> properties = super.getProperties(name);
209            resolveUnknownVisibilitiesForMembers((Set) properties);
210            return properties;
211        }
212    
213        private void resolveUnknownVisibilitiesForMembers(@NotNull Set<? extends CallableMemberDescriptor> descriptors) {
214            for (CallableMemberDescriptor descriptor : descriptors) {
215                if (descriptor.getKind() != FAKE_OVERRIDE && descriptor.getKind() != DELEGATION) {
216                    OverridingUtil.resolveUnknownVisibilityForMember(descriptor, OverrideResolver.createCannotInferVisibilityReporter(trace));
217                }
218            }
219        }
220    
221        @Override
222        @SuppressWarnings("unchecked")
223        protected void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result) {
224            createPropertiesFromPrimaryConstructorParameters(name, result);
225    
226            // Members from supertypes
227            Collection<PropertyDescriptor> fromSupertypes = Lists.newArrayList();
228            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
229                fromSupertypes.addAll((Collection) supertype.getMemberScope().getProperties(name));
230            }
231            result.addAll(generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_PROPERTIES, result));
232            generateFakeOverrides(name, fromSupertypes, (Collection) result, PropertyDescriptor.class);
233        }
234    
235        protected void createPropertiesFromPrimaryConstructorParameters(@NotNull Name name, @NotNull Set<VariableDescriptor> result) {
236            JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
237    
238            // From primary constructor parameters
239            ConstructorDescriptor primaryConstructor = getPrimaryConstructor();
240            if (primaryConstructor == null) return;
241    
242            List<ValueParameterDescriptor> valueParameterDescriptors = primaryConstructor.getValueParameters();
243            List<? extends JetParameter> primaryConstructorParameters = classInfo.getPrimaryConstructorParameters();
244            assert valueParameterDescriptors.size() == primaryConstructorParameters.size()
245                    : "From descriptor: " + valueParameterDescriptors.size() + " but from PSI: " + primaryConstructorParameters.size();
246    
247            for (ValueParameterDescriptor valueParameterDescriptor : valueParameterDescriptors) {
248                if (!name.equals(valueParameterDescriptor.getName())) continue;
249    
250                JetParameter parameter = primaryConstructorParameters.get(valueParameterDescriptor.getIndex());
251                if (parameter.hasValOrVarNode()) {
252                    PropertyDescriptor propertyDescriptor =
253                            resolveSession.getDescriptorResolver().resolvePrimaryConstructorParameterToAProperty(
254                                    thisDescriptor,
255                                    valueParameterDescriptor,
256                                    thisDescriptor.getScopeForClassHeaderResolution(),
257                                    parameter, trace
258                            );
259                    result.add(propertyDescriptor);
260                }
261            }
262        }
263    
264        @NotNull
265        private <T extends CallableMemberDescriptor> Collection<T> generateDelegatingDescriptors(
266                @NotNull final Name name,
267                @NotNull final MemberExtractor<T> extractor,
268                @NotNull Collection<? extends CallableDescriptor> existingDescriptors
269        ) {
270            JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
271            if (classOrObject == null) {
272                // Enum class objects do not have delegated members
273                return Collections.emptySet();
274            }
275    
276            DelegationResolver.TypeResolver lazyTypeResolver = new DelegationResolver.TypeResolver() {
277                @Nullable
278                @Override
279                public JetType resolve(@NotNull JetTypeReference reference) {
280                    return resolveSession.getTypeResolver().resolveType(
281                            thisDescriptor.getScopeForClassHeaderResolution(),
282                            reference,
283                            trace,
284                            false);
285                }
286            };
287            DelegationResolver.MemberExtractor<T> lazyMemberExtractor = new DelegationResolver.MemberExtractor<T>() {
288                @NotNull
289                @Override
290                public Collection<T> getMembersByType(@NotNull JetType type) {
291                    return extractor.extract(type, name);
292                }
293            };
294            return generateDelegatedMembers(classOrObject, thisDescriptor, existingDescriptors, trace, lazyMemberExtractor,
295                                            lazyTypeResolver);
296        }
297    
298        @Override
299        @NotNull
300        protected Collection<DeclarationDescriptor> computeExtraDescriptors() {
301            ArrayList<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>();
302            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
303                for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
304                    if (descriptor instanceof FunctionDescriptor) {
305                        result.addAll(getFunctions(descriptor.getName()));
306                    }
307                    else if (descriptor instanceof PropertyDescriptor) {
308                        result.addAll(getProperties(descriptor.getName()));
309                    }
310                    // Nothing else is inherited
311                }
312            }
313    
314            result.addAll(getFunctions(DescriptorFactory.VALUES_METHOD_NAME));
315            result.addAll(getFunctions(DescriptorFactory.VALUE_OF_METHOD_NAME));
316    
317            addDataClassMethods(result);
318    
319            result.trimToSize();
320            return result;
321        }
322    
323        private void addDataClassMethods(@NotNull Collection<DeclarationDescriptor> result) {
324            if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return;
325    
326            ConstructorDescriptor constructor = getPrimaryConstructor();
327            if (constructor == null) return;
328    
329            // Generate componentN functions until there's no such function for some n
330            int n = 1;
331            while (true) {
332                Name componentName = Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + n);
333                Set<FunctionDescriptor> functions = getFunctions(componentName);
334                if (functions.isEmpty()) break;
335    
336                result.addAll(functions);
337    
338                n++;
339            }
340            result.addAll(getFunctions(Name.identifier("copy")));
341        }
342    
343        @Nullable
344        @Override
345        public PackageViewDescriptor getPackage(@NotNull Name name) {
346            return null;
347        }
348    
349        @NotNull
350        @Override
351        protected ReceiverParameterDescriptor getImplicitReceiver() {
352            return thisDescriptor.getThisAsReceiverParameter();
353        }
354    
355        @NotNull
356        public Set<ConstructorDescriptor> getConstructors() {
357            ConstructorDescriptor constructor = getPrimaryConstructor();
358            return constructor == null ? Collections.<ConstructorDescriptor>emptySet() : Collections.singleton(constructor);
359        }
360    
361        @Nullable
362        public ConstructorDescriptor getPrimaryConstructor() {
363            return primaryConstructor.invoke();
364        }
365    
366        @Nullable
367        protected ConstructorDescriptor resolvePrimaryConstructor() {
368            if (GENERATE_CONSTRUCTORS_FOR.contains(thisDescriptor.getKind())) {
369                JetClassLikeInfo ownerInfo = declarationProvider.getOwnerInfo();
370                JetClassOrObject classOrObject = ownerInfo.getCorrespondingClassOrObject();
371                if (!thisDescriptor.getKind().isSingleton()) {
372                    JetClass jetClass = (JetClass) classOrObject;
373                    assert jetClass != null : "No JetClass for " + thisDescriptor;
374                    ConstructorDescriptorImpl constructor = resolveSession.getDescriptorResolver()
375                            .resolvePrimaryConstructorDescriptor(thisDescriptor.getScopeForClassHeaderResolution(),
376                                                                 thisDescriptor,
377                                                                 jetClass,
378                                                                 trace);
379                    assert constructor != null : "No constructor created for " + thisDescriptor;
380                    setDeferredReturnType(constructor);
381                    return constructor;
382                }
383                else {
384                    ConstructorDescriptorImpl constructor =
385                            DescriptorResolver.createAndRecordPrimaryConstructorForObject(classOrObject, thisDescriptor, trace);
386                    setDeferredReturnType(constructor);
387                    return constructor;
388                }
389            }
390            return null;
391        }
392    
393        protected void setDeferredReturnType(@NotNull ConstructorDescriptorImpl descriptor) {
394            descriptor.setReturnType(DeferredType.create(resolveSession.getStorageManager(), trace,
395                    new Function0<JetType>() {
396                        @Override
397                        public JetType invoke() {
398                            return thisDescriptor.getDefaultType();
399                        }
400                    })
401            );
402        }
403    
404        @Override
405        public String toString() {
406            // Do not add details here, they may compromise the laziness during debugging
407            return "lazy scope for class " + thisDescriptor.getName();
408        }
409    }