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