001    package org.jetbrains.jet.descriptors.serialization;
002    
003    import org.jetbrains.annotations.NotNull;
004    import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
005    import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
006    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
007    import org.jetbrains.jet.lang.resolve.name.FqName;
008    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
009    import org.jetbrains.jet.lang.resolve.name.Name;
010    
011    import java.util.List;
012    
013    public final class ClassId {
014        private final FqName packageFqName;
015        private final FqNameUnsafe relativeClassName;
016    
017        @NotNull
018        public static ClassId fromFqNameAndContainingDeclaration(
019                @NotNull FqNameUnsafe fqName,
020                @NotNull ClassOrNamespaceDescriptor containingDeclaration
021        ) {
022            NamespaceDescriptor containingNamespace = DescriptorUtils.getParentOfType(containingDeclaration, NamespaceDescriptor.class, false);
023            assert containingNamespace != null;
024            List<Name> fullNameSegments = fqName.pathSegments();
025            FqName namespaceFqName = DescriptorUtils.getFQName(containingNamespace).toSafe();
026            List<Name> namespaceNameSegments = namespaceFqName.pathSegments();
027            assert fullNameSegments.subList(0, namespaceNameSegments.size()).equals(namespaceNameSegments);
028            List<Name> relativeNameSegments = fullNameSegments.subList(namespaceNameSegments.size(), fullNameSegments.size());
029            return new ClassId(namespaceFqName, FqNameUnsafe.fromSegments(relativeNameSegments));
030        }
031    
032        public ClassId(@NotNull FqName packageFqName, @NotNull FqNameUnsafe relativeClassName) {
033            this.packageFqName = packageFqName;
034            assert !relativeClassName.isRoot() : "Class name must not be root. " + packageFqName;
035            this.relativeClassName = relativeClassName;
036        }
037    
038        @NotNull
039        public FqName getPackageFqName() {
040            return packageFqName;
041        }
042    
043        @NotNull
044        public FqNameUnsafe getRelativeClassName() {
045            return relativeClassName;
046        }
047    
048        @NotNull
049        public ClassId createNestedClassId(@NotNull Name name) {
050            return new ClassId(getPackageFqName(), relativeClassName.child(name));
051        }
052    
053        @NotNull
054        public ClassId getOuterClassId() {
055            return new ClassId(getPackageFqName(), relativeClassName.parent());
056        }
057    
058        public boolean isTopLevelClass() {
059            return relativeClassName.parent().isRoot();
060        }
061    
062        public FqNameUnsafe asSingleFqName() {
063            if (packageFqName.isRoot()) return relativeClassName;
064            return new FqNameUnsafe(packageFqName.asString() + "." + relativeClassName.asString());
065        }
066    
067        @Override
068        public boolean equals(Object o) {
069            if (this == o) return true;
070            if (o == null || getClass() != o.getClass()) return false;
071    
072            ClassId id = (ClassId) o;
073    
074            if (!packageFqName.equals(id.packageFqName)) return false;
075            if (!relativeClassName.equals(id.relativeClassName)) return false;
076    
077            return true;
078        }
079    
080        @Override
081        public int hashCode() {
082            int result = packageFqName.hashCode();
083            result = 31 * result + relativeClassName.hashCode();
084            return result;
085        }
086    
087        @Override
088        public String toString() {
089            if (packageFqName.isRoot()) return "/" + relativeClassName;
090            return packageFqName.toString().replace('.', '/') + "/" + relativeClassName;
091        }
092    }