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