/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.descriptors.impl;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.resolve.scopes.SubstitutingScope;
import org.jetbrains.kotlin.types.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class LazySubstitutingClassDescriptor implements ClassDescriptor {
private final ClassDescriptor original;
private final TypeSubstitutor originalSubstitutor;
private TypeSubstitutor newSubstitutor;
private List<TypeParameterDescriptor> typeConstructorParameters;
private List<TypeParameterDescriptor> declaredTypeParameters;
private TypeConstructor typeConstructor;
public LazySubstitutingClassDescriptor(ClassDescriptor descriptor, TypeSubstitutor substitutor) {
this.original = descriptor;
this.originalSubstitutor = substitutor;
}
private TypeSubstitutor getSubstitutor() {
if (newSubstitutor == null) {
if (originalSubstitutor.isEmpty()) {
newSubstitutor = originalSubstitutor;
}
else {
List<TypeParameterDescriptor> originalTypeParameters = original.getTypeConstructor().getParameters();
typeConstructorParameters = new ArrayList<TypeParameterDescriptor>(originalTypeParameters.size());
newSubstitutor = DescriptorSubstitutor.substituteTypeParameters(
originalTypeParameters, originalSubstitutor.getSubstitution(), this, typeConstructorParameters
);
declaredTypeParameters = CollectionsKt.filter(typeConstructorParameters, new Function1<TypeParameterDescriptor, Boolean>() {
@Override
public Boolean invoke(TypeParameterDescriptor descriptor) {
return !descriptor.isCapturedFromOuterDeclaration();
}
});
}
}
return newSubstitutor;
}
@NotNull
@Override
public TypeConstructor getTypeConstructor() {
TypeConstructor originalTypeConstructor = original.getTypeConstructor();
if (originalSubstitutor.isEmpty()) {
return originalTypeConstructor;
}
if (typeConstructor == null) {
TypeSubstitutor substitutor = getSubstitutor();
Collection<KotlinType> originalSupertypes = originalTypeConstructor.getSupertypes();
Collection<KotlinType> supertypes = new ArrayList<KotlinType>(originalSupertypes.size());
for (KotlinType supertype : originalSupertypes) {
supertypes.add(substitutor.substitute(supertype, Variance.INVARIANT));
}
typeConstructor = new ClassTypeConstructorImpl(this, originalTypeConstructor.isFinal(), typeConstructorParameters, supertypes);
}
return typeConstructor;
}
@NotNull
@Override
public MemberScope getMemberScope(@NotNull List<? extends TypeProjection> typeArguments) {
MemberScope memberScope = original.getMemberScope(typeArguments);
if (originalSubstitutor.isEmpty()) {
return memberScope;
}
return new SubstitutingScope(memberScope, getSubstitutor());
}
@NotNull
@Override
public MemberScope getMemberScope(@NotNull TypeSubstitution typeSubstitution) {
MemberScope memberScope = original.getMemberScope(typeSubstitution);
if (originalSubstitutor.isEmpty()) {
return memberScope;
}
return new SubstitutingScope(memberScope, getSubstitutor());
}
@NotNull
@Override
public MemberScope getUnsubstitutedMemberScope() {
MemberScope memberScope = original.getUnsubstitutedMemberScope();
if (originalSubstitutor.isEmpty()) {
return memberScope;
}
return new SubstitutingScope(memberScope, getSubstitutor());
}
@NotNull
@Override
public MemberScope getStaticScope() {
return original.getStaticScope();
}
@NotNull
@Override
public SimpleType getDefaultType() {
List<TypeProjection> typeProjections = TypeUtils.getDefaultTypeProjections(getTypeConstructor().getParameters());
return KotlinTypeFactory.simpleNotNullType(getAnnotations(), this, typeProjections);
}
@NotNull
@Override
public ReceiverParameterDescriptor getThisAsReceiverParameter() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public Collection<ClassConstructorDescriptor> getConstructors() {
Collection<ClassConstructorDescriptor> originalConstructors = original.getConstructors();
Collection<ClassConstructorDescriptor> result = new ArrayList<ClassConstructorDescriptor>(originalConstructors.size());
for (ClassConstructorDescriptor constructor : originalConstructors) {
ClassConstructorDescriptor copy =
constructor.copy(this, constructor.getModality(), constructor.getVisibility(), constructor.getKind(), false);
result.add(copy.substitute(getSubstitutor()));
}
return result;
}
@NotNull
@Override
public Annotations getAnnotations() {
return original.getAnnotations();
}
@NotNull
@Override
public Name getName() {
return original.getName();
}
@NotNull
@Override
public ClassDescriptor getOriginal() {
return original.getOriginal();
}
@NotNull
@Override
public DeclarationDescriptor getContainingDeclaration() {
return original.getContainingDeclaration();
}
@NotNull
@Override
public ClassDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
if (substitutor.isEmpty()) return this;
return new LazySubstitutingClassDescriptor(this, TypeSubstitutor.createChainedSubstitutor(substitutor.getSubstitution(), getSubstitutor().getSubstitution()));
}
@Override
public ClassDescriptor getCompanionObjectDescriptor() {
return original.getCompanionObjectDescriptor();
}
@NotNull
@Override
public ClassKind getKind() {
return original.getKind();
}
@Override
@NotNull
public Modality getModality() {
return original.getModality();
}
@NotNull
@Override
public Visibility getVisibility() {
return original.getVisibility();
}
@Override
public boolean isInner() {
return original.isInner();
}
@Override
public boolean isData() {
return original.isData();
}
@Override
public boolean isExternal() {
return original.isExternal();
}
@Override
public boolean isCompanionObject() {
return original.isCompanionObject();
}
@Override
public boolean isHeader() {
return original.isHeader();
}
@Override
public boolean isImpl() {
return original.isImpl();
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitClassDescriptor(this, data);
}
@Override
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public MemberScope getUnsubstitutedInnerClassesScope() {
return original.getUnsubstitutedInnerClassesScope();
}
@Nullable
@Override
public ClassConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
return original.getUnsubstitutedPrimaryConstructor();
}
@NotNull
@Override
public SourceElement getSource() {
return SourceElement.NO_SOURCE;
}
@NotNull
@Override
public List<TypeParameterDescriptor> getDeclaredTypeParameters() {
getSubstitutor();
return declaredTypeParameters;
}
@NotNull
@Override
public Collection<ClassDescriptor> getSealedSubclasses() {
return original.getSealedSubclasses();
}
}