Revert "Move fqname related stuff into core:util.runtime module"
This reverts commit e651e1c6
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.name
|
||||
|
||||
// NB: with className == null we are at top level
|
||||
data class CallableId(
|
||||
val packageName: FqName,
|
||||
val className: FqName?,
|
||||
val callableName: Name,
|
||||
// Currently, it's only used for debug info
|
||||
private val pathToLocal: FqName? = null
|
||||
) {
|
||||
private companion object {
|
||||
val LOCAL_NAME = Name.special("<local>")
|
||||
val PACKAGE_FQ_NAME_FOR_LOCAL = FqName.topLevel(LOCAL_NAME)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if corresponding declaration is itself local or it is a member of local class
|
||||
* Otherwise, returns `false`
|
||||
*/
|
||||
val isLocal: Boolean
|
||||
get() = packageName == PACKAGE_FQ_NAME_FOR_LOCAL
|
||||
|| classId?.isLocal == true
|
||||
|
||||
var classId: ClassId? = null
|
||||
get() {
|
||||
if (field == null && className != null) {
|
||||
field = ClassId(packageName, className, false)
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
constructor(classId: ClassId, callableName: Name) : this(classId.packageFqName, classId.relativeClassName, callableName) {
|
||||
this.classId = classId
|
||||
}
|
||||
|
||||
constructor(packageName: FqName, callableName: Name) : this(packageName, null, callableName)
|
||||
|
||||
constructor(
|
||||
callableName: Name,
|
||||
// Currently, it's only used for debug info
|
||||
pathToLocal: FqName? = null
|
||||
) : this(
|
||||
PACKAGE_FQ_NAME_FOR_LOCAL,
|
||||
className = null,
|
||||
callableName,
|
||||
pathToLocal,
|
||||
)
|
||||
|
||||
fun asFqNameForDebugInfo(): FqName {
|
||||
if (pathToLocal != null) return pathToLocal.child(callableName)
|
||||
return asSingleFqName()
|
||||
}
|
||||
|
||||
fun asSingleFqName(): FqName {
|
||||
return classId?.asSingleFqName()?.child(callableName) ?: packageName.child(callableName)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return buildString {
|
||||
append(packageName.asString().replace('.', '/'))
|
||||
append("/")
|
||||
if (className != null) {
|
||||
append(className)
|
||||
append(".")
|
||||
}
|
||||
append(callableName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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) {
|
||||
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();
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.utils.StringsKt;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class FqName {
|
||||
|
||||
@NotNull
|
||||
public static FqName fromSegments(@NotNull List<String> names) {
|
||||
return new FqName(StringsKt.join(names, "."));
|
||||
}
|
||||
|
||||
public static final FqName ROOT = new FqName("");
|
||||
|
||||
@NotNull
|
||||
private final FqNameUnsafe fqName;
|
||||
|
||||
// cache
|
||||
private transient FqName parent;
|
||||
|
||||
public FqName(@NotNull String fqName) {
|
||||
this.fqName = new FqNameUnsafe(fqName, this);
|
||||
}
|
||||
|
||||
public FqName(@NotNull FqNameUnsafe fqName) {
|
||||
this.fqName = fqName;
|
||||
}
|
||||
|
||||
private FqName(@NotNull FqNameUnsafe fqName, FqName parent) {
|
||||
this.fqName = fqName;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String asString() {
|
||||
return fqName.asString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqNameUnsafe toUnsafe() {
|
||||
return fqName;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return fqName.isRoot();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqName parent() {
|
||||
if (parent != null) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
if (isRoot()) {
|
||||
throw new IllegalStateException("root");
|
||||
}
|
||||
|
||||
parent = new FqName(fqName.parent());
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqName child(@NotNull Name name) {
|
||||
return new FqName(fqName.child(name), this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Name shortName() {
|
||||
return fqName.shortName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Name shortNameOrSpecial() {
|
||||
return fqName.shortNameOrSpecial();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Name> pathSegments() {
|
||||
return fqName.pathSegments();
|
||||
}
|
||||
|
||||
public boolean startsWith(@NotNull Name segment) {
|
||||
return fqName.startsWith(segment);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FqName topLevel(@NotNull Name shortName) {
|
||||
return new FqName(FqNameUnsafe.topLevel(shortName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fqName.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof FqName)) return false;
|
||||
|
||||
FqName otherFqName = (FqName) o;
|
||||
|
||||
if (!fqName.equals(otherFqName.fqName)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return fqName.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* 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.collections.ArraysKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Like {@link FqName} but allows '<' and '>' characters in name.
|
||||
*/
|
||||
public final class FqNameUnsafe {
|
||||
private static final Name ROOT_NAME = Name.special("<root>");
|
||||
private static final Pattern SPLIT_BY_DOTS = Pattern.compile("\\.");
|
||||
|
||||
private static final Function1<String, Name> STRING_TO_NAME = new Function1<String, Name>() {
|
||||
@Override
|
||||
public Name invoke(String name) {
|
||||
return Name.guessByFirstCharacter(name);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private final String fqName;
|
||||
|
||||
// cache
|
||||
private transient FqName safe;
|
||||
private transient FqNameUnsafe parent;
|
||||
private transient Name shortName;
|
||||
|
||||
FqNameUnsafe(@NotNull String fqName, @NotNull FqName safe) {
|
||||
this.fqName = fqName;
|
||||
this.safe = safe;
|
||||
}
|
||||
|
||||
public FqNameUnsafe(@NotNull String fqName) {
|
||||
this.fqName = fqName;
|
||||
}
|
||||
|
||||
private FqNameUnsafe(@NotNull String fqName, FqNameUnsafe parent, Name shortName) {
|
||||
this.fqName = fqName;
|
||||
this.parent = parent;
|
||||
this.shortName = shortName;
|
||||
}
|
||||
|
||||
public static boolean isValid(@Nullable String qualifiedName) {
|
||||
// TODO: There's a valid name with escape char ``
|
||||
return qualifiedName != null && qualifiedName.indexOf('/') < 0 && qualifiedName.indexOf('*') < 0;
|
||||
}
|
||||
|
||||
private void compute() {
|
||||
int lastDot = fqName.lastIndexOf('.');
|
||||
if (lastDot >= 0) {
|
||||
shortName = Name.guessByFirstCharacter(fqName.substring(lastDot + 1));
|
||||
parent = new FqNameUnsafe(fqName.substring(0, lastDot));
|
||||
}
|
||||
else {
|
||||
shortName = Name.guessByFirstCharacter(fqName);
|
||||
parent = FqName.ROOT.toUnsafe();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String asString() {
|
||||
return fqName;
|
||||
}
|
||||
|
||||
public boolean isSafe() {
|
||||
return safe != null || asString().indexOf('<') < 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqName toSafe() {
|
||||
if (safe != null) {
|
||||
return safe;
|
||||
}
|
||||
safe = new FqName(this);
|
||||
return safe;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return fqName.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqNameUnsafe parent() {
|
||||
if (parent != null) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
if (isRoot()) {
|
||||
throw new IllegalStateException("root");
|
||||
}
|
||||
|
||||
compute();
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqNameUnsafe child(@NotNull Name name) {
|
||||
String childFqName;
|
||||
if (isRoot()) {
|
||||
childFqName = name.asString();
|
||||
}
|
||||
else {
|
||||
childFqName = fqName + "." + name.asString();
|
||||
}
|
||||
return new FqNameUnsafe(childFqName, this, name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Name shortName() {
|
||||
if (shortName != null) {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
if (isRoot()) {
|
||||
throw new IllegalStateException("root");
|
||||
}
|
||||
|
||||
compute();
|
||||
|
||||
return shortName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Name shortNameOrSpecial() {
|
||||
if (isRoot()) {
|
||||
return ROOT_NAME;
|
||||
}
|
||||
else {
|
||||
return shortName();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Name> pathSegments() {
|
||||
return isRoot() ? Collections.<Name>emptyList() : ArraysKt.map(SPLIT_BY_DOTS.split(fqName), STRING_TO_NAME);
|
||||
}
|
||||
|
||||
public boolean startsWith(@NotNull Name segment) {
|
||||
if (isRoot())
|
||||
return false;
|
||||
|
||||
int firstDot = fqName.indexOf('.');
|
||||
return fqName.regionMatches(0, segment.asString(), 0, firstDot == -1 ? fqName.length() : firstDot);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FqNameUnsafe topLevel(@NotNull Name shortName) {
|
||||
return new FqNameUnsafe(shortName.asString(), FqName.ROOT.toUnsafe(), shortName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String toString() {
|
||||
return isRoot() ? ROOT_NAME.asString() : fqName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof FqNameUnsafe)) return false;
|
||||
|
||||
FqNameUnsafe that = (FqNameUnsafe) o;
|
||||
|
||||
if (!fqName.equals(that.fqName)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return fqName.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.name
|
||||
|
||||
fun FqName.isSubpackageOf(packageName: FqName): Boolean {
|
||||
return when {
|
||||
this == packageName -> true
|
||||
packageName.isRoot -> true
|
||||
else -> isSubpackageOf(this.asString(), packageName.asString())
|
||||
}
|
||||
}
|
||||
|
||||
fun FqName.isChildOf(packageName: FqName): Boolean = parentOrNull() == packageName
|
||||
|
||||
private fun isSubpackageOf(subpackageNameStr: String, packageNameStr: String): Boolean {
|
||||
return subpackageNameStr.startsWith(packageNameStr) && subpackageNameStr[packageNameStr.length] == '.'
|
||||
}
|
||||
|
||||
fun FqName.isOneSegmentFQN(): Boolean = !isRoot && parent().isRoot
|
||||
|
||||
/**
|
||||
* Get the tail part of the FQ name by stripping a prefix. If FQ name does not begin with the given prefix, it will be returned as is.
|
||||
*
|
||||
* Examples:
|
||||
* "org.jetbrains.kotlin".tail("org") = "jetbrains.kotlin"
|
||||
* "org.jetbrains.kotlin".tail("") = "org.jetbrains.kotlin"
|
||||
* "org.jetbrains.kotlin".tail("org.jetbrains.kotlin") = ""
|
||||
* "org.jetbrains.kotlin".tail("org.jetbrains.gogland") = "org.jetbrains.kotlin"
|
||||
*/
|
||||
fun FqName.tail(prefix: FqName): FqName {
|
||||
return when {
|
||||
!isSubpackageOf(prefix) || prefix.isRoot -> this
|
||||
this == prefix -> FqName.ROOT
|
||||
else -> FqName(asString().substring(prefix.asString().length + 1))
|
||||
}
|
||||
}
|
||||
|
||||
fun FqName.parentOrNull(): FqName? = if (this.isRoot) null else parent()
|
||||
|
||||
private enum class State {
|
||||
BEGINNING,
|
||||
MIDDLE,
|
||||
AFTER_DOT
|
||||
}
|
||||
|
||||
// Check that it is javaName(\.javaName)* or an empty string
|
||||
fun isValidJavaFqName(qualifiedName: String?): Boolean {
|
||||
if (qualifiedName == null) return false
|
||||
|
||||
var state = State.BEGINNING
|
||||
|
||||
for (c in qualifiedName) {
|
||||
when (state) {
|
||||
State.BEGINNING, State.AFTER_DOT -> {
|
||||
if (!Character.isJavaIdentifierPart(c)) return false
|
||||
state = State.MIDDLE
|
||||
}
|
||||
State.MIDDLE -> {
|
||||
if (c == '.') {
|
||||
state = State.AFTER_DOT
|
||||
} else if (!Character.isJavaIdentifierPart(c)) return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state != State.AFTER_DOT
|
||||
}
|
||||
|
||||
fun <V> FqName.findValueForMostSpecificFqname(values: Map<FqName, V>): V? {
|
||||
val suitableItems = values.filter { (fqName, _) -> this == fqName || this.isChildOf(fqName) }
|
||||
.takeIf { it.isNotEmpty() } ?: return null
|
||||
|
||||
return suitableItems.minByOrNull { (fqName, _) -> fqName.tail(this).asString().length }?.value
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* 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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class Name implements Comparable<Name> {
|
||||
@NotNull
|
||||
private final String name;
|
||||
private final boolean special;
|
||||
|
||||
private Name(@NotNull String name, boolean special) {
|
||||
this.name = name;
|
||||
this.special = special;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String asString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getIdentifier() {
|
||||
if (special) {
|
||||
throw new IllegalStateException("not identifier: " + this);
|
||||
}
|
||||
return asString();
|
||||
}
|
||||
|
||||
public boolean isSpecial() {
|
||||
return special;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String asStringStripSpecialMarkers() {
|
||||
if (isSpecial()) return asString().substring(1, asString().length() - 1);
|
||||
return asString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Name that) {
|
||||
return this.name.compareTo(that.name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Name identifier(@NotNull String name) {
|
||||
return new Name(name, false);
|
||||
}
|
||||
|
||||
public static boolean isValidIdentifier(@NotNull String name) {
|
||||
if (name.isEmpty() || name.startsWith("<")) return false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char ch = name.charAt(i);
|
||||
if (ch == '.' || ch == '/' || ch == '\\') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Name special(@NotNull String name) {
|
||||
if (!name.startsWith("<")) {
|
||||
throw new IllegalArgumentException("special name must start with '<': " + name);
|
||||
}
|
||||
return new Name(name, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Name guessByFirstCharacter(@NotNull String name) {
|
||||
if (name.startsWith("<")) {
|
||||
return special(name);
|
||||
}
|
||||
else {
|
||||
return identifier(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getIdentifierOrNullIfSpecial() {
|
||||
if (special) return null;
|
||||
return asString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof Name)) return false;
|
||||
|
||||
Name name1 = (Name) o;
|
||||
|
||||
if (special != name1.special) return false;
|
||||
if (!name.equals(name1.name)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + (special ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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 java.util.*
|
||||
|
||||
object NameUtils {
|
||||
private val SANITIZE_AS_JAVA_INVALID_CHARACTERS = "[^\\p{L}\\p{Digit}]".toRegex()
|
||||
|
||||
@JvmStatic
|
||||
fun sanitizeAsJavaIdentifier(name: String): String {
|
||||
return SANITIZE_AS_JAVA_INVALID_CHARACTERS.replace(name, "_")
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes the short name of the file (without extension) and sanitizes it so that it's a valid Java identifier.
|
||||
* E.g. "fileName" -> "FileName", "1" -> "_1", "" -> "_"
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getPackagePartClassNamePrefix(shortFileName: String): String =
|
||||
if (shortFileName.isEmpty())
|
||||
"_"
|
||||
else
|
||||
capitalizeAsJavaClassName(sanitizeAsJavaIdentifier(shortFileName))
|
||||
|
||||
@JvmStatic
|
||||
private fun capitalizeAsJavaClassName(str: String): String =
|
||||
// NB `uppercase` uses Locale.ROOT and is locale-independent.
|
||||
// See Javadoc on java.lang.String.toUpperCase() for more details.
|
||||
if (Character.isJavaIdentifierStart(str[0]))
|
||||
str[0].uppercase() + str.substring(1)
|
||||
else
|
||||
"_$str"
|
||||
|
||||
// "pkg/someScript.kts" -> "SomeScript"
|
||||
@JvmStatic
|
||||
fun getScriptNameForFile(filePath: String): Name =
|
||||
Name.identifier(NameUtils.getPackagePartClassNamePrefix(filePath.substringAfterLast('/').substringBeforeLast('.')))
|
||||
|
||||
@JvmStatic
|
||||
fun hasName(name: Name) = name != SpecialNames.NO_NAME_PROVIDED && name != SpecialNames.ANONYMOUS_FUNCTION
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SpecialNames {
|
||||
public static final Name NO_NAME_PROVIDED = Name.special("<no name provided>");
|
||||
public static final Name ROOT_PACKAGE = Name.special("<root package>");
|
||||
|
||||
public static final Name DEFAULT_NAME_FOR_COMPANION_OBJECT = Name.identifier("Companion");
|
||||
|
||||
// This name is used as a key for the case when something has no name _due to a syntactic error_
|
||||
// Example: fun (x: Int) = 5
|
||||
// There's no name for this function in the PSI
|
||||
// The name contains a GUID to avoid clashes, if a clash happens, it's not a big deal: the code does not compile anyway
|
||||
public static final Name SAFE_IDENTIFIER_FOR_NO_NAME = Name.identifier("no_name_in_PSI_3d19d79d_1ba9_4cd0_b7f5_b46aa3cd5d40");
|
||||
|
||||
public static final String ANONYMOUS = "<anonymous>";
|
||||
public static final Name ANONYMOUS_FUNCTION = Name.special(ANONYMOUS);
|
||||
|
||||
@NotNull
|
||||
public static Name safeIdentifier(@Nullable Name name) {
|
||||
return name != null && !name.isSpecial() ? name : SAFE_IDENTIFIER_FOR_NO_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Name safeIdentifier(@Nullable String name) {
|
||||
return safeIdentifier(name == null ? null : Name.identifier(name));
|
||||
}
|
||||
|
||||
public static boolean isSafeIdentifier(@NotNull Name name) {
|
||||
return !name.asString().isEmpty() && !name.isSpecial();
|
||||
}
|
||||
|
||||
private SpecialNames() {}
|
||||
}
|
||||
Reference in New Issue
Block a user