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 com.google.common.collect.Lists;
020    import com.google.common.collect.Sets;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
025    import org.jetbrains.jet.lang.resolve.DescriptorFactory;
026    import org.jetbrains.jet.lang.resolve.OverridingUtil;
027    import org.jetbrains.jet.lang.resolve.name.Name;
028    import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
029    import org.jetbrains.jet.lang.types.JetType;
030    import org.jetbrains.jet.lang.types.TypeSubstitutor;
031    import org.jetbrains.jet.lang.types.Variance;
032    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033    
034    import java.util.Collections;
035    import java.util.List;
036    import java.util.Set;
037    
038    public class PropertyDescriptorImpl extends VariableDescriptorImpl implements PropertyDescriptor {
039    
040        private final Modality modality;
041        private Visibility visibility;
042        private final boolean isVar;
043        private final Set<PropertyDescriptor> overriddenProperties = Sets.newLinkedHashSet(); // LinkedHashSet is essential here
044        private final PropertyDescriptor original;
045        private final Kind kind;
046    
047        private ReceiverParameterDescriptor expectedThisObject;
048        private ReceiverParameterDescriptor receiverParameter;
049        private List<TypeParameterDescriptor> typeParameters;
050        private PropertyGetterDescriptorImpl getter;
051        private PropertySetterDescriptor setter;
052        private boolean setterProjectedOut;
053    
054        protected PropertyDescriptorImpl(
055                @NotNull DeclarationDescriptor containingDeclaration,
056                @Nullable PropertyDescriptor original,
057                @NotNull Annotations annotations,
058                @NotNull Modality modality,
059                @NotNull Visibility visibility,
060                boolean isVar,
061                @NotNull Name name,
062                @NotNull Kind kind
063        ) {
064            super(containingDeclaration, annotations, name, null);
065            this.isVar = isVar;
066            this.modality = modality;
067            this.visibility = visibility;
068            this.original = original == null ? this : original;
069            this.kind = kind;
070        }
071    
072        @NotNull
073        public static PropertyDescriptorImpl create(
074                @NotNull DeclarationDescriptor containingDeclaration,
075                @NotNull Annotations annotations,
076                @NotNull Modality modality,
077                @NotNull Visibility visibility,
078                boolean isVar,
079                @NotNull Name name,
080                @NotNull Kind kind
081        ) {
082            return new PropertyDescriptorImpl(containingDeclaration, null, annotations, modality, visibility, isVar, name, kind);
083        }
084    
085        public void setType(
086                @NotNull JetType outType,
087                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
088                @Nullable ReceiverParameterDescriptor expectedThisObject,
089                @Nullable JetType receiverType
090        ) {
091            ReceiverParameterDescriptor receiverParameter = DescriptorFactory.createReceiverParameterForCallable(this, receiverType);
092            setType(outType, typeParameters, expectedThisObject, receiverParameter);
093        }
094    
095        public void setType(
096                @NotNull JetType outType,
097                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
098                @Nullable ReceiverParameterDescriptor expectedThisObject,
099                @Nullable ReceiverParameterDescriptor receiverParameter
100        ) {
101            setOutType(outType);
102    
103            this.typeParameters = Lists.newArrayList(typeParameters);
104    
105            this.receiverParameter = receiverParameter;
106            this.expectedThisObject = expectedThisObject;
107        }
108    
109        public void initialize(@Nullable PropertyGetterDescriptorImpl getter, @Nullable PropertySetterDescriptor setter) {
110            this.getter = getter;
111            this.setter = setter;
112        }
113    
114        public void setSetterProjectedOut(boolean setterProjectedOut) {
115            this.setterProjectedOut = setterProjectedOut;
116        }
117    
118        public void setVisibility(@NotNull Visibility visibility) {
119            this.visibility = visibility;
120        }
121    
122        @NotNull
123        @Override
124        public List<TypeParameterDescriptor> getTypeParameters() {
125            return typeParameters;
126        }
127    
128        @Override
129        @Nullable
130        public ReceiverParameterDescriptor getReceiverParameter() {
131            return receiverParameter;
132        }
133    
134        @Nullable
135        @Override
136        public ReceiverParameterDescriptor getExpectedThisObject() {
137            return expectedThisObject;
138        }
139    
140        @NotNull
141        @Override
142        public JetType getReturnType() {
143            return getType();
144        }
145    
146        @Override
147        public boolean isVar() {
148            return isVar;
149        }
150    
151        @NotNull
152        @Override
153        public Modality getModality() {
154            return modality;
155        }
156    
157        @NotNull
158        @Override
159        public Visibility getVisibility() {
160            return visibility;
161        }
162    
163        @Override
164        @Nullable
165        public PropertyGetterDescriptorImpl getGetter() {
166            return getter;
167        }
168    
169        @Override
170        @Nullable
171        public PropertySetterDescriptor getSetter() {
172            return setter;
173        }
174    
175        @Override
176        public boolean isSetterProjectedOut() {
177            return setterProjectedOut;
178        }
179    
180        @Override
181        @NotNull
182        public List<PropertyAccessorDescriptor> getAccessors() {
183            List<PropertyAccessorDescriptor> r = Lists.newArrayListWithCapacity(2);
184            if (getter != null) {
185                r.add(getter);
186            }
187            if (setter != null) {
188                r.add(setter);
189            }
190            return r;
191        }
192    
193        @Override
194        public PropertyDescriptor substitute(@NotNull TypeSubstitutor originalSubstitutor) {
195            if (originalSubstitutor.isEmpty()) {
196                return this;
197            }
198            return doSubstitute(originalSubstitutor, getContainingDeclaration(), modality, visibility, getOriginal(), true, getKind());
199        }
200    
201        @Nullable
202        private PropertyDescriptor doSubstitute(
203                @NotNull TypeSubstitutor originalSubstitutor,
204                @NotNull DeclarationDescriptor newOwner,
205                @NotNull Modality newModality,
206                @NotNull Visibility newVisibility,
207                @Nullable PropertyDescriptor original,
208                boolean copyOverrides,
209                @NotNull Kind kind
210        ) {
211            PropertyDescriptorImpl substitutedDescriptor = createSubstitutedCopy(newOwner, newModality, newVisibility, original, kind);
212    
213            List<TypeParameterDescriptor> substitutedTypeParameters = Lists.newArrayList();
214            TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(getTypeParameters(), originalSubstitutor, substitutedDescriptor, substitutedTypeParameters);
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 substitutedExpectedThisObject;
224            ReceiverParameterDescriptor expectedThisObject = getExpectedThisObject();
225            if (expectedThisObject != null) {
226                substitutedExpectedThisObject = expectedThisObject.substitute(substitutor);
227                if (substitutedExpectedThisObject == null) return null;
228            }
229            else {
230                substitutedExpectedThisObject = null;
231            }
232    
233            JetType substitutedReceiverType;
234            if (receiverParameter != null) {
235                substitutedReceiverType = substitutor.substitute(receiverParameter.getType(), Variance.IN_VARIANCE);
236                if (substitutedReceiverType == null) return null;
237            }
238            else {
239                substitutedReceiverType = null;
240            }
241    
242            substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedExpectedThisObject, 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()
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()
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);
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    }