001    /*
002     * Copyright 2010-2016 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 int hashCode = 0;
034    
035        public AbstractClassTypeConstructor(@NotNull StorageManager storageManager) {
036            super(storageManager);
037        }
038    
039        @Override
040        public final int hashCode() {
041            int currentHashCode = hashCode;
042            if (currentHashCode != 0) return currentHashCode;
043    
044            ClassifierDescriptor descriptor = getDeclarationDescriptor();
045            if (descriptor instanceof ClassDescriptor && hasMeaningfulFqName(descriptor)) {
046                currentHashCode = DescriptorUtils.getFqName(descriptor).hashCode();
047            }
048            else {
049                currentHashCode = System.identityHashCode(this);
050            }
051            hashCode = currentHashCode;
052            return currentHashCode;
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            // Sometimes we can get two classes from different modules with different counts of type parameters.
073            // To avoid problems in type checker we suppose that it is different type constructors.
074            if (((TypeConstructor) other).getParameters().size() != getParameters().size()) return false;
075    
076            ClassifierDescriptor myDescriptor = getDeclarationDescriptor();
077            ClassifierDescriptor otherDescriptor = ((TypeConstructor) other).getDeclarationDescriptor();
078    
079            // descriptor for type is created once per module
080            if (myDescriptor == otherDescriptor) return true;
081    
082            // All error types have the same descriptor
083            if (!hasMeaningfulFqName(myDescriptor) ||
084                otherDescriptor != null && !hasMeaningfulFqName(otherDescriptor)) {
085                return this == other;
086            }
087    
088            if (myDescriptor instanceof ClassDescriptor && otherDescriptor instanceof ClassDescriptor) {
089                FqNameUnsafe otherFqName = DescriptorUtils.getFqName(otherDescriptor);
090                FqNameUnsafe myFqName = DescriptorUtils.getFqName(myDescriptor);
091                return myFqName.equals(otherFqName);
092            }
093    
094            return false;
095        }
096    
097        private static boolean hasMeaningfulFqName(@NotNull ClassifierDescriptor descriptor) {
098            return !ErrorUtils.isError(descriptor) &&
099                   !DescriptorUtils.isLocal(descriptor);
100        }
101    
102        @NotNull
103        @Override
104        protected Collection<KotlinType> getAdditionalNeighboursInSupertypeGraph() {
105            // We suppose that there is an edge from C to A in graph when disconnecting loops in supertypes,
106            // because such cyclic declarations should be prohibited (see p.10.2.1 of Kotlin spec)
107            // class A : B {
108            //   static class C {}
109            // }
110            // class B : A.C {}
111            DeclarationDescriptor containingDeclaration = getDeclarationDescriptor().getContainingDeclaration();
112            if (containingDeclaration instanceof ClassDescriptor) {
113                return Collections.<KotlinType>singleton(((ClassDescriptor) containingDeclaration).getDefaultType());
114            }
115            return Collections.emptyList();
116        }
117    }