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