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 }