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