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.context.DeserializationContextWithTypes;
023    import org.jetbrains.jet.descriptors.serialization.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
026    import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
027    import org.jetbrains.jet.lang.descriptors.impl.PropertyGetterDescriptorImpl;
028    import org.jetbrains.jet.lang.descriptors.impl.PropertySetterDescriptorImpl;
029    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
030    import org.jetbrains.jet.lang.resolve.DescriptorFactory;
031    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
032    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
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.SerializationPackage.*;
041    
042    public class MemberDeserializer {
043    
044        private final DeserializationContextWithTypes context;
045    
046        public MemberDeserializer(@NotNull DeserializationContextWithTypes context) {
047            this.context = context;
048        }
049    
050        @NotNull
051        public CallableMemberDescriptor loadCallable(@NotNull Callable proto) {
052            Callable.CallableKind callableKind = Flags.CALLABLE_KIND.get(proto.getFlags());
053            switch (callableKind) {
054                case FUN:
055                    return loadFunction(proto);
056                case VAL:
057                case VAR:
058                    return loadProperty(proto);
059                case CONSTRUCTOR:
060                    return loadConstructor(proto);
061            }
062            throw new IllegalArgumentException("Unsupported callable kind: " + callableKind);
063        }
064    
065        @NotNull
066        private PropertyDescriptor loadProperty(@NotNull final Callable proto) {
067            final int flags = proto.getFlags();
068    
069            DeserializedPropertyDescriptor property = new DeserializedPropertyDescriptor(
070                    context.getContainingDeclaration(),
071                    null,
072                    getAnnotations(proto, flags, AnnotatedCallableKind.PROPERTY),
073                    modality(Flags.MODALITY.get(flags)),
074                    visibility(Flags.VISIBILITY.get(flags)),
075                    Flags.CALLABLE_KIND.get(flags) == Callable.CallableKind.VAR,
076                    context.getNameResolver().getName(proto.getName()),
077                    SerializationPackage.memberKind(Flags.MEMBER_KIND.get(flags)),
078                    proto,
079                    context.getNameResolver()
080            );
081    
082            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(proto.getTypeParameterCount());
083            DeserializationContextWithTypes local = context.childContext(property, proto.getTypeParameterList(), typeParameters);
084            property.setType(
085                    local.getTypeDeserializer().type(proto.getReturnType()),
086                    typeParameters,
087                    getExpectedThisObject(),
088                    local.getTypeDeserializer().typeOrNull(proto.hasReceiverType() ? proto.getReceiverType() : null)
089            );
090    
091            PropertyGetterDescriptorImpl getter = null;
092            PropertySetterDescriptorImpl setter = null;
093    
094            if (Flags.HAS_GETTER.get(flags)) {
095                int getterFlags = proto.getGetterFlags();
096                boolean isNotDefault = proto.hasGetterFlags() && Flags.IS_NOT_DEFAULT.get(getterFlags);
097                if (isNotDefault) {
098                    getter = new PropertyGetterDescriptorImpl(property,
099                                                              getAnnotations(proto, getterFlags, AnnotatedCallableKind.PROPERTY_GETTER),
100                                                              modality(Flags.MODALITY.get(getterFlags)),
101                                                              visibility(Flags.VISIBILITY.get(getterFlags)),
102                                                              isNotDefault, !isNotDefault,
103                                                              property.getKind(), null, SourceElement.NO_SOURCE);
104                }
105                else {
106                    getter = DescriptorFactory.createDefaultGetter(property);
107                }
108                getter.initialize(property.getReturnType());
109            }
110    
111            if (Flags.HAS_SETTER.get(flags)) {
112                int setterFlags = proto.getSetterFlags();
113                boolean isNotDefault = proto.hasSetterFlags() && Flags.IS_NOT_DEFAULT.get(setterFlags);
114                if (isNotDefault) {
115                    setter = new PropertySetterDescriptorImpl(property,
116                                                              getAnnotations(proto, setterFlags, AnnotatedCallableKind.PROPERTY_SETTER),
117                                                              modality(Flags.MODALITY.get(setterFlags)),
118                                                              visibility(Flags.VISIBILITY.get(setterFlags)), isNotDefault,
119                                                              !isNotDefault,
120                                                              property.getKind(), null, SourceElement.NO_SOURCE);
121                    DeserializationContextWithTypes setterLocal = local.childContext(setter, Collections.<TypeParameter>emptyList(),
122                                                                                     Collections.<TypeParameterDescriptor>emptyList());
123                    List<ValueParameterDescriptor> valueParameters
124                            = setterLocal.getDeserializer().valueParameters(proto, AnnotatedCallableKind.PROPERTY_SETTER);
125                    assert valueParameters.size() == 1 : "Property setter should have a single value parameter: " + setter;
126                    setter.initialize(valueParameters.get(0));
127                }
128                else {
129                    setter = DescriptorFactory.createDefaultSetter(property);
130                }
131            }
132    
133            if (Flags.HAS_CONSTANT.get(flags)) {
134                property.setCompileTimeInitializer(
135                        context.getStorageManager().createNullableLazyValue(new Function0<CompileTimeConstant<?>>() {
136                            @Nullable
137                            @Override
138                            public CompileTimeConstant<?> invoke() {
139                                DeclarationDescriptor containingDeclaration = context.getContainingDeclaration();
140                                assert containingDeclaration instanceof ClassOrPackageFragmentDescriptor
141                                        : "Only members in classes or package fragments should be serialized: " + containingDeclaration;
142                                return context.getConstantLoader().loadPropertyConstant(
143                                        (ClassOrPackageFragmentDescriptor) containingDeclaration, proto,
144                                        context.getNameResolver(), AnnotatedCallableKind.PROPERTY);
145                            }
146                        })
147                );
148            }
149    
150            property.initialize(getter, setter);
151    
152            return property;
153        }
154    
155        @NotNull
156        private CallableMemberDescriptor loadFunction(@NotNull Callable proto) {
157            int flags = proto.getFlags();
158            DeserializedSimpleFunctionDescriptor function = DeserializedSimpleFunctionDescriptor.create(
159                    context.getContainingDeclaration(), proto, context.getAnnotationLoader(), context.getNameResolver()
160            );
161            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(proto.getTypeParameterCount());
162            DeserializationContextWithTypes local = context.childContext(function, proto.getTypeParameterList(), typeParameters);
163            function.initialize(
164                    local.getTypeDeserializer().typeOrNull(proto.hasReceiverType() ? proto.getReceiverType() : null),
165                    getExpectedThisObject(),
166                    typeParameters,
167                    local.getDeserializer().valueParameters(proto, AnnotatedCallableKind.FUNCTION),
168                    local.getTypeDeserializer().type(proto.getReturnType()),
169                    modality(Flags.MODALITY.get(flags)),
170                    visibility(Flags.VISIBILITY.get(flags))
171            );
172            return function;
173        }
174    
175        @Nullable
176        private ReceiverParameterDescriptor getExpectedThisObject() {
177            DeclarationDescriptor containingDeclaration = context.getContainingDeclaration();
178            return containingDeclaration instanceof ClassDescriptor
179                   ? ((ClassDescriptor) containingDeclaration).getThisAsReceiverParameter() : null;
180        }
181    
182        @NotNull
183        private CallableMemberDescriptor loadConstructor(@NotNull Callable proto) {
184            ClassDescriptor classDescriptor = (ClassDescriptor) context.getContainingDeclaration();
185            ConstructorDescriptorImpl descriptor = ConstructorDescriptorImpl.create(
186                    classDescriptor,
187                    getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION),
188                    // TODO: primary
189                    true, SourceElement.NO_SOURCE);
190            List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(proto.getTypeParameterCount());
191            DeserializationContextWithTypes local = context.childContext(descriptor, Collections.<TypeParameter>emptyList(), typeParameters);
192            descriptor.initialize(
193                    classDescriptor.getTypeConstructor().getParameters(),
194                    local.getDeserializer().valueParameters(proto, AnnotatedCallableKind.FUNCTION),
195                    visibility(Flags.VISIBILITY.get(proto.getFlags())),
196                    DescriptorUtils.isConstructorOfStaticNestedClass(descriptor)
197            );
198            descriptor.setReturnType(local.getTypeDeserializer().type(proto.getReturnType()));
199            return descriptor;
200        }
201    
202        @NotNull
203        private Annotations getAnnotations(@NotNull Callable proto, int flags, @NotNull AnnotatedCallableKind kind) {
204            return getAnnotations(context.getContainingDeclaration(), proto, flags, kind, context.getAnnotationLoader(), context.getNameResolver());
205        }
206    
207        public static Annotations getAnnotations(
208                @NotNull DeclarationDescriptor containingDeclaration,
209                @NotNull Callable proto,
210                int flags,
211                @NotNull AnnotatedCallableKind kind,
212                @NotNull AnnotationLoader annotationLoader,
213                @NotNull NameResolver nameResolver
214        ) {
215            assert containingDeclaration instanceof ClassOrPackageFragmentDescriptor
216                    : "Only members in classes or package fragments should be serialized: " + containingDeclaration;
217            return Flags.HAS_ANNOTATIONS.get(flags) ? annotationLoader.loadCallableAnnotations(
218                    (ClassOrPackageFragmentDescriptor) containingDeclaration, proto, nameResolver, kind) : Annotations.EMPTY;
219        }
220    
221        @NotNull
222        public List<DeserializedTypeParameterDescriptor> typeParameters(
223                @NotNull List<TypeParameter> protos,
224                @NotNull TypeDeserializer typeDeserializer
225        ) {
226            List<DeserializedTypeParameterDescriptor> result = new ArrayList<DeserializedTypeParameterDescriptor>(protos.size());
227            for (int i = 0; i < protos.size(); i++) {
228                TypeParameter proto = protos.get(i);
229                DeserializedTypeParameterDescriptor descriptor = new DeserializedTypeParameterDescriptor(
230                        context.getStorageManager(),
231                        typeDeserializer,
232                        proto,
233                        context.getContainingDeclaration(),
234                        context.getNameResolver().getName(proto.getName()),
235                        variance(proto.getVariance()),
236                        proto.getReified(),
237                        i
238                );
239                result.add(descriptor);
240            }
241            return result;
242        }
243    
244        @NotNull
245        private List<ValueParameterDescriptor> valueParameters(@NotNull Callable callable, @NotNull AnnotatedCallableKind kind) {
246            DeclarationDescriptor containerOfCallable = context.getContainingDeclaration().getContainingDeclaration();
247            assert containerOfCallable instanceof ClassOrPackageFragmentDescriptor
248                    : "Only members in classes or package fragments should be serialized: " + containerOfCallable;
249            ClassOrPackageFragmentDescriptor classOrPackage = (ClassOrPackageFragmentDescriptor) containerOfCallable;
250    
251            List<Callable.ValueParameter> protos = callable.getValueParameterList();
252            List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(protos.size());
253            for (int i = 0; i < protos.size(); i++) {
254                Callable.ValueParameter proto = protos.get(i);
255                result.add(new ValueParameterDescriptorImpl(
256                        context.getContainingDeclaration(),
257                        null,
258                        i,
259                        getAnnotations(classOrPackage, callable, kind, proto),
260                        context.getNameResolver().getName(proto.getName()),
261                        context.getTypeDeserializer().type(proto.getType()),
262                        Flags.DECLARES_DEFAULT_VALUE.get(proto.getFlags()),
263                        context.getTypeDeserializer().typeOrNull(proto.hasVarargElementType() ? proto.getVarargElementType() : null),
264                        SourceElement.NO_SOURCE)
265                );
266            }
267            return result;
268        }
269    
270        @NotNull
271        private Annotations getAnnotations(
272                @NotNull ClassOrPackageFragmentDescriptor classOrPackage,
273                @NotNull Callable callable,
274                @NotNull AnnotatedCallableKind kind,
275                @NotNull Callable.ValueParameter valueParameter
276        ) {
277            return Flags.HAS_ANNOTATIONS.get(valueParameter.getFlags()) ? context.getAnnotationLoader()
278                           .loadValueParameterAnnotations(classOrPackage, callable, context.getNameResolver(), kind, valueParameter)
279                   : Annotations.EMPTY;
280        }
281    }