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 com.intellij.openapi.util.Computable;
022    import com.intellij.psi.PsiElement;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.jet.lang.descriptors.*;
026    import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
027    import org.jetbrains.jet.lang.diagnostics.Errors;
028    import org.jetbrains.jet.lang.psi.*;
029    import org.jetbrains.jet.lang.resolve.*;
030    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
031    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
032    import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
033    import org.jetbrains.jet.lang.resolve.lazy.storage.NullableLazyValue;
034    import org.jetbrains.jet.lang.resolve.name.Name;
035    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036    import org.jetbrains.jet.lang.types.DeferredType;
037    import org.jetbrains.jet.lang.types.ErrorUtils;
038    import org.jetbrains.jet.lang.types.JetType;
039    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040    import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
041    
042    import java.util.*;
043    
044    public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescriptor, ClassMemberDeclarationProvider> {
045    
046        @NotNull
047        private static final Set<ClassKind> GENERATE_CONSTRUCTORS_FOR =
048                ImmutableSet.of(ClassKind.CLASS, ClassKind.ANNOTATION_CLASS, ClassKind.OBJECT,
049                                ClassKind.ENUM_CLASS, ClassKind.ENUM_ENTRY, ClassKind.CLASS_OBJECT);
050    
051        private interface MemberExtractor<T extends CallableMemberDescriptor> {
052            MemberExtractor<FunctionDescriptor> EXTRACT_FUNCTIONS = new MemberExtractor<FunctionDescriptor>() {
053                @NotNull
054                @Override
055                public Collection<FunctionDescriptor> extract(@NotNull JetType extractFrom, @NotNull Name name) {
056                    return extractFrom.getMemberScope().getFunctions(name);
057                }
058            };
059    
060            MemberExtractor<PropertyDescriptor> EXTRACT_PROPERTIES = new MemberExtractor<PropertyDescriptor>() {
061                @NotNull
062                @Override
063                public Collection<PropertyDescriptor> extract(@NotNull JetType extractFrom, @NotNull Name name) {
064                    //noinspection unchecked
065                    return (Collection) extractFrom.getMemberScope().getProperties(name);
066                }
067            };
068    
069            @NotNull
070            Collection<T> extract(@NotNull JetType extractFrom, @NotNull Name name);
071        }
072    
073        private final NullableLazyValue<ConstructorDescriptor> primaryConstructor;
074    
075        public LazyClassMemberScope(
076                @NotNull ResolveSession resolveSession,
077                @NotNull ClassMemberDeclarationProvider declarationProvider,
078                @NotNull LazyClassDescriptor thisClass
079        ) {
080            super(resolveSession, declarationProvider, thisClass);
081            this.primaryConstructor = resolveSession.getStorageManager().createNullableLazyValue(new Computable<ConstructorDescriptor>() {
082                @Override
083                public ConstructorDescriptor compute() {
084                    return resolvePrimaryConstructor();
085                }
086            });
087        }
088    
089        @NotNull
090        @Override
091        protected JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration) {
092            if (declaration instanceof JetProperty) {
093                return thisDescriptor.getScopeForPropertyInitializerResolution();
094            }
095            return thisDescriptor.getScopeForMemberDeclarationResolution();
096        }
097    
098        private <D extends CallableMemberDescriptor> void generateFakeOverrides(
099                @NotNull Name name,
100                @NotNull Collection<D> fromSupertypes,
101                @NotNull final Collection<D> result,
102                @NotNull final Class<? extends D> exactDescriptorClass
103        ) {
104            OverrideResolver.generateOverridesInFunctionGroup(
105                    name,
106                    fromSupertypes,
107                    Lists.newArrayList(result),
108                    thisDescriptor,
109                    new OverrideResolver.DescriptorSink() {
110                        @Override
111                        public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
112                            assert exactDescriptorClass.isInstance(fakeOverride) : "Wrong descriptor type in an override: " +
113                                                                                   fakeOverride +
114                                                                                   " while expecting " +
115                                                                                   exactDescriptorClass.getSimpleName();
116                            //noinspection unchecked
117                            result.add((D) fakeOverride);
118                        }
119    
120                        @Override
121                        public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
122                            BindingTrace trace = resolveSession.getTrace();
123                            JetDeclaration declaration = (JetDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(),
124                                                                                                                      fromCurrent);
125                            assert declaration != null : "fromCurrent can not be a fake override";
126                            trace.report(Errors.CONFLICTING_OVERLOADS
127                                                 .on(declaration, fromCurrent, fromCurrent.getContainingDeclaration().getName().asString()));
128                        }
129                    }
130            );
131            OverrideResolver.resolveUnknownVisibilities(result, resolveSession.getTrace());
132        }
133    
134        @NotNull
135        @Override
136        public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
137            // TODO: this should be handled by lazy function descriptors
138            Set<FunctionDescriptor> functions = super.getFunctions(name);
139            for (FunctionDescriptor functionDescriptor : functions) {
140                if (functionDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue;
141                PsiElement element =
142                        BindingContextUtils.callableDescriptorToDeclaration(resolveSession.getTrace().getBindingContext(), functionDescriptor);
143                OverrideResolver.resolveUnknownVisibilityForMember((JetDeclaration) element, functionDescriptor, resolveSession.getTrace());
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            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 (ErrorUtils.isErrorType(parameter.getType())) 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(DescriptorResolver.VALUES_METHOD_NAME)) {
196                SimpleFunctionDescriptor valuesMethod = DescriptorResolver
197                        .createEnumClassObjectValuesMethod(thisDescriptor, resolveSession.getTrace());
198                result.add(valuesMethod);
199            }
200            else if (name.equals(DescriptorResolver.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() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue;
215                PsiElement element =
216                        BindingContextUtils.callableDescriptorToDeclaration(resolveSession.getTrace().getBindingContext(), propertyDescriptor);
217                OverrideResolver.resolveUnknownVisibilityForMember((JetDeclaration) element, propertyDescriptor, resolveSession.getTrace());
218            }
219            return properties;
220        }
221    
222        @Override
223        @SuppressWarnings("unchecked")
224        protected void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result) {
225            JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
226    
227            // From primary constructor parameters
228            ConstructorDescriptor primaryConstructor = getPrimaryConstructor();
229            if (primaryConstructor != null) {
230                List<ValueParameterDescriptor> valueParameterDescriptors = primaryConstructor.getValueParameters();
231                List<? extends JetParameter> primaryConstructorParameters = classInfo.getPrimaryConstructorParameters();
232                assert valueParameterDescriptors.size() == primaryConstructorParameters.size() : "From descriptor: " + valueParameterDescriptors.size() + " but from PSI: " + primaryConstructorParameters.size();
233                for (ValueParameterDescriptor valueParameterDescriptor : valueParameterDescriptors) {
234                    JetParameter parameter = primaryConstructorParameters.get(valueParameterDescriptor.getIndex());
235                    if (parameter.getValOrVarNode() != null && name.equals(parameter.getNameAsName())) {
236                        PropertyDescriptor propertyDescriptor =
237                                resolveSession.getInjector().getDescriptorResolver().resolvePrimaryConstructorParameterToAProperty(
238                                        thisDescriptor,
239                                        valueParameterDescriptor,
240                                        thisDescriptor.getScopeForClassHeaderResolution(),
241                                        parameter, resolveSession.getTrace()
242                                );
243                        result.add(propertyDescriptor);
244                    }
245                }
246            }
247    
248            // Members from supertypes
249            Collection<PropertyDescriptor> fromSupertypes = Lists.newArrayList();
250            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
251                fromSupertypes.addAll((Set) supertype.getMemberScope().getProperties(name));
252            }
253            generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_PROPERTIES, result);
254            generateFakeOverrides(name, fromSupertypes, (Set) result, PropertyDescriptor.class);
255        }
256    
257        private <T extends CallableMemberDescriptor> void generateDelegatingDescriptors(
258                @NotNull Name name,
259                @NotNull MemberExtractor<T> extractor,
260                @NotNull Set<? super T> result
261        ) {
262            for (JetDelegationSpecifier delegationSpecifier : declarationProvider.getOwnerInfo().getDelegationSpecifiers()) {
263                if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) {
264                    JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
265                    JetTypeReference typeReference = specifier.getTypeReference();
266                    if (typeReference != null) {
267                        JetType supertype = resolveSession.getInjector().getTypeResolver().resolveType(
268                                thisDescriptor.getScopeForClassHeaderResolution(),
269                                typeReference,
270                                resolveSession.getTrace(),
271                                false);
272                        Collection<T> descriptors =
273                                DelegationResolver.generateDelegatedMembers(thisDescriptor, extractor.extract(supertype, name));
274                        result.addAll(descriptors);
275                    }
276                }
277            }
278        }
279    
280        @Override
281        protected void addExtraDescriptors(@NotNull Collection<DeclarationDescriptor> result) {
282            for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) {
283                for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
284                    if (descriptor instanceof FunctionDescriptor) {
285                        result.addAll(getFunctions(descriptor.getName()));
286                    }
287                    else if (descriptor instanceof PropertyDescriptor) {
288                        result.addAll(getProperties(descriptor.getName()));
289                    }
290                    // Nothing else is inherited
291                }
292            }
293    
294            result.addAll(getFunctions(DescriptorResolver.VALUES_METHOD_NAME));
295            result.addAll(getFunctions(DescriptorResolver.VALUE_OF_METHOD_NAME));
296    
297            addDataClassMethods(result);
298        }
299    
300        private void addDataClassMethods(@NotNull Collection<DeclarationDescriptor> result) {
301            if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return;
302    
303            ConstructorDescriptor constructor = getPrimaryConstructor();
304            if (constructor == null) return;
305    
306            // Generate componentN functions until there's no such function for some n
307            int n = 1;
308            while (true) {
309                Name componentName = Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + n);
310                Set<FunctionDescriptor> functions = getFunctions(componentName);
311                if (functions.isEmpty()) break;
312    
313                result.addAll(functions);
314    
315                n++;
316            }
317            result.addAll(getFunctions(Name.identifier("copy")));
318        }
319    
320        @Override
321        public NamespaceDescriptor getNamespace(@NotNull Name name) {
322            return null;
323        }
324    
325        @NotNull
326        @Override
327        protected ReceiverParameterDescriptor getImplicitReceiver() {
328            return thisDescriptor.getThisAsReceiverParameter();
329        }
330    
331        @NotNull
332        public Set<ConstructorDescriptor> getConstructors() {
333            ConstructorDescriptor constructor = getPrimaryConstructor();
334            return constructor == null ? Collections.<ConstructorDescriptor>emptySet() : Collections.singleton(constructor);
335        }
336    
337        @Nullable
338        public ConstructorDescriptor getPrimaryConstructor() {
339            return primaryConstructor.compute();
340        }
341    
342        @Nullable
343        private ConstructorDescriptor resolvePrimaryConstructor() {
344            ConstructorDescriptor primaryConstructor = null;
345            if (GENERATE_CONSTRUCTORS_FOR.contains(thisDescriptor.getKind())) {
346                JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
347                if (!thisDescriptor.getKind().isObject()) {
348                    JetClass jetClass = (JetClass) classOrObject;
349                    ConstructorDescriptorImpl constructor = resolveSession.getInjector().getDescriptorResolver()
350                            .resolvePrimaryConstructorDescriptor(thisDescriptor.getScopeForClassHeaderResolution(),
351                                                                 thisDescriptor,
352                                                                 jetClass,
353                                                                 resolveSession.getTrace());
354                    primaryConstructor = constructor;
355                    setDeferredReturnType(constructor);
356                }
357                else {
358                    ConstructorDescriptorImpl constructor =
359                            DescriptorResolver.createAndRecordPrimaryConstructorForObject(classOrObject, thisDescriptor, resolveSession.getTrace());
360                    setDeferredReturnType(constructor);
361                    primaryConstructor = constructor;
362                }
363            }
364            return primaryConstructor;
365        }
366    
367        private void setDeferredReturnType(@NotNull ConstructorDescriptorImpl descriptor) {
368            descriptor.setReturnType(DeferredType.create(resolveSession.getTrace(), new RecursionIntolerantLazyValue<JetType>() {
369                @Override
370                protected JetType compute() {
371                    return thisDescriptor.getDefaultType();
372                }
373            }));
374        }
375    
376        @Override
377        public String toString() {
378            // Do not add details here, they may compromise the laziness during debugging
379            return "lazy scope for class " + thisDescriptor.getName();
380        }
381    }