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;
018    
019    import kotlin.Function0;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.descriptors.serialization.descriptors.*;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
025    import org.jetbrains.jet.lang.descriptors.impl.*;
026    import org.jetbrains.jet.lang.resolve.DescriptorFactory;
027    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
029    import org.jetbrains.jet.lang.types.Variance;
030    import org.jetbrains.jet.storage.StorageManager;
031    
032    import java.util.ArrayList;
033    import java.util.Collections;
034    import java.util.List;
035    
036    import static org.jetbrains.jet.descriptors.serialization.ProtoBuf.Callable;
037    import static org.jetbrains.jet.descriptors.serialization.ProtoBuf.TypeParameter;
038    import static org.jetbrains.jet.descriptors.serialization.TypeDeserializer.TypeParameterResolver.NONE;
039    import static org.jetbrains.jet.descriptors.serialization.descriptors.Deserializers.AnnotatedCallableKind;
040    
041    public class DescriptorDeserializer {
042    
043        @NotNull
044        public static DescriptorDeserializer create(
045                @NotNull StorageManager storageManager,
046                @NotNull DeclarationDescriptor containingDeclaration,
047                @NotNull NameResolver nameResolver,
048                @NotNull DescriptorFinder descriptorFinder,
049                @NotNull Deserializers annotationDeserializer
050        ) {
051            return new DescriptorDeserializer(storageManager,
052                    new TypeDeserializer(storageManager, null, nameResolver, descriptorFinder,
053                                         "Deserializer for " + containingDeclaration.getName(), NONE),
054                    containingDeclaration, nameResolver, annotationDeserializer);
055        }
056    
057        @NotNull
058        public static DescriptorDeserializer create(
059                @NotNull StorageManager storageManager,
060                @NotNull TypeDeserializer typeDeserializer,
061                @NotNull DeclarationDescriptor containingDeclaration,
062                @NotNull NameResolver nameResolver,
063                @NotNull Deserializers annotationDeserializer
064        ) {
065            return new DescriptorDeserializer(storageManager, typeDeserializer, containingDeclaration, nameResolver, annotationDeserializer);
066        }
067    
068        private final DeclarationDescriptor containingDeclaration;
069        private final NameResolver nameResolver;
070        private final TypeDeserializer typeDeserializer;
071        private final Deserializers deserializers;
072    
073        private final StorageManager storageManager;
074    
075        private DescriptorDeserializer(
076                @NotNull StorageManager storageManager,
077                @NotNull TypeDeserializer typeDeserializer,
078                @NotNull DeclarationDescriptor containingDeclaration,
079                @NotNull NameResolver nameResolver,
080                @NotNull Deserializers deserializers
081        ) {
082            this.storageManager = storageManager;
083            this.typeDeserializer = typeDeserializer;
084            this.containingDeclaration = containingDeclaration;
085            this.nameResolver = nameResolver;
086            this.deserializers = deserializers;
087        }
088    
089        @NotNull
090        public TypeDeserializer getTypeDeserializer() {
091            return typeDeserializer;
092        }
093    
094        @NotNull
095        public NameResolver getNameResolver() {
096            return nameResolver;
097        }
098    
099        @NotNull
100        public DescriptorDeserializer createChildDeserializer(
101                @NotNull DeclarationDescriptor descriptor,
102                @NotNull final List<TypeParameter> typeParameterProtos,
103                @NotNull final List<TypeParameterDescriptor> typeParameters
104        ) {
105            TypeDeserializer childTypeDeserializer = new TypeDeserializer(
106                    storageManager,
107                    typeDeserializer, "Child deserializer for " + descriptor.getName(),
108                    new TypeDeserializer.TypeParameterResolver() {
109                        @NotNull
110                        @Override
111                        public List<DeserializedTypeParameterDescriptor> getTypeParameters(@NotNull TypeDeserializer typeDeserializer) {
112                            List<DeserializedTypeParameterDescriptor> descriptors = typeParameters(typeParameterProtos, typeDeserializer);
113                            typeParameters.addAll(descriptors);
114                            return descriptors;
115                        }
116                    });
117            return create(storageManager, childTypeDeserializer, descriptor, nameResolver, deserializers);
118        }
119    
120        @NotNull
121        public CallableMemberDescriptor loadCallable(@NotNull Callable proto) {
122            Callable.CallableKind callableKind = Flags.CALLABLE_KIND.get(proto.getFlags());
123            switch (callableKind) {
124                case FUN:
125                    return loadFunction(proto);
126                case VAL:
127                case VAR:
128                    return loadProperty(proto);
129                case CONSTRUCTOR:
130                    return loadConstructor(proto);
131            }
132            throw new IllegalArgumentException("Unsupported callable kind: " + callableKind);
133        }
134    
135        @NotNull
136        private PropertyDescriptor loadProperty(@NotNull final Callable proto) {
137            final int flags = proto.getFlags();
138    
139            PropertyDescriptorImpl property = new PropertyDescriptorImpl(
140                    containingDeclaration,
141                    getAnnotations(proto, flags, AnnotatedCallableKind.PROPERTY),
142                    modality(Flags.MODALITY.get(flags)),
143                    visibility(Flags.VISIBILITY.get(flags)),
144                    Flags.CALLABLE_KIND.get(flags) == Callable.CallableKind.VAR,
145                    nameResolver.getName(proto.getName()),
146                    memberKind(Flags.MEMBER_KIND.get(flags))
147            );
148    
149            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(proto.getTypeParameterCount());
150            DescriptorDeserializer local = createChildDeserializer(property, proto.getTypeParameterList(), typeParameters);
151            property.setType(
152                    local.typeDeserializer.type(proto.getReturnType()),
153                    typeParameters,
154                    getExpectedThisObject(),
155                    local.typeDeserializer.typeOrNull(proto.hasReceiverType() ? proto.getReceiverType() : null)
156            );
157    
158            PropertyGetterDescriptorImpl getter = null;
159            PropertySetterDescriptorImpl setter = null;
160    
161            if (Flags.HAS_GETTER.get(flags)) {
162                int getterFlags = proto.getGetterFlags();
163                boolean isNotDefault = proto.hasGetterFlags() && Flags.IS_NOT_DEFAULT.get(getterFlags);
164                if (isNotDefault) {
165                    getter = new PropertyGetterDescriptorImpl(
166                            property, getAnnotations(proto, getterFlags, AnnotatedCallableKind.PROPERTY_GETTER),
167                            modality(Flags.MODALITY.get(getterFlags)), visibility(Flags.VISIBILITY.get(getterFlags)),
168                            isNotDefault, !isNotDefault, property.getKind()
169                    );
170                }
171                else {
172                    getter = DescriptorFactory.createDefaultGetter(property);
173                }
174                getter.initialize(property.getReturnType());
175            }
176    
177            if (Flags.HAS_SETTER.get(flags)) {
178                int setterFlags = proto.getSetterFlags();
179                boolean isNotDefault = proto.hasSetterFlags() && Flags.IS_NOT_DEFAULT.get(setterFlags);
180                if (isNotDefault) {
181                    setter = new PropertySetterDescriptorImpl(
182                            property, getAnnotations(proto, setterFlags, AnnotatedCallableKind.PROPERTY_SETTER),
183                            modality(Flags.MODALITY.get(setterFlags)), visibility(Flags.VISIBILITY.get(setterFlags)),
184                            isNotDefault, !isNotDefault, property.getKind()
185                    );
186                    DescriptorDeserializer setterLocal = local.createChildDeserializer(setter, Collections.<TypeParameter>emptyList(),
187                                                                                       Collections.<TypeParameterDescriptor>emptyList());
188                    List<ValueParameterDescriptor> valueParameters = setterLocal.valueParameters(proto, AnnotatedCallableKind.PROPERTY_SETTER);
189                    assert valueParameters.size() == 1 : "Property setter should have a single value parameter: " + setter;
190                    setter.initialize(valueParameters.get(0));
191                }
192                else {
193                    setter = DescriptorFactory.createDefaultSetter(property);
194                }
195            }
196    
197            if (Flags.HAS_CONSTANT.get(flags)) {
198                property.setCompileTimeInitializer(
199                        storageManager.createNullableLazyValue(new Function0<CompileTimeConstant<?>>() {
200                            @Nullable
201                            @Override
202                            public CompileTimeConstant<?> invoke() {
203                                assert containingDeclaration instanceof ClassOrPackageFragmentDescriptor
204                                        : "Only members in classes or package fragments should be serialized: " + containingDeclaration;
205                                return deserializers.getConstantDeserializer().loadPropertyConstant(
206                                                                (ClassOrPackageFragmentDescriptor) containingDeclaration,
207                                                                proto, nameResolver,
208                                                                AnnotatedCallableKind.PROPERTY);
209                            }
210                        })
211                );
212            }
213    
214            property.initialize(getter, setter);
215    
216            return property;
217        }
218    
219        @NotNull
220        private CallableMemberDescriptor loadFunction(@NotNull Callable proto) {
221            int flags = proto.getFlags();
222            DeserializedSimpleFunctionDescriptor function = new DeserializedSimpleFunctionDescriptor(
223                    containingDeclaration, proto,
224                    deserializers,
225                    nameResolver
226            );
227            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(proto.getTypeParameterCount());
228            DescriptorDeserializer local = createChildDeserializer(function, proto.getTypeParameterList(), typeParameters);
229            function.initialize(
230                    local.typeDeserializer.typeOrNull(proto.hasReceiverType() ? proto.getReceiverType() : null),
231                    getExpectedThisObject(),
232                    typeParameters,
233                    local.valueParameters(proto, AnnotatedCallableKind.FUNCTION),
234                    local.typeDeserializer.type(proto.getReturnType()),
235                    modality(Flags.MODALITY.get(flags)),
236                    visibility(Flags.VISIBILITY.get(flags))
237            );
238            return function;
239        }
240    
241        @Nullable
242        private ReceiverParameterDescriptor getExpectedThisObject() {
243            return containingDeclaration instanceof ClassDescriptor
244                   ? ((ClassDescriptor) containingDeclaration).getThisAsReceiverParameter() : null;
245        }
246    
247        @NotNull
248        private CallableMemberDescriptor loadConstructor(@NotNull Callable proto) {
249            ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
250            ConstructorDescriptorImpl descriptor = new ConstructorDescriptorImpl(
251                    classDescriptor,
252                    getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION),
253                    // TODO: primary
254                    true);
255            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(proto.getTypeParameterCount());
256            DescriptorDeserializer local = createChildDeserializer(descriptor, Collections.<TypeParameter>emptyList(), typeParameters);
257            descriptor.initialize(
258                    classDescriptor.getTypeConstructor().getParameters(),
259                    local.valueParameters(proto, AnnotatedCallableKind.FUNCTION),
260                    visibility(Flags.VISIBILITY.get(proto.getFlags())),
261                    DescriptorUtils.isConstructorOfStaticNestedClass(descriptor)
262            );
263            descriptor.setReturnType(local.typeDeserializer.type(proto.getReturnType()));
264            return descriptor;
265        }
266    
267        @NotNull
268        private Annotations getAnnotations(@NotNull Callable proto, int flags, @NotNull AnnotatedCallableKind kind) {
269            return getAnnotations(containingDeclaration, proto, flags, kind, deserializers.getAnnotationDeserializer(), nameResolver);
270        }
271    
272        public static Annotations getAnnotations(
273                @NotNull DeclarationDescriptor containingDeclaration,
274                @NotNull Callable proto,
275                int flags,
276                @NotNull AnnotatedCallableKind kind,
277                @NotNull AnnotationDeserializer annotationDeserializer,
278                @NotNull NameResolver nameResolver
279        ) {
280            assert containingDeclaration instanceof ClassOrPackageFragmentDescriptor
281                    : "Only members in classes or package fragments should be serialized: " + containingDeclaration;
282            return Flags.HAS_ANNOTATIONS.get(flags)
283                   ? annotationDeserializer
284                           .loadCallableAnnotations((ClassOrPackageFragmentDescriptor) containingDeclaration, proto, nameResolver, kind)
285                   : Annotations.EMPTY;
286        }
287    
288        public static CallableMemberDescriptor.Kind memberKind(Callable.MemberKind memberKind) {
289            switch (memberKind) {
290                case DECLARATION:
291                    return CallableMemberDescriptor.Kind.DECLARATION;
292                case FAKE_OVERRIDE:
293                    return CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
294                case DELEGATION:
295                    return CallableMemberDescriptor.Kind.DELEGATION;
296                case SYNTHESIZED:
297                    return CallableMemberDescriptor.Kind.SYNTHESIZED;
298            }
299            throw new IllegalArgumentException("Unknown member kind: " + memberKind);
300        }
301    
302        @NotNull
303        public static Modality modality(@NotNull ProtoBuf.Modality modality) {
304            switch (modality) {
305                case FINAL:
306                    return Modality.FINAL;
307                case OPEN:
308                    return Modality.OPEN;
309                case ABSTRACT:
310                    return Modality.ABSTRACT;
311            }
312            throw new IllegalArgumentException("Unknown modality: " + modality);
313        }
314    
315        @NotNull
316        public static Visibility visibility(@NotNull ProtoBuf.Visibility visibility) {
317            switch (visibility) {
318                case INTERNAL:
319                    return Visibilities.INTERNAL;
320                case PRIVATE:
321                    return Visibilities.PRIVATE;
322                case PROTECTED:
323                    return Visibilities.PROTECTED;
324                case PUBLIC:
325                    return Visibilities.PUBLIC;
326                case EXTRA:
327                    throw new UnsupportedOperationException("Extra visibilities are not supported yet"); // TODO
328            }
329            throw new IllegalArgumentException("Unknown visibility: " + visibility);
330        }
331    
332        @NotNull
333        public static ClassKind classKind(@NotNull ProtoBuf.Class.Kind kind) {
334            switch (kind) {
335                case CLASS:
336                    return ClassKind.CLASS;
337                case TRAIT:
338                    return ClassKind.TRAIT;
339                case ENUM_CLASS:
340                    return ClassKind.ENUM_CLASS;
341                case ENUM_ENTRY:
342                    return ClassKind.ENUM_ENTRY;
343                case ANNOTATION_CLASS:
344                    return ClassKind.ANNOTATION_CLASS;
345                case OBJECT:
346                    return ClassKind.OBJECT;
347                case CLASS_OBJECT:
348                    return ClassKind.CLASS_OBJECT;
349            }
350            throw new IllegalArgumentException("Unknown class kind: " + kind);
351        }
352    
353        @NotNull
354        public List<DeserializedTypeParameterDescriptor> typeParameters(
355                @NotNull List<TypeParameter> protos,
356                @NotNull TypeDeserializer typeDeserializer
357        ) {
358            List<DeserializedTypeParameterDescriptor> result = new ArrayList<DeserializedTypeParameterDescriptor>(protos.size());
359            for (int i = 0; i < protos.size(); i++) {
360                TypeParameter proto = protos.get(i);
361                DeserializedTypeParameterDescriptor descriptor = new DeserializedTypeParameterDescriptor(
362                        storageManager,
363                        typeDeserializer,
364                        proto,
365                        containingDeclaration,
366                        nameResolver.getName(proto.getName()),
367                        variance(proto.getVariance()),
368                        proto.getReified(),
369                        i
370                );
371                result.add(descriptor);
372            }
373            return result;
374        }
375    
376        private static Variance variance(TypeParameter.Variance proto) {
377            switch (proto) {
378                case IN:
379                    return Variance.IN_VARIANCE;
380                case OUT:
381                    return Variance.OUT_VARIANCE;
382                case INV:
383                    return Variance.INVARIANT;
384            }
385            throw new IllegalStateException("Unknown projection: " + proto);
386        }
387    
388        @NotNull
389        private List<ValueParameterDescriptor> valueParameters(@NotNull Callable callable, @NotNull AnnotatedCallableKind kind) {
390            DeclarationDescriptor containerOfCallable = containingDeclaration.getContainingDeclaration();
391            assert containerOfCallable instanceof ClassOrPackageFragmentDescriptor
392                    : "Only members in classes or package fragments should be serialized: " + containerOfCallable;
393            ClassOrPackageFragmentDescriptor classOrPackage = (ClassOrPackageFragmentDescriptor) containerOfCallable;
394    
395            List<Callable.ValueParameter> protos = callable.getValueParameterList();
396            List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(protos.size());
397            for (int i = 0; i < protos.size(); i++) {
398                Callable.ValueParameter proto = protos.get(i);
399                result.add(new ValueParameterDescriptorImpl(
400                        containingDeclaration,
401                        i,
402                        getAnnotations(classOrPackage, callable, kind, proto),
403                        nameResolver.getName(proto.getName()),
404                        typeDeserializer.type(proto.getType()),
405                        Flags.DECLARES_DEFAULT_VALUE.get(proto.getFlags()),
406                        typeDeserializer.typeOrNull(proto.hasVarargElementType() ? proto.getVarargElementType() : null))
407                );
408            }
409            return result;
410        }
411    
412        @NotNull
413        private Annotations getAnnotations(
414                @NotNull ClassOrPackageFragmentDescriptor classOrPackage,
415                @NotNull Callable callable,
416                @NotNull AnnotatedCallableKind kind,
417                @NotNull Callable.ValueParameter valueParameter
418        ) {
419            return Flags.HAS_ANNOTATIONS.get(valueParameter.getFlags())
420                   ? deserializers.getAnnotationDeserializer().loadValueParameterAnnotations(classOrPackage, callable, nameResolver, kind, valueParameter)
421                   : Annotations.EMPTY;
422        }
423    }