/*
* 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;
/**
* 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;
}
@
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) {
String packageName =
StringsKt.
substringBeforeLast(
string, '/', "").
replace('/', '.');
String className =
StringsKt.
substringAfterLast(
string, '/',
string);
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();
}
@
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();
}
}