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