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