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