org.jetbrains.kotlin.name.ClassId Maven / Gradle / Ivy
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.name;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* A class name which is used to uniquely identify a Kotlin class.
*
* 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
* the first non-class container of the class is not a package.
* In the case of a local class, relativeClassName consists of a single name including all callables' and class' names all the way up to
* the package, separated by dollar signs. If a class is an inner of local, relativeClassName would consist of two names,
* the second one being the class' short name.
*/
public final class ClassId {
@NotNull
public static ClassId topLevel(@NotNull FqName topLevelFqName) {
return new ClassId(topLevelFqName.parent(), topLevelFqName.shortName());
}
private final FqName packageFqName;
private final FqName relativeClassName;
private final boolean local;
public ClassId(@NotNull FqName packageFqName, @NotNull FqName relativeClassName, boolean local) {
this.packageFqName = packageFqName;
assert !relativeClassName.isRoot() :
"Class name must not be root: " + packageFqName + (local ? " (local)" : "");
this.relativeClassName = relativeClassName;
this.local = local;
}
public ClassId(@NotNull FqName packageFqName, @NotNull Name topLevelName) {
this(packageFqName, FqName.topLevel(topLevelName), false);
}
@NotNull
public FqName getPackageFqName() {
return packageFqName;
}
@NotNull
public FqName getRelativeClassName() {
return relativeClassName;
}
@Nullable
public ClassId getParentClassId() {
if (!isNestedClass()) return null;
return new ClassId(packageFqName, relativeClassName.parent(), isLocal());
}
@NotNull
public Name getShortClassName() {
return relativeClassName.shortName();
}
public boolean isLocal() {
return local;
}
@NotNull
public ClassId createNestedClassId(@NotNull Name name) {
return new ClassId(getPackageFqName(), relativeClassName.child(name), local);
}
@Nullable
public ClassId getOuterClassId() {
FqName parent = relativeClassName.parent();
return parent.isRoot() ? null : new ClassId(getPackageFqName(), parent, local);
}
public boolean isNestedClass() {
return !relativeClassName.parent().isRoot();
}
@NotNull
public FqName asSingleFqName() {
if (packageFqName.isRoot()) return relativeClassName;
return new FqName(packageFqName.asString() + "." + relativeClassName.asString());
}
public boolean startsWith(@NotNull Name segment) {
return packageFqName.startsWith(segment);
}
/**
* @param string a string where packages are delimited by '/' and classes by '.', e.g. "kotlin/Map.Entry"
*/
@NotNull
public static ClassId fromString(@NotNull String string) {
return fromString(string, false);
}
@NotNull
public static ClassId fromString(@NotNull String string, boolean isLocal) {
int lastSlashIndex = string.lastIndexOf("/");
String packageName;
String className;
if (lastSlashIndex == -1) {
packageName = "";
className = string;
} else {
packageName = string.substring(0, lastSlashIndex).replace('/', '.');
className = string.substring(lastSlashIndex + 1);
}
return new ClassId(new FqName(packageName), new FqName(className), isLocal);
}
/**
* @return a string where packages are delimited by '/' and classes by '.', e.g. "kotlin/Map.Entry"
*/
@NotNull
public String asString() {
if (packageFqName.isRoot()) return relativeClassName.asString();
return packageFqName.asString().replace('.', '/') + "/" + relativeClassName.asString();
}
@NotNull
public String asFqNameString() {
if (packageFqName.isRoot()) return relativeClassName.asString();
return packageFqName.asString() + "." + relativeClassName.asString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClassId id = (ClassId) o;
return packageFqName.equals(id.packageFqName) &&
relativeClassName.equals(id.relativeClassName) &&
local == id.local;
}
@Override
public int hashCode() {
int result = packageFqName.hashCode();
result = 31 * result + relativeClassName.hashCode();
result = 31 * result + Boolean.valueOf(local).hashCode();
return result;
}
@Override
public String toString() {
return packageFqName.isRoot() ? "/" + asString() : asString();
}
}