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
017package org.jetbrains.jet.lang.descriptors.impl;
018
019import com.google.common.collect.Lists;
020import com.google.common.collect.Sets;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.annotations.Nullable;
023import org.jetbrains.jet.lang.descriptors.*;
024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025import org.jetbrains.jet.lang.resolve.DescriptorResolver;
026import org.jetbrains.jet.lang.resolve.DescriptorUtils;
027import org.jetbrains.jet.lang.resolve.OverridingUtil;
028import org.jetbrains.jet.lang.resolve.name.Name;
029import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
030import org.jetbrains.jet.lang.types.JetType;
031import org.jetbrains.jet.lang.types.TypeSubstitutor;
032import org.jetbrains.jet.lang.types.Variance;
033
034import java.util.Collections;
035import java.util.List;
036import java.util.Set;
037
038public 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
053    private PropertyDescriptorImpl(
054            @Nullable PropertyDescriptor original,
055            @NotNull DeclarationDescriptor containingDeclaration,
056            @NotNull List<AnnotationDescriptor> annotations,
057            @NotNull Modality modality,
058            @NotNull Visibility visibility,
059            boolean isVar,
060            @NotNull Name name,
061            @NotNull Kind kind
062    ) {
063        super(containingDeclaration, annotations, name);
064        this.isVar = isVar;
065        this.modality = modality;
066        this.visibility = visibility;
067        this.original = original == null ? this : original;
068        this.kind = kind;
069    }
070
071    public PropertyDescriptorImpl(
072            @NotNull DeclarationDescriptor containingDeclaration,
073            @NotNull List<AnnotationDescriptor> annotations,
074            @NotNull Modality modality,
075            @NotNull Visibility visibility,
076            boolean isVar,
077            @NotNull Name name,
078            @NotNull Kind kind
079    ) {
080        this(null, containingDeclaration, annotations, modality, visibility, isVar, name, kind);
081    }
082
083    public PropertyDescriptorImpl(
084            @NotNull DeclarationDescriptor containingDeclaration,
085            @NotNull List<AnnotationDescriptor> annotations,
086            @NotNull Modality modality,
087            @NotNull Visibility visibility,
088            boolean isVar,
089            @Nullable JetType receiverType,
090            @Nullable ReceiverParameterDescriptor expectedThisObject,
091            @NotNull Name name,
092            @NotNull JetType outType,
093            @NotNull Kind kind
094    ) {
095        this(containingDeclaration, annotations, modality, visibility, isVar, name, kind);
096        setType(outType, Collections.<TypeParameterDescriptor>emptyList(), expectedThisObject, receiverType);
097    }
098
099    public void setType(
100            @NotNull JetType outType,
101            @NotNull List<? extends TypeParameterDescriptor> typeParameters,
102            @Nullable ReceiverParameterDescriptor expectedThisObject,
103            @Nullable JetType receiverType
104    ) {
105        ReceiverParameterDescriptor receiverParameter = DescriptorResolver.resolveReceiverParameterFor(this, receiverType);
106        setType(outType, typeParameters, expectedThisObject, receiverParameter);
107    }
108
109    public void setType(
110            @NotNull JetType outType,
111            @NotNull List<? extends TypeParameterDescriptor> typeParameters,
112            @Nullable ReceiverParameterDescriptor expectedThisObject,
113            @Nullable ReceiverParameterDescriptor receiverParameter
114    ) {
115        setOutType(outType);
116
117        this.typeParameters = Lists.newArrayList(typeParameters);
118
119        this.receiverParameter = receiverParameter;
120        this.expectedThisObject = expectedThisObject;
121    }
122
123    public void initialize(@Nullable PropertyGetterDescriptorImpl getter, @Nullable PropertySetterDescriptor setter) {
124        this.getter = getter;
125        this.setter = setter;
126    }
127
128    public void setVisibility(@NotNull Visibility visibility) {
129        this.visibility = visibility;
130    }
131
132    @NotNull
133    @Override
134    public List<TypeParameterDescriptor> getTypeParameters() {
135        return typeParameters;
136    }
137
138    @Override
139    @Nullable
140    public ReceiverParameterDescriptor getReceiverParameter() {
141        return receiverParameter;
142    }
143
144    @Nullable
145    @Override
146    public ReceiverParameterDescriptor getExpectedThisObject() {
147        return expectedThisObject;
148    }
149
150    @NotNull
151    @Override
152    public JetType getReturnType() {
153        return getType();
154    }
155
156    @Override
157    public boolean isVar() {
158        return isVar;
159    }
160
161    @NotNull
162    @Override
163    public Modality getModality() {
164        return modality;
165    }
166
167    @NotNull
168    @Override
169    public Visibility getVisibility() {
170        return visibility;
171    }
172
173    @Override
174    @Nullable
175    public PropertyGetterDescriptorImpl getGetter() {
176        return getter;
177    }
178
179    @Override
180    @Nullable
181    public PropertySetterDescriptor getSetter() {
182        return setter;
183    }
184
185    @Override
186    @NotNull
187    public List<PropertyAccessorDescriptor> getAccessors() {
188        List<PropertyAccessorDescriptor> r = Lists.newArrayListWithCapacity(2);
189        if (getter != null) {
190            r.add(getter);
191        }
192        if (setter != null) {
193            r.add(setter);
194        }
195        return r;
196    }
197
198    @Override
199    public PropertyDescriptor substitute(@NotNull TypeSubstitutor originalSubstitutor) {
200        if (originalSubstitutor.isEmpty()) {
201            return this;
202        }
203        return doSubstitute(originalSubstitutor, getContainingDeclaration(), modality, visibility, true, true, getKind());
204    }
205
206    private PropertyDescriptor doSubstitute(TypeSubstitutor originalSubstitutor,
207            DeclarationDescriptor newOwner, Modality newModality, Visibility newVisibility, boolean preserveOriginal, boolean copyOverrides, Kind kind) {
208        PropertyDescriptorImpl substitutedDescriptor = new PropertyDescriptorImpl(preserveOriginal ? getOriginal() : null, newOwner,
209                getAnnotations(), newModality, newVisibility, isVar(), getName(), kind);
210
211        List<TypeParameterDescriptor> substitutedTypeParameters = Lists.newArrayList();
212        TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(getTypeParameters(), originalSubstitutor, substitutedDescriptor, substitutedTypeParameters);
213
214        JetType originalOutType = getType();
215        JetType outType = substitutor.substitute(originalOutType, Variance.OUT_VARIANCE);
216        if (outType == null) {
217            return null; // TODO : tell the user that the property was projected out
218        }
219
220
221        ReceiverParameterDescriptor substitutedExpectedThisObject;
222        ReceiverParameterDescriptor expectedThisObject = getExpectedThisObject();
223        if (expectedThisObject != null) {
224            substitutedExpectedThisObject = expectedThisObject.substitute(substitutor);
225            if (substitutedExpectedThisObject == null) return null;
226        }
227        else {
228            substitutedExpectedThisObject = null;
229        }
230
231        JetType substitutedReceiverType;
232        if (receiverParameter != null) {
233            substitutedReceiverType = substitutor.substitute(receiverParameter.getType(), Variance.IN_VARIANCE);
234            if (substitutedReceiverType == null) return null;
235        }
236        else {
237            substitutedReceiverType = null;
238        }
239
240        substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedExpectedThisObject, substitutedReceiverType);
241
242        PropertyGetterDescriptorImpl newGetter = getter == null ? null : new PropertyGetterDescriptorImpl(
243                substitutedDescriptor, Lists.newArrayList(getter.getAnnotations()),
244                DescriptorUtils.convertModality(getter.getModality(), false), convertVisibility(getter.getVisibility(), newVisibility),
245                getter.hasBody(), getter.isDefault(), kind, getter.getOriginal());
246        if (newGetter != null) {
247            JetType returnType = getter.getReturnType();
248            newGetter.initialize(returnType != null ? substitutor.substitute(returnType, Variance.OUT_VARIANCE) : null);
249        }
250        PropertySetterDescriptorImpl newSetter = setter == null ? null : new PropertySetterDescriptorImpl(
251                substitutedDescriptor, Lists.newArrayList(setter.getAnnotations()), DescriptorUtils.convertModality(setter.getModality(), false),
252                convertVisibility(setter.getVisibility(), newVisibility), setter.hasBody(), setter.isDefault(), kind, setter.getOriginal());
253        if (newSetter != null) {
254            List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorUtil.getSubstitutedValueParameters(newSetter, setter, substitutor);
255            if (substitutedValueParameters == null) {
256                return null;
257            }
258            if (substitutedValueParameters.size() != 1) {
259                throw new IllegalStateException();
260            }
261            newSetter.initialize(substitutedValueParameters.get(0));
262        }
263
264        substitutedDescriptor.initialize(newGetter, newSetter);
265
266        if (copyOverrides) {
267            for (PropertyDescriptor propertyDescriptor : overriddenProperties) {
268                OverridingUtil.bindOverride(substitutedDescriptor, propertyDescriptor.substitute(substitutor));
269            }
270        }
271
272        return substitutedDescriptor;
273    }
274
275    @NotNull
276    private static Visibility convertVisibility(Visibility orig, Visibility candidate) {
277        if (candidate == Visibilities.INHERITED) {
278            return candidate;
279        }
280
281        Integer result = Visibilities.compare(orig, candidate);
282        return result != null && result < 0 ? candidate : orig;
283    }
284
285    @Override
286    public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
287        return visitor.visitPropertyDescriptor(this, data);
288    }
289
290    @NotNull
291    @Override
292    public PropertyDescriptor getOriginal() {
293        return original == this ? this : original.getOriginal();
294    }
295
296    @Override
297    public Kind getKind() {
298        return kind;
299    }
300
301    @Override
302    public void addOverriddenDescriptor(@NotNull CallableMemberDescriptor overridden) {
303        overriddenProperties.add((PropertyDescriptorImpl) overridden);
304    }
305
306    @NotNull
307    @Override
308    public Set<? extends PropertyDescriptor> getOverriddenDescriptors() {
309        return overriddenProperties;
310    }
311
312    @NotNull
313    @Override
314    public PropertyDescriptor copy(DeclarationDescriptor newOwner, Modality modality, Visibility visibility, Kind kind, boolean copyOverrides) {
315        return doSubstitute(TypeSubstitutor.EMPTY, newOwner, modality, visibility, false, copyOverrides, kind);
316    }
317}