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