All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.types.AbstractClassTypeConstructor Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * 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.types;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.storage.StorageManager;

import java.util.Collection;
import java.util.Collections;

public abstract class AbstractClassTypeConstructor extends AbstractTypeConstructor implements TypeConstructor {
    private int hashCode = 0;

    public AbstractClassTypeConstructor(@NotNull StorageManager storageManager) {
        super(storageManager);
    }

    @Override
    public final int hashCode() {
        int currentHashCode = hashCode;
        if (currentHashCode != 0) return currentHashCode;

        ClassifierDescriptor descriptor = getDeclarationDescriptor();
        if (descriptor instanceof ClassDescriptor && hasMeaningfulFqName(descriptor)) {
            currentHashCode = DescriptorUtils.getFqName(descriptor).hashCode();
        }
        else {
            currentHashCode = System.identityHashCode(this);
        }
        hashCode = currentHashCode;
        return currentHashCode;
    }

    @NotNull
    @Override
    public abstract ClassifierDescriptor getDeclarationDescriptor();

    @NotNull
    @Override
    public KotlinBuiltIns getBuiltIns() {
        return DescriptorUtilsKt.getBuiltIns(getDeclarationDescriptor());
    }

    @Override
    public final boolean equals(Object other) {
        if (!(other instanceof TypeConstructor)) return false;

        // performance optimization: getFqName is slow method
        if (other.hashCode() != hashCode()) return false;

        // Sometimes we can get two classes from different modules with different counts of type parameters.
        // To avoid problems in type checker we suppose that it is different type constructors.
        if (((TypeConstructor) other).getParameters().size() != getParameters().size()) return false;

        ClassifierDescriptor myDescriptor = getDeclarationDescriptor();
        ClassifierDescriptor otherDescriptor = ((TypeConstructor) other).getDeclarationDescriptor();

        // descriptor for type is created once per module
        if (myDescriptor == otherDescriptor) return true;

        // All error types have the same descriptor
        if (!hasMeaningfulFqName(myDescriptor) ||
            otherDescriptor != null && !hasMeaningfulFqName(otherDescriptor)) {
            return this == other;
        }

        if (myDescriptor instanceof ClassDescriptor && otherDescriptor instanceof ClassDescriptor) {
            return areFqNamesEqual(((ClassDescriptor) myDescriptor), ((ClassDescriptor) otherDescriptor));
        }

        return false;
    }

    private static boolean areFqNamesEqual(ClassDescriptor first, ClassDescriptor second) {
        if (!first.getName().equals(second.getName())) return false;

        DeclarationDescriptor a = first.getContainingDeclaration();
        DeclarationDescriptor b = second.getContainingDeclaration();
        while (a != null && b != null) {
            if (a instanceof ModuleDescriptor) return b instanceof ModuleDescriptor;
            if (b instanceof ModuleDescriptor) return false;

            if (a instanceof PackageFragmentDescriptor) {
                return b instanceof PackageFragmentDescriptor &&
                       ((PackageFragmentDescriptor) a).getFqName().equals(((PackageFragmentDescriptor) b).getFqName());
            }
            if (b instanceof PackageFragmentDescriptor) return false;

            if (!a.getName().equals(b.getName())) return false;

            a = a.getContainingDeclaration();
            b = b.getContainingDeclaration();
        }
        return true;
    }

    private static boolean hasMeaningfulFqName(@NotNull ClassifierDescriptor descriptor) {
        return !ErrorUtils.isError(descriptor) &&
               !DescriptorUtils.isLocal(descriptor);
    }

    @NotNull
    @Override
    protected Collection getAdditionalNeighboursInSupertypeGraph() {
        // We suppose that there is an edge from C to A in graph when disconnecting loops in supertypes,
        // because such cyclic declarations should be prohibited (see p.10.2.1 of Kotlin spec)
        // class A : B {
        //   static class C {}
        // }
        // class B : A.C {}
        DeclarationDescriptor containingDeclaration = getDeclarationDescriptor().getContainingDeclaration();
        if (containingDeclaration instanceof ClassDescriptor) {
            return Collections.singleton(((ClassDescriptor) containingDeclaration).getDefaultType());
        }
        return Collections.emptyList();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy