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