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