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