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