001    /*
002     * Copyright 2010-2015 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.kotlin.descriptors.impl;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.annotations.ReadOnly;
022    import org.jetbrains.kotlin.descriptors.*;
023    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
024    import org.jetbrains.kotlin.name.Name;
025    import org.jetbrains.kotlin.resolve.DescriptorFactory;
026    import org.jetbrains.kotlin.types.DescriptorSubstitutor;
027    import org.jetbrains.kotlin.types.JetType;
028    import org.jetbrains.kotlin.types.TypeSubstitutor;
029    import org.jetbrains.kotlin.types.Variance;
030    import org.jetbrains.kotlin.utils.SmartSet;
031    
032    import java.util.*;
033    
034    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
035    
036    public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImpl implements PropertyDescriptor {
037        private final Modality modality;
038        private Visibility visibility;
039        private final Set<PropertyDescriptor> overriddenProperties = SmartSet.create();
040        private final PropertyDescriptor original;
041        private final Kind kind;
042        private final boolean lateInit;
043        private final boolean isConst;
044    
045        private ReceiverParameterDescriptor dispatchReceiverParameter;
046        private ReceiverParameterDescriptor extensionReceiverParameter;
047        private List<TypeParameterDescriptor> typeParameters;
048        private PropertyGetterDescriptorImpl getter;
049        private PropertySetterDescriptor setter;
050        private boolean setterProjectedOut;
051    
052        protected PropertyDescriptorImpl(
053                @NotNull DeclarationDescriptor containingDeclaration,
054                @Nullable PropertyDescriptor original,
055                @NotNull Annotations annotations,
056                @NotNull Modality modality,
057                @NotNull Visibility visibility,
058                boolean isVar,
059                @NotNull Name name,
060                @NotNull Kind kind,
061                @NotNull SourceElement source,
062                boolean lateInit,
063                boolean isConst
064        ) {
065            super(containingDeclaration, annotations, name, null, isVar, source);
066            this.modality = modality;
067            this.visibility = visibility;
068            this.original = original == null ? this : original;
069            this.kind = kind;
070            this.lateInit = lateInit;
071            this.isConst = isConst;
072        }
073    
074        @NotNull
075        public static PropertyDescriptorImpl create(
076                @NotNull DeclarationDescriptor containingDeclaration,
077                @NotNull Annotations annotations,
078                @NotNull Modality modality,
079                @NotNull Visibility visibility,
080                boolean isVar,
081                @NotNull Name name,
082                @NotNull Kind kind,
083                @NotNull SourceElement source,
084                boolean lateInit,
085                boolean isConst
086        ) {
087            return new PropertyDescriptorImpl(containingDeclaration, null, annotations,
088                                              modality, visibility, isVar, name, kind, source, lateInit, isConst);
089        }
090    
091        public void setType(
092                @NotNull JetType outType,
093                @ReadOnly @NotNull List<? extends TypeParameterDescriptor> typeParameters,
094                @Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
095                @Nullable JetType receiverType
096        ) {
097            ReceiverParameterDescriptor extensionReceiverParameter = DescriptorFactory.createExtensionReceiverParameterForCallable(this, receiverType);
098            setType(outType, typeParameters, dispatchReceiverParameter, extensionReceiverParameter);
099        }
100    
101        public void setType(
102                @NotNull JetType outType,
103                @ReadOnly @NotNull List<? extends TypeParameterDescriptor> typeParameters,
104                @Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
105                @Nullable ReceiverParameterDescriptor extensionReceiverParameter
106        ) {
107            setOutType(outType);
108    
109            this.typeParameters = new ArrayList<TypeParameterDescriptor>(typeParameters);
110    
111            this.extensionReceiverParameter = extensionReceiverParameter;
112            this.dispatchReceiverParameter = dispatchReceiverParameter;
113        }
114    
115        public void initialize(@Nullable PropertyGetterDescriptorImpl getter, @Nullable PropertySetterDescriptor setter) {
116            this.getter = getter;
117            this.setter = setter;
118        }
119    
120        public void setSetterProjectedOut(boolean setterProjectedOut) {
121            this.setterProjectedOut = setterProjectedOut;
122        }
123    
124        public void setVisibility(@NotNull Visibility visibility) {
125            this.visibility = visibility;
126        }
127    
128        @NotNull
129        @Override
130        public List<TypeParameterDescriptor> getTypeParameters() {
131            return typeParameters;
132        }
133    
134        @Override
135        @Nullable
136        public ReceiverParameterDescriptor getExtensionReceiverParameter() {
137            return extensionReceiverParameter;
138        }
139    
140        @Nullable
141        @Override
142        public ReceiverParameterDescriptor getDispatchReceiverParameter() {
143            return dispatchReceiverParameter;
144        }
145    
146        @NotNull
147        @Override
148        public JetType getReturnType() {
149            return getType();
150        }
151    
152        @NotNull
153        @Override
154        public Modality getModality() {
155            return modality;
156        }
157    
158        @NotNull
159        @Override
160        public Visibility getVisibility() {
161            return visibility;
162        }
163    
164        @Override
165        @Nullable
166        public PropertyGetterDescriptorImpl getGetter() {
167            return getter;
168        }
169    
170        @Override
171        @Nullable
172        public PropertySetterDescriptor getSetter() {
173            return setter;
174        }
175    
176        @Override
177        public boolean isSetterProjectedOut() {
178            return setterProjectedOut;
179        }
180    
181        @Override
182        public boolean isLateInit() {
183            return lateInit;
184        }
185    
186        @Override
187        public boolean isConst() {
188            return isConst;
189        }
190    
191        @Override
192        @NotNull
193        public List<PropertyAccessorDescriptor> getAccessors() {
194            List<PropertyAccessorDescriptor> result = new ArrayList<PropertyAccessorDescriptor>(2);
195            if (getter != null) {
196                result.add(getter);
197            }
198            if (setter != null) {
199                result.add(setter);
200            }
201            return result;
202        }
203    
204        @Override
205        public PropertyDescriptor substitute(@NotNull TypeSubstitutor originalSubstitutor) {
206            if (originalSubstitutor.isEmpty()) {
207                return this;
208            }
209            return doSubstitute(originalSubstitutor, getContainingDeclaration(), modality, visibility, getOriginal(), true, getKind());
210        }
211    
212        @Nullable
213        private PropertyDescriptor doSubstitute(
214                @NotNull TypeSubstitutor originalSubstitutor,
215                @NotNull DeclarationDescriptor newOwner,
216                @NotNull Modality newModality,
217                @NotNull Visibility newVisibility,
218                @Nullable PropertyDescriptor original,
219                boolean copyOverrides,
220                @NotNull Kind kind
221        ) {
222            PropertyDescriptorImpl substitutedDescriptor = createSubstitutedCopy(newOwner, newModality, newVisibility, original, kind);
223    
224            List<TypeParameterDescriptor> originalTypeParameters = getTypeParameters();
225            List<TypeParameterDescriptor> substitutedTypeParameters = new ArrayList<TypeParameterDescriptor>(originalTypeParameters.size());
226            TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(
227                    originalTypeParameters, originalSubstitutor.getSubstitution(), substitutedDescriptor, substitutedTypeParameters
228            );
229    
230            JetType originalOutType = getType();
231            JetType outType = substitutor.substitute(originalOutType, Variance.OUT_VARIANCE);
232            if (outType == null) {
233                return null; // TODO : tell the user that the property was projected out
234            }
235    
236    
237            ReceiverParameterDescriptor substitutedDispatchReceiver;
238            ReceiverParameterDescriptor dispatchReceiver = getDispatchReceiverParameter();
239            if (dispatchReceiver != null) {
240                substitutedDispatchReceiver = dispatchReceiver.substitute(substitutor);
241                if (substitutedDispatchReceiver == null) return null;
242            }
243            else {
244                substitutedDispatchReceiver = null;
245            }
246    
247            JetType substitutedReceiverType;
248            if (extensionReceiverParameter != null) {
249                substitutedReceiverType = substitutor.substitute(extensionReceiverParameter.getType(), Variance.IN_VARIANCE);
250                if (substitutedReceiverType == null) return null;
251            }
252            else {
253                substitutedReceiverType = null;
254            }
255    
256            substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedDispatchReceiver, substitutedReceiverType);
257    
258            PropertyGetterDescriptorImpl newGetter = getter == null ? null : new PropertyGetterDescriptorImpl(
259                    substitutedDescriptor, getter.getAnnotations(), newModality, convertVisibility(getter.getVisibility(), newVisibility),
260                    getter.hasBody(), getter.isDefault(), kind, original == null ? null : original.getGetter(), SourceElement.NO_SOURCE
261            );
262            if (newGetter != null) {
263                JetType returnType = getter.getReturnType();
264                newGetter.initialize(returnType != null ? substitutor.substitute(returnType, Variance.OUT_VARIANCE) : null);
265            }
266            PropertySetterDescriptorImpl newSetter = setter == null ? null : new PropertySetterDescriptorImpl(
267                    substitutedDescriptor, setter.getAnnotations(), newModality, convertVisibility(setter.getVisibility(), newVisibility),
268                    setter.hasBody(), setter.isDefault(), kind, original == null ? null : original.getSetter(), SourceElement.NO_SOURCE
269            );
270            if (newSetter != null) {
271                List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(
272                        newSetter, setter.getValueParameters(), substitutor
273                );
274                if (substitutedValueParameters == null) {
275                    // The setter is projected out, e.g. in this case:
276                    //     trait Tr<T> { var v: T }
277                    //     fun test(tr: Tr<out Any?>) { ... }
278                    // we want to tell the user that although the property is declared as a var,
279                    // it can not be assigned to because of the projection
280                    substitutedDescriptor.setSetterProjectedOut(true);
281                    substitutedValueParameters = Collections.<ValueParameterDescriptor>singletonList(
282                            PropertySetterDescriptorImpl.createSetterParameter(newSetter, getBuiltIns(newOwner).getNothingType())
283                    );
284                }
285                if (substitutedValueParameters.size() != 1) {
286                    throw new IllegalStateException();
287                }
288                newSetter.initialize(substitutedValueParameters.get(0));
289            }
290    
291            substitutedDescriptor.initialize(newGetter, newSetter);
292    
293            if (copyOverrides) {
294                for (PropertyDescriptor propertyDescriptor : overriddenProperties) {
295                    substitutedDescriptor.addOverriddenDescriptor(propertyDescriptor.substitute(substitutor));
296                }
297            }
298    
299            return substitutedDescriptor;
300        }
301    
302        @NotNull
303        protected PropertyDescriptorImpl createSubstitutedCopy(
304                @NotNull DeclarationDescriptor newOwner,
305                @NotNull Modality newModality,
306                @NotNull Visibility newVisibility,
307                @Nullable PropertyDescriptor original,
308                @NotNull Kind kind
309        ) {
310            return new PropertyDescriptorImpl(newOwner, original,
311                                              getAnnotations(), newModality, newVisibility,
312                                              isVar(), getName(), kind, SourceElement.NO_SOURCE, isLateInit(), isConst());
313        }
314    
315        @NotNull
316        private static Visibility convertVisibility(Visibility orig, Visibility candidate) {
317            if (candidate == Visibilities.INHERITED) {
318                return candidate;
319            }
320    
321            Integer result = Visibilities.compare(orig, candidate);
322            return result != null && result < 0 ? candidate : orig;
323        }
324    
325        @Override
326        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
327            return visitor.visitPropertyDescriptor(this, data);
328        }
329    
330        @NotNull
331        @Override
332        public PropertyDescriptor getOriginal() {
333            return original == this ? this : original.getOriginal();
334        }
335    
336        @NotNull
337        @Override
338        public Kind getKind() {
339            return kind;
340        }
341    
342        @Override
343        public void addOverriddenDescriptor(@NotNull CallableMemberDescriptor overridden) {
344            overriddenProperties.add((PropertyDescriptorImpl) overridden);
345        }
346    
347        @NotNull
348        @Override
349        public Collection<? extends PropertyDescriptor> getOverriddenDescriptors() {
350            return overriddenProperties;
351        }
352    
353        @NotNull
354        @Override
355        public PropertyDescriptor copy(DeclarationDescriptor newOwner, Modality modality, Visibility visibility, Kind kind, boolean copyOverrides) {
356            return doSubstitute(TypeSubstitutor.EMPTY, newOwner, modality, visibility, null, copyOverrides, kind);
357        }
358    }