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.descriptors.serialization.descriptors;
018    
019    import jet.Function0;
020    import jet.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.descriptors.serialization.*;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.*;
027    import org.jetbrains.jet.lang.resolve.DescriptorFactory;
028    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
029    import org.jetbrains.jet.lang.resolve.OverridingUtil;
030    import org.jetbrains.jet.lang.resolve.name.Name;
031    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
032    import org.jetbrains.jet.lang.types.ErrorUtils;
033    import org.jetbrains.jet.lang.types.JetType;
034    import org.jetbrains.jet.lang.types.TypeConstructor;
035    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036    import org.jetbrains.jet.storage.MemoizedFunctionToNullable;
037    import org.jetbrains.jet.storage.NotNullLazyValue;
038    import org.jetbrains.jet.storage.NullableLazyValue;
039    import org.jetbrains.jet.storage.StorageManager;
040    
041    import java.util.*;
042    
043    import static org.jetbrains.jet.descriptors.serialization.TypeDeserializer.TypeParameterResolver.NONE;
044    import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
045    import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
046    
047    public class DeserializedClassDescriptor extends AbstractClassDescriptor implements ClassDescriptor {
048    
049        private final ClassId classId;
050        private final ProtoBuf.Class classProto;
051        private final TypeDeserializer typeDeserializer;
052        private final DescriptorDeserializer deserializer;
053        private final DeserializedMemberScope memberScope;
054    
055        private final NullableLazyValue<ConstructorDescriptor> primaryConstructor;
056    
057        private final AnnotationDeserializer annotationDeserializer;
058        private final NotNullLazyValue<List<AnnotationDescriptor>> annotations;
059    
060        private final NullableLazyValue<ClassDescriptor> classObjectDescriptor;
061    
062        private final NestedClassDescriptors nestedClasses;
063        private final NestedClassDescriptors nestedObjects;
064    
065        private final NotNullLazyValue<DeclarationDescriptor> containingDeclaration;
066        private final DeserializedClassTypeConstructor typeConstructor;
067        private final Modality modality;
068        private final Visibility visibility;
069        private final ClassKind kind;
070        private final boolean isInner;
071        private final DescriptorFinder descriptorFinder;
072    
073        public DeserializedClassDescriptor(
074                @NotNull StorageManager storageManager,
075                @NotNull AnnotationDeserializer annotationResolver,
076                @NotNull DescriptorFinder descriptorFinder,
077                @NotNull ClassData classData
078        ) {
079            super(storageManager,
080                  classData.getNameResolver().getClassId(classData.getClassProto().getFqName()).getRelativeClassName().shortName());
081            NameResolver nameResolver = classData.getNameResolver();
082            this.classProto = classData.getClassProto();
083    
084            this.classId = nameResolver.getClassId(classProto.getFqName());
085            this.descriptorFinder = descriptorFinder;
086    
087            TypeDeserializer notNullTypeDeserializer = new TypeDeserializer(storageManager, null, nameResolver,
088                                                                            descriptorFinder, "Deserializer for class " + getName(), NONE);
089            DescriptorDeserializer outerDeserializer = DescriptorDeserializer.create(storageManager, notNullTypeDeserializer,
090                                                                                     this, nameResolver, annotationResolver);
091            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(classProto.getTypeParameterCount());
092            this.deserializer = outerDeserializer.createChildDeserializer(this, classProto.getTypeParameterList(), typeParameters);
093            this.typeDeserializer = deserializer.getTypeDeserializer();
094    
095            this.containingDeclaration = storageManager.createLazyValue(new Function0<DeclarationDescriptor>() {
096                @Override
097                public DeclarationDescriptor invoke() {
098                    return computeContainingDeclaration();
099                }
100            });
101    
102            this.typeConstructor = new DeserializedClassTypeConstructor(typeParameters);
103            this.memberScope = new DeserializedClassMemberScope(storageManager, this);
104    
105            int flags = classProto.getFlags();
106            this.modality = DescriptorDeserializer.modality(Flags.MODALITY.get(flags));
107            this.visibility = DescriptorDeserializer.visibility(Flags.VISIBILITY.get(flags));
108            this.kind = DescriptorDeserializer.classKind(Flags.CLASS_KIND.get(flags));
109            this.isInner = Flags.INNER.get(flags);
110    
111            this.annotationDeserializer = annotationResolver;
112            this.annotations = storageManager.createLazyValue(new Function0<List<AnnotationDescriptor>>() {
113                @Override
114                public List<AnnotationDescriptor> invoke() {
115                    return computeAnnotations();
116                }
117            });
118    
119            this.primaryConstructor = storageManager.createNullableLazyValue(new Function0<ConstructorDescriptor>() {
120                @Override
121                public ConstructorDescriptor invoke() {
122                    return computePrimaryConstructor();
123                }
124            });
125    
126            this.classObjectDescriptor = storageManager.createNullableLazyValue(new Function0<ClassDescriptor>() {
127                @Override
128                public ClassDescriptor invoke() {
129                    return computeClassObjectDescriptor();
130                }
131            });
132            this.nestedClasses = new NestedClassDescriptors(storageManager, names(classProto.getNestedClassNameList(), nameResolver));
133            this.nestedObjects = new NestedClassDescriptors(storageManager, names(classProto.getNestedObjectNameList(), nameResolver));
134        }
135    
136        @NotNull
137        private static Set<Name> names(@NotNull List<Integer> nameIndices, @NotNull NameResolver nameResolver) {
138            Set<Name> result = new HashSet<Name>(nameIndices.size());
139            for (Integer index : nameIndices) {
140                result.add(nameResolver.getName(index));
141            }
142            return result;
143        }
144    
145        @NotNull
146        @Override
147        public DeclarationDescriptor getContainingDeclaration() {
148            return containingDeclaration.invoke();
149        }
150    
151        @NotNull
152        private DeclarationDescriptor computeContainingDeclaration() {
153            ClassOrNamespaceDescriptor result = classId.isTopLevelClass() ?
154                                                descriptorFinder.findPackage(classId.getPackageFqName()) :
155                                                descriptorFinder.findClass(classId.getOuterClassId());
156            return result != null ? result : ErrorUtils.getErrorModule();
157        }
158    
159        @NotNull
160        @Override
161        public TypeConstructor getTypeConstructor() {
162            return typeConstructor;
163        }
164    
165    
166        @NotNull
167        @Override
168        public ClassKind getKind() {
169            return kind;
170        }
171    
172        @NotNull
173        @Override
174        public Modality getModality() {
175            return modality;
176        }
177    
178        @NotNull
179        @Override
180        public Visibility getVisibility() {
181            return visibility;
182        }
183    
184        @Override
185        public boolean isInner() {
186            return isInner;
187        }
188    
189        private List<AnnotationDescriptor> computeAnnotations() {
190            if (!Flags.HAS_ANNOTATIONS.get(classProto.getFlags())) {
191                return Collections.emptyList();
192            }
193            return annotationDeserializer.loadClassAnnotations(this, classProto);
194        }
195    
196        @NotNull
197        @Override
198        public List<AnnotationDescriptor> getAnnotations() {
199            return annotations.invoke();
200        }
201    
202        @NotNull
203        @Override
204        protected JetScope getScopeForMemberLookup() {
205            return memberScope;
206        }
207    
208        @Nullable
209        private ConstructorDescriptor computePrimaryConstructor() {
210            if (!classProto.hasPrimaryConstructor()) return null;
211    
212            ProtoBuf.Callable constructorProto = classProto.getPrimaryConstructor();
213            return (ConstructorDescriptor) deserializer.loadCallable(constructorProto);
214        }
215    
216        @Nullable
217        @Override
218        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
219            return primaryConstructor.invoke();
220        }
221    
222        @NotNull
223        @Override
224        public Collection<ConstructorDescriptor> getConstructors() {
225            ConstructorDescriptor constructor = getUnsubstitutedPrimaryConstructor();
226            if (constructor == null) {
227                return Collections.emptyList();
228            }
229            // TODO: other constructors
230            return Collections.singletonList(constructor);
231        }
232    
233        @Nullable
234        private ClassDescriptor computeClassObjectDescriptor() {
235            if (!classProto.getClassObjectPresent()) {
236                return null;
237            }
238    
239            if (getKind() == ClassKind.ENUM_CLASS) {
240                MutableClassDescriptor classObject = createEnumClassObject();
241    
242                for (int enumEntry : classProto.getEnumEntryList()) {
243                    createEnumEntry(classObject, deserializer.getNameResolver().getName(enumEntry));
244                }
245    
246                return classObject;
247            }
248    
249            return descriptorFinder.findClass(classId.createNestedClassId(getClassObjectName(getName())));
250        }
251    
252        @NotNull
253        private MutableClassDescriptor createEnumClassObject() {
254            MutableClassDescriptor classObject = new MutableClassDescriptor(this, getScopeForMemberLookup(), ClassKind.CLASS_OBJECT,
255                                                                            false, getClassObjectName(getName()));
256            classObject.setModality(Modality.FINAL);
257            classObject.setVisibility(DescriptorUtils.getSyntheticClassObjectVisibility());
258            classObject.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
259            classObject.setPrimaryConstructor(DescriptorFactory.createPrimaryConstructorForObject(classObject));
260            classObject.createTypeConstructor();
261    
262            JetType enumType = getDefaultType();
263            JetType enumArrayType = KotlinBuiltIns.getInstance().getArrayType(enumType);
264            classObject.getBuilder().addFunctionDescriptor(DescriptorFactory.createEnumClassObjectValuesMethod(classObject, enumArrayType));
265            classObject.getBuilder().addFunctionDescriptor(DescriptorFactory.createEnumClassObjectValueOfMethod(classObject, enumType));
266    
267            return classObject;
268        }
269    
270        private void createEnumEntry(@NotNull MutableClassDescriptor enumClassObject, @NotNull Name name) {
271            PropertyDescriptorImpl property = new PropertyDescriptorForObjectImpl(enumClassObject,
272                                                                                  Collections.<AnnotationDescriptor>emptyList(),
273                                                                                  Visibilities.PUBLIC, name, this);
274            property.setType(getDefaultType(), Collections.<TypeParameterDescriptor>emptyList(),
275                             enumClassObject.getThisAsReceiverParameter(), NO_RECEIVER_PARAMETER);
276    
277            PropertyGetterDescriptorImpl getter = DescriptorFactory.createDefaultGetter(property);
278            getter.initialize(property.getReturnType());
279            property.initialize(getter, null);
280    
281            enumClassObject.getBuilder().addPropertyDescriptor(property);
282        }
283    
284        @Nullable
285        @Override
286        public ClassDescriptor getClassObjectDescriptor() {
287            return classObjectDescriptor.invoke();
288        }
289    
290        private Collection<JetType> computeSuperTypes() {
291            List<JetType> supertypes = new ArrayList<JetType>(classProto.getSupertypeCount());
292            for (ProtoBuf.Type supertype : classProto.getSupertypeList()) {
293                supertypes.add(typeDeserializer.type(supertype));
294            }
295            return supertypes;
296        }
297    
298        @Override
299        public String toString() {
300            return "deserialized class " + getName().toString();
301        }
302    
303        private class DeserializedClassTypeConstructor implements TypeConstructor {
304            private final Collection<JetType> supertypes = computeSuperTypes();
305            private final List<TypeParameterDescriptor> parameters;
306    
307            public DeserializedClassTypeConstructor(@NotNull List<TypeParameterDescriptor> typeParameters) {
308                parameters = typeParameters;
309            }
310    
311            @NotNull
312            @Override
313            public List<TypeParameterDescriptor> getParameters() {
314                return parameters;
315            }
316    
317            @NotNull
318            @Override
319            public Collection<JetType> getSupertypes() {
320                return supertypes;
321            }
322    
323            @Override
324            public boolean isFinal() {
325                return !getModality().isOverridable();
326            }
327    
328            @Override
329            public boolean isDenotable() {
330                return true;
331            }
332    
333            @Nullable
334            @Override
335            public ClassifierDescriptor getDeclarationDescriptor() {
336                return DeserializedClassDescriptor.this;
337            }
338    
339            @NotNull
340            @Override
341            public List<AnnotationDescriptor> getAnnotations() {
342                return Collections.emptyList(); // TODO
343            }
344    
345            @Override
346            public String toString() {
347                return getName().toString();
348            }
349        }
350    
351        private static class DeserializedClassMemberScope extends DeserializedMemberScope {
352            private final DeserializedClassDescriptor classDescriptor;
353    
354            public DeserializedClassMemberScope(@NotNull StorageManager storageManager, @NotNull DeserializedClassDescriptor classDescriptor) {
355                super(storageManager, classDescriptor, classDescriptor.deserializer, classDescriptor.classProto.getMemberList());
356                this.classDescriptor = classDescriptor;
357            }
358    
359            @Override
360            protected void computeNonDeclaredFunctions(
361                    @NotNull Name name, @NotNull Collection<FunctionDescriptor> functions
362            ) {
363                Collection<FunctionDescriptor> fromSupertypes = new ArrayList<FunctionDescriptor>();
364                for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
365                    fromSupertypes.addAll(supertype.getMemberScope().getFunctions(name));
366                }
367                generateFakeOverrides(name, fromSupertypes, functions);
368            }
369    
370            @Override
371            protected void computeNonDeclaredProperties(
372                    @NotNull Name name, @NotNull Collection<PropertyDescriptor> property
373            ) {
374                Collection<PropertyDescriptor> fromSupertypes = new ArrayList<PropertyDescriptor>();
375                for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
376                    //noinspection unchecked
377                    fromSupertypes.addAll((Collection) supertype.getMemberScope().getProperties(name));
378                }
379                generateFakeOverrides(name, fromSupertypes, property);
380            }
381    
382            private <D extends CallableMemberDescriptor> void generateFakeOverrides(
383                    @NotNull Name name,
384                    @NotNull Collection<D> fromSupertypes,
385                    @NotNull final Collection<D> result
386            ) {
387                List<CallableMemberDescriptor> fromCurrent = new ArrayList<CallableMemberDescriptor>(result);
388                OverridingUtil.generateOverridesInFunctionGroup(
389                        name,
390                        fromSupertypes,
391                        fromCurrent,
392                        classDescriptor,
393                        new OverridingUtil.DescriptorSink() {
394                            @Override
395                            public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
396                                OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, new OverridingUtil.NotInferredVisibilitySink() {
397                                    @Override
398                                    public void cannotInferVisibility(@NotNull CallableMemberDescriptor descriptor) {
399                                        // Do nothing
400                                        // TODO: do something
401                                    }
402                                });
403                                //noinspection unchecked
404                                result.add((D) fakeOverride);
405                            }
406    
407                            @Override
408                            public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
409                                // TODO report conflicts
410                            }
411                        }
412                );
413            }
414    
415            @Override
416            protected void addNonDeclaredDescriptors(@NotNull Collection<DeclarationDescriptor> result) {
417                for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
418                    for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
419                        if (descriptor instanceof FunctionDescriptor) {
420                            result.addAll(getFunctions(descriptor.getName()));
421                        }
422                        else if (descriptor instanceof PropertyDescriptor) {
423                            result.addAll(getProperties(descriptor.getName()));
424                        }
425                        // Nothing else is inherited
426                    }
427                }
428            }
429    
430            @Nullable
431            @Override
432            protected ReceiverParameterDescriptor getImplicitReceiver() {
433                return classDescriptor.getThisAsReceiverParameter();
434            }
435    
436            @Nullable
437            @Override
438            protected ClassifierDescriptor getClassDescriptor(@NotNull Name name) {
439                return classDescriptor.nestedClasses.findClass.invoke(name);
440            }
441    
442            @Override
443            protected void addAllClassDescriptors(@NotNull Collection<DeclarationDescriptor> result) {
444                result.addAll(classDescriptor.nestedClasses.getAllDescriptors());
445            }
446    
447            @Nullable
448            @Override
449            public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
450                return classDescriptor.nestedObjects.findClass.invoke(name);
451            }
452    
453            @NotNull
454            @Override
455            protected Collection<ClassDescriptor> computeAllObjectDescriptors() {
456                return classDescriptor.nestedObjects.getAllDescriptors();
457            }
458        }
459    
460        private class NestedClassDescriptors {
461            private final Set<Name> declaredNames;
462            private final MemoizedFunctionToNullable<Name, ClassDescriptor> findClass;
463    
464            public NestedClassDescriptors(@NotNull StorageManager storageManager, @NotNull Set<Name> declaredNames) {
465                this.declaredNames = declaredNames;
466                this.findClass = storageManager.createMemoizedFunctionWithNullableValues(new Function1<Name, ClassDescriptor>() {
467                    @Override
468                    public ClassDescriptor invoke(Name name) {
469                        return NestedClassDescriptors.this.declaredNames.contains(name) ?
470                               descriptorFinder.findClass(classId.createNestedClassId(name)) :
471                               null;
472                    }
473                });
474            }
475    
476            @NotNull
477            public Collection<ClassDescriptor> getAllDescriptors() {
478                Collection<ClassDescriptor> result = new ArrayList<ClassDescriptor>(declaredNames.size());
479                for (Name name : declaredNames) {
480                    ClassDescriptor descriptor = findClass.invoke(name);
481                    if (descriptor != null) {
482                        result.add(descriptor);
483                    }
484                }
485                return result;
486            }
487        }
488    }
489