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