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.name;
018    
019    import org.jetbrains.annotations.NotNull;
020    
021    /**
022     * A class name which is used to uniquely identify a Kotlin class.
023     *
024     * If local = true, the class represented by this id is either itself local or is an inner class of some local class. This also means that
025     * the first non-class container of the class is not a package.
026     * In the case of a local class, relativeClassName consists of a single name including all callables' and class' names all the way up to
027     * the package, separated by dollar signs. If a class is an inner of local, relativeClassName would consist of two names,
028     * the second one being the class' short name.
029     */
030    public final class ClassId {
031        @NotNull
032        public static ClassId topLevel(@NotNull FqName topLevelFqName) {
033            return new ClassId(topLevelFqName.parent(), topLevelFqName.shortName());
034        }
035    
036        private final FqName packageFqName;
037        private final FqName relativeClassName;
038        private final boolean local;
039    
040        public ClassId(@NotNull FqName packageFqName, @NotNull FqName relativeClassName, boolean local) {
041            this.packageFqName = packageFqName;
042            assert !relativeClassName.isRoot() :
043                    "Class name must not be root: " + packageFqName + (local ? " (local)" : "");
044            this.relativeClassName = relativeClassName;
045            this.local = local;
046        }
047    
048        public ClassId(@NotNull FqName packageFqName, @NotNull Name topLevelName) {
049            this(packageFqName, FqName.topLevel(topLevelName), false);
050        }
051    
052        @NotNull
053        public FqName getPackageFqName() {
054            return packageFqName;
055        }
056    
057        @NotNull
058        public FqName getRelativeClassName() {
059            return relativeClassName;
060        }
061    
062        @NotNull
063        public Name getShortClassName() {
064            return relativeClassName.shortName();
065        }
066    
067        public boolean isLocal() {
068            return local;
069        }
070    
071        @NotNull
072        public ClassId createNestedClassId(@NotNull Name name) {
073            return new ClassId(getPackageFqName(), relativeClassName.child(name), local);
074        }
075    
076        @NotNull
077        public ClassId getOuterClassId() {
078            return new ClassId(getPackageFqName(), relativeClassName.parent(), local);
079        }
080    
081        public boolean isNestedClass() {
082            return !relativeClassName.parent().isRoot();
083        }
084    
085        @NotNull
086        public FqName asSingleFqName() {
087            if (packageFqName.isRoot()) return relativeClassName;
088            return new FqName(packageFqName.asString() + "." + relativeClassName.asString());
089        }
090    
091        @Override
092        public boolean equals(Object o) {
093            if (this == o) return true;
094            if (o == null || getClass() != o.getClass()) return false;
095    
096            ClassId id = (ClassId) o;
097    
098            return packageFqName.equals(id.packageFqName) &&
099                   relativeClassName.equals(id.relativeClassName) &&
100                   local == id.local;
101        }
102    
103        @Override
104        public int hashCode() {
105            int result = packageFqName.hashCode();
106            result = 31 * result + relativeClassName.hashCode();
107            result = 31 * result + Boolean.valueOf(local).hashCode();
108            return result;
109        }
110    
111        @Override
112        public String toString() {
113            if (packageFqName.isRoot()) return "/" + relativeClassName;
114            return packageFqName.toString().replace('.', '/') + "/" + relativeClassName;
115        }
116    }