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