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