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.types;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
021    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
022    import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
023    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
024    import org.jetbrains.kotlin.name.FqNameUnsafe;
025    import org.jetbrains.kotlin.resolve.DescriptorUtils;
026    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
027    import org.jetbrains.kotlin.storage.StorageManager;
028    
029    import java.util.Collection;
030    import java.util.Collections;
031    
032    public abstract class AbstractClassTypeConstructor extends AbstractTypeConstructor implements TypeConstructor {
033        private boolean hashCodeComputed;
034        private int hashCode;
035    
036        public AbstractClassTypeConstructor(@NotNull StorageManager storageManager) {
037            super(storageManager);
038        }
039    
040        @Override
041        public final int hashCode() {
042            if (!hashCodeComputed) {
043                hashCodeComputed = true;
044                ClassifierDescriptor descriptor = getDeclarationDescriptor();
045                if (descriptor instanceof ClassDescriptor && hasMeaningfulFqName(descriptor)) {
046                    hashCode = DescriptorUtils.getFqName(descriptor).hashCode();
047                }
048                else {
049                    hashCode = System.identityHashCode(this);
050                }
051            }
052            return hashCode;
053        }
054    
055        @NotNull
056        @Override
057        public abstract ClassifierDescriptor getDeclarationDescriptor();
058    
059        @NotNull
060        @Override
061        public KotlinBuiltIns getBuiltIns() {
062            return DescriptorUtilsKt.getBuiltIns(getDeclarationDescriptor());
063        }
064    
065        @Override
066        public boolean equals(Object other) {
067            if (!(other instanceof TypeConstructor)) return false;
068    
069            // performance optimization: getFqName is slow method
070            if (other.hashCode() != hashCode()) return false;
071    
072            ClassifierDescriptor myDescriptor = getDeclarationDescriptor();
073            ClassifierDescriptor otherDescriptor = ((TypeConstructor) other).getDeclarationDescriptor();
074    
075            // descriptor for type is created once per module
076            if (myDescriptor == otherDescriptor) return true;
077    
078            // All error types have the same descriptor
079            if (!hasMeaningfulFqName(myDescriptor) ||
080                otherDescriptor != null && !hasMeaningfulFqName(otherDescriptor)) {
081                return this == other;
082            }
083    
084            if (myDescriptor instanceof ClassDescriptor && otherDescriptor instanceof ClassDescriptor) {
085                FqNameUnsafe otherFqName = DescriptorUtils.getFqName(otherDescriptor);
086                FqNameUnsafe myFqName = DescriptorUtils.getFqName(myDescriptor);
087                return myFqName.equals(otherFqName);
088            }
089    
090            return false;
091        }
092    
093        private static boolean hasMeaningfulFqName(@NotNull ClassifierDescriptor descriptor) {
094            return !ErrorUtils.isError(descriptor) &&
095                   !DescriptorUtils.isLocal(descriptor);
096        }
097    
098        @NotNull
099        @Override
100        protected Collection<KotlinType> getAdditionalNeighboursInSupertypeGraph() {
101            // We suppose that there is an edge from C to A in graph when disconnecting loops in supertypes,
102            // because such cyclic declarations should be prohibited (see p.10.2.1 of Kotlin spec)
103            // class A : B {
104            //   static class C {}
105            // }
106            // class B : A.C {}
107            DeclarationDescriptor containingDeclaration = getDeclarationDescriptor().getContainingDeclaration();
108            if (containingDeclaration instanceof ClassDescriptor) {
109                return Collections.singleton(((ClassDescriptor) containingDeclaration).getDefaultType());
110            }
111            return Collections.emptyList();
112        }
113    }