001    /*
002     * Copyright 2010-2015 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.kotlin.descriptors.impl;
018    
019    import kotlin.collections.CollectionsKt;
020    import kotlin.jvm.functions.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
025    import org.jetbrains.kotlin.name.Name;
026    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
027    import org.jetbrains.kotlin.resolve.scopes.SubstitutingScope;
028    import org.jetbrains.kotlin.types.*;
029    
030    import java.util.ArrayList;
031    import java.util.Collection;
032    import java.util.List;
033    
034    public class LazySubstitutingClassDescriptor implements ClassDescriptor {
035        private final ClassDescriptor original;
036        private final TypeSubstitutor originalSubstitutor;
037        private TypeSubstitutor newSubstitutor;
038        private List<TypeParameterDescriptor> typeConstructorParameters;
039        private List<TypeParameterDescriptor> declaredTypeParameters;
040        private TypeConstructor typeConstructor;
041    
042        public LazySubstitutingClassDescriptor(ClassDescriptor descriptor, TypeSubstitutor substitutor) {
043            this.original = descriptor;
044            this.originalSubstitutor = substitutor;
045        }
046    
047        private TypeSubstitutor getSubstitutor() {
048            if (newSubstitutor == null) {
049                if (originalSubstitutor.isEmpty()) {
050                    newSubstitutor = originalSubstitutor;
051                }
052                else {
053                    List<TypeParameterDescriptor> originalTypeParameters = original.getTypeConstructor().getParameters();
054                    typeConstructorParameters = new ArrayList<TypeParameterDescriptor>(originalTypeParameters.size());
055                    newSubstitutor = DescriptorSubstitutor.substituteTypeParameters(
056                            originalTypeParameters, originalSubstitutor.getSubstitution(), this, typeConstructorParameters
057                    );
058    
059                    declaredTypeParameters = CollectionsKt.filter(typeConstructorParameters, new Function1<TypeParameterDescriptor, Boolean>() {
060                        @Override
061                        public Boolean invoke(TypeParameterDescriptor descriptor) {
062                            return !descriptor.isCapturedFromOuterDeclaration();
063                        }
064                    });
065                }
066            }
067            return newSubstitutor;
068        }
069    
070        @NotNull
071        @Override
072        public TypeConstructor getTypeConstructor() {
073            TypeConstructor originalTypeConstructor = original.getTypeConstructor();
074            if (originalSubstitutor.isEmpty()) {
075                return originalTypeConstructor;
076            }
077    
078            if (typeConstructor == null) {
079                TypeSubstitutor substitutor = getSubstitutor();
080    
081                Collection<KotlinType> originalSupertypes = originalTypeConstructor.getSupertypes();
082                Collection<KotlinType> supertypes = new ArrayList<KotlinType>(originalSupertypes.size());
083                for (KotlinType supertype : originalSupertypes) {
084                    supertypes.add(substitutor.substitute(supertype, Variance.INVARIANT));
085                }
086    
087                typeConstructor = new ClassTypeConstructorImpl(
088                        this, originalTypeConstructor.getAnnotations(), originalTypeConstructor.isFinal(), typeConstructorParameters, supertypes
089                );
090            }
091    
092            return typeConstructor;
093        }
094    
095        @NotNull
096        @Override
097        public MemberScope getMemberScope(@NotNull List<? extends TypeProjection> typeArguments) {
098            MemberScope memberScope = original.getMemberScope(typeArguments);
099            if (originalSubstitutor.isEmpty()) {
100                return memberScope;
101            }
102            return new SubstitutingScope(memberScope, getSubstitutor());
103        }
104    
105        @NotNull
106        @Override
107        public MemberScope getMemberScope(@NotNull TypeSubstitution typeSubstitution) {
108            MemberScope memberScope = original.getMemberScope(typeSubstitution);
109            if (originalSubstitutor.isEmpty()) {
110                return memberScope;
111            }
112            return new SubstitutingScope(memberScope, getSubstitutor());
113        }
114    
115        @NotNull
116        @Override
117        public MemberScope getUnsubstitutedMemberScope() {
118            MemberScope memberScope = original.getUnsubstitutedMemberScope();
119            if (originalSubstitutor.isEmpty()) {
120                return memberScope;
121            }
122            return new SubstitutingScope(memberScope, getSubstitutor());
123        }
124    
125        @NotNull
126        @Override
127        public MemberScope getStaticScope() {
128            return original.getStaticScope();
129        }
130    
131        @NotNull
132        @Override
133        public KotlinType getDefaultType() {
134            List<TypeProjection> typeProjections = TypeUtils.getDefaultTypeProjections(getTypeConstructor().getParameters());
135            return KotlinTypeImpl.create(
136                    getAnnotations(),
137                    this,
138                    false,
139                    typeProjections
140            );
141        }
142    
143        @NotNull
144        @Override
145        public ReceiverParameterDescriptor getThisAsReceiverParameter() {
146            throw new UnsupportedOperationException(); // TODO
147        }
148    
149        @NotNull
150        @Override
151        public Collection<ConstructorDescriptor> getConstructors() {
152            Collection<ConstructorDescriptor> originalConstructors = original.getConstructors();
153            Collection<ConstructorDescriptor> result = new ArrayList<ConstructorDescriptor>(originalConstructors.size());
154            for (ConstructorDescriptor constructor : originalConstructors) {
155                ConstructorDescriptor copy =
156                        constructor.copy(this, constructor.getModality(), constructor.getVisibility(), constructor.getKind(), false);
157                result.add(copy.substitute(getSubstitutor()));
158            }
159            return result;
160        }
161    
162        @NotNull
163        @Override
164        public Annotations getAnnotations() {
165            return original.getAnnotations();
166        }
167    
168        @NotNull
169        @Override
170        public Name getName() {
171            return original.getName();
172        }
173    
174        @NotNull
175        @Override
176        public ClassDescriptor getOriginal() {
177            return original.getOriginal();
178        }
179    
180        @NotNull
181        @Override
182        public DeclarationDescriptor getContainingDeclaration() {
183            return original.getContainingDeclaration();
184        }
185    
186        @NotNull
187        @Override
188        public ClassDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
189            if (substitutor.isEmpty()) return this;
190            return new LazySubstitutingClassDescriptor(this, TypeSubstitutor.createChainedSubstitutor(substitutor.getSubstitution(), getSubstitutor().getSubstitution()));
191        }
192    
193        @Override
194        public ClassDescriptor getCompanionObjectDescriptor() {
195            return original.getCompanionObjectDescriptor();
196        }
197    
198        @NotNull
199        @Override
200        public ClassKind getKind() {
201            return original.getKind();
202        }
203    
204        @Override
205        @NotNull
206        public Modality getModality() {
207            return original.getModality();
208        }
209    
210        @NotNull
211        @Override
212        public Visibility getVisibility() {
213            return original.getVisibility();
214        }
215    
216        @Override
217        public boolean isInner() {
218            return original.isInner();
219        }
220    
221        @Override
222        public boolean isData() {
223            return original.isData();
224        }
225    
226        @Override
227        public boolean isCompanionObject() {
228            return original.isCompanionObject();
229        }
230    
231        @Override
232        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
233            return visitor.visitClassDescriptor(this, data);
234        }
235    
236        @Override
237        public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
238            throw new UnsupportedOperationException(); // TODO
239        }
240    
241        @NotNull
242        @Override
243        public MemberScope getUnsubstitutedInnerClassesScope() {
244            return original.getUnsubstitutedInnerClassesScope();
245        }
246    
247        @Nullable
248        @Override
249        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
250            return original.getUnsubstitutedPrimaryConstructor();
251        }
252    
253        @NotNull
254        @Override
255        public SourceElement getSource() {
256            return SourceElement.NO_SOURCE;
257        }
258    
259        @NotNull
260        @Override
261        public List<TypeParameterDescriptor> getDeclaredTypeParameters() {
262            getSubstitutor();
263            return declaredTypeParameters;
264        }
265    }