[FE] Convert ClassId.java to Kotlin

This commit is contained in:
Dmitriy Novozhilov
2023-09-19 12:37:41 +03:00
committed by Space Team
parent a3bcac00e4
commit a43cb721ba
10 changed files with 103 additions and 149 deletions
@@ -68,7 +68,7 @@ class FirExtensionDeclarationsSymbolProvider private constructor(
cachesFactory.createLazyValue { cachesFactory.createLazyValue {
computeNamesGroupedByPackage( computeNamesGroupedByPackage(
FirDeclarationGenerationExtension::getTopLevelClassIds, FirDeclarationGenerationExtension::getTopLevelClassIds,
ClassId::getPackageFqName ClassId::packageFqName
) { it.shortClassName.asString() } ) { it.shortClassName.asString() }
} }
@@ -31,7 +31,7 @@ class KotlinOnlyClasspathSnapshotterTest : ClasspathSnapshotTestCommon() {
fun testSimpleClass() { fun testSimpleClass() {
val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.kt") val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.kt")
val actualSnapshot = sourceFile.compileAndSnapshot().toGson() val actualSnapshot = sourceFile.compileAndSnapshot().toGson()
val expectedSnapshot = sourceFile.getExpectedSnapshotFile().readText() val expectedSnapshot = sourceFile.getExpectedSnapshotText()
assertEquals(expectedSnapshot, actualSnapshot) assertEquals(expectedSnapshot, actualSnapshot)
@@ -55,7 +55,7 @@ class KotlinOnlyClasspathSnapshotterTest : ClasspathSnapshotTestCommon() {
val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.kt") val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.kt")
val classFile = sourceFile.compileSingle() val classFile = sourceFile.compileSingle()
val actualSnapshot = classFile.snapshot(ClassSnapshotGranularity.CLASS_LEVEL).toGson() val actualSnapshot = classFile.snapshot(ClassSnapshotGranularity.CLASS_LEVEL).toGson()
val expectedSnapshot = sourceFile.getExpectedSnapshotFile(ClassSnapshotGranularity.CLASS_LEVEL).readText() val expectedSnapshot = sourceFile.getExpectedSnapshotText(ClassSnapshotGranularity.CLASS_LEVEL)
assertEquals(expectedSnapshot, actualSnapshot) assertEquals(expectedSnapshot, actualSnapshot)
@@ -103,7 +103,7 @@ class JavaOnlyClasspathSnapshotterTest : ClasspathSnapshotTestCommon() {
fun testSimpleClass() { fun testSimpleClass() {
val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.java") val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.java")
val actualSnapshot = sourceFile.compileAndSnapshot().toGson() val actualSnapshot = sourceFile.compileAndSnapshot().toGson()
val expectedSnapshot = sourceFile.getExpectedSnapshotFile().readText() val expectedSnapshot = sourceFile.getExpectedSnapshotText()
assertEquals(expectedSnapshot, actualSnapshot) assertEquals(expectedSnapshot, actualSnapshot)
@@ -126,7 +126,7 @@ class JavaOnlyClasspathSnapshotterTest : ClasspathSnapshotTestCommon() {
val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.java") val sourceFile = getSourceFile("testSimpleClass", "com/example/SimpleClass.java")
val classFile = sourceFile.compileSingle() val classFile = sourceFile.compileSingle()
val actualSnapshot = classFile.snapshot(ClassSnapshotGranularity.CLASS_LEVEL).toGson() val actualSnapshot = classFile.snapshot(ClassSnapshotGranularity.CLASS_LEVEL).toGson()
val expectedSnapshot = sourceFile.getExpectedSnapshotFile(ClassSnapshotGranularity.CLASS_LEVEL).readText() val expectedSnapshot = sourceFile.getExpectedSnapshotText(ClassSnapshotGranularity.CLASS_LEVEL)
assertEquals(expectedSnapshot, actualSnapshot) assertEquals(expectedSnapshot, actualSnapshot)
@@ -135,10 +135,10 @@ class JavaOnlyClasspathSnapshotterTest : ClasspathSnapshotTestCommon() {
} }
} }
private fun TestSourceFile.getExpectedSnapshotFile(granularity: ClassSnapshotGranularity? = null): File { private fun TestSourceFile.getExpectedSnapshotText(granularity: ClassSnapshotGranularity? = null): String {
val relativePath = sourceFile.unixStyleRelativePath.substringBeforeLast(".") + ".json" val relativePath = sourceFile.unixStyleRelativePath.substringBeforeLast(".") + ".json"
val expectedSnapshotDirName = if (granularity == null) "expected-snapshot" else "expected-snapshot-${granularity.name}" val expectedSnapshotDirName = if (granularity == null) "expected-snapshot" else "expected-snapshot-${granularity.name}"
return sourceFile.baseDir.resolve("../$expectedSnapshotDirName/$relativePath") return sourceFile.baseDir.resolve("../$expectedSnapshotDirName/$relativePath").readText().trimEnd()
} }
private fun String.assertContains(vararg elements: String) { private fun String.assertContains(vararg elements: String) {
@@ -10,7 +10,7 @@
"fqName": "SimpleClass" "fqName": "SimpleClass"
} }
}, },
"local": false "isLocal": false
}, },
"classAbiHash": -6515999856905133685, "classAbiHash": -6515999856905133685,
"supertypes": [ "supertypes": [
@@ -18,4 +18,4 @@
"internalName": "java/lang/Object" "internalName": "java/lang/Object"
} }
] ]
} }
@@ -10,7 +10,7 @@
"fqName": "SimpleClass" "fqName": "SimpleClass"
} }
}, },
"local": false "isLocal": false
}, },
"classAbiHash": 2881075740228300324, "classAbiHash": 2881075740228300324,
"classMemberLevelSnapshot": { "classMemberLevelSnapshot": {
@@ -40,4 +40,4 @@
"internalName": "java/lang/Object" "internalName": "java/lang/Object"
} }
] ]
} }
@@ -10,7 +10,7 @@
"fqName": "SimpleClass" "fqName": "SimpleClass"
} }
}, },
"local": false "isLocal": false
}, },
"classAbiHash": 8283317449409255124, "classAbiHash": 8283317449409255124,
"supertypes": [ "supertypes": [
@@ -18,4 +18,4 @@
"internalName": "java/lang/Object" "internalName": "java/lang/Object"
} }
] ]
} }
@@ -10,7 +10,7 @@
"fqName": "SimpleClass" "fqName": "SimpleClass"
} }
}, },
"local": false "isLocal": false
}, },
"classAbiHash": 8283317449409255124, "classAbiHash": 8283317449409255124,
"classMemberLevelSnapshot": { "classMemberLevelSnapshot": {
@@ -25,7 +25,7 @@
"fqName": "SimpleClass" "fqName": "SimpleClass"
} }
}, },
"local": false "isLocal": false
}, },
"classKind": "CLASS", "classKind": "CLASS",
"classHeaderData": [ "classHeaderData": [
@@ -74,4 +74,4 @@
"internalName": "java/lang/Object" "internalName": "java/lang/Object"
} }
] ]
} }
@@ -13,14 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.name
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. * A class name which is used to uniquely identify a Kotlin class.
@@ -31,145 +24,106 @@ import java.util.List;
* the package, separated by dollar signs. If a class is an inner of local, relativeClassName would consist of two names, * 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. * the second one being the class' short name.
*/ */
public final class ClassId { class ClassId(val packageFqName: FqName, relativeClassName: FqName, local: Boolean) {
@NotNull val relativeClassName: FqName
public static ClassId topLevel(@NotNull FqName topLevelFqName) { val isLocal: Boolean
return new ClassId(topLevelFqName.parent(), topLevelFqName.shortName());
init {
assert(!relativeClassName.isRoot) { "Class name must not be root: " + packageFqName + if (local) " (local)" else "" }
this.relativeClassName = relativeClassName
isLocal = local
} }
private final FqName packageFqName; constructor(packageFqName: FqName, topLevelName: Name) : this(packageFqName, FqName.topLevel(topLevelName), false)
private final FqName relativeClassName;
private final boolean local;
public ClassId(@NotNull FqName packageFqName, @NotNull FqName relativeClassName, boolean local) { val parentClassId: ClassId?
this.packageFqName = packageFqName; get() = if (!isNestedClass) null else ClassId(
assert !relativeClassName.isRoot() : packageFqName,
"Class name must not be root: " + packageFqName + (local ? " (local)" : ""); relativeClassName.parent(),
this.relativeClassName = relativeClassName; isLocal
this.local = local; )
val shortClassName: Name
get() = relativeClassName.shortName()
fun createNestedClassId(name: Name): ClassId {
return ClassId(packageFqName, relativeClassName.child(name), isLocal)
} }
public ClassId(@NotNull FqName packageFqName, @NotNull Name topLevelName) { val outerClassId: ClassId?
this(packageFqName, FqName.topLevel(topLevelName), false); get() {
} val parent = relativeClassName.parent()
return if (parent.isRoot) null else ClassId(packageFqName, parent, isLocal)
@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);
}
@NotNull
public ClassId getOutermostClassId() {
FqName name = relativeClassName;
while (!name.parent().isRoot()) name = name.parent();
return new ClassId(packageFqName, name, false);
}
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); val outermostClassId: ClassId
get() {
var name = relativeClassName
while (!name.parent().isRoot) name = name.parent()
return ClassId(packageFqName, name, false)
}
val isNestedClass: Boolean
get() = !relativeClassName.parent().isRoot
fun asSingleFqName(): FqName {
return if (packageFqName.isRoot) relativeClassName else FqName(packageFqName.asString() + "." + relativeClassName.asString())
}
fun startsWith(segment: Name): Boolean {
return packageFqName.startsWith(segment)
} }
/** /**
* @return a string where packages are delimited by '/' and classes by '.', e.g. "kotlin/Map.Entry" * @return a string where packages are delimited by '/' and classes by '.', e.g. "kotlin/Map.Entry"
*/ */
@NotNull fun asString(): String {
public String asString() { return if (packageFqName.isRoot) relativeClassName.asString() else packageFqName.asString()
if (packageFqName.isRoot()) return relativeClassName.asString(); .replace('.', '/') + "/" + relativeClassName.asString()
return packageFqName.asString().replace('.', '/') + "/" + relativeClassName.asString();
} }
@NotNull fun asFqNameString(): String {
public String asFqNameString() { return if (packageFqName.isRoot) relativeClassName.asString() else packageFqName.asString() + "." + relativeClassName.asString()
if (packageFqName.isRoot()) return relativeClassName.asString();
return packageFqName.asString() + "." + relativeClassName.asString();
} }
@Override override fun equals(o: Any?): Boolean {
public boolean equals(Object o) { if (this === o) return true
if (this == o) return true; if (o == null || javaClass != o.javaClass) return false
if (o == null || getClass() != o.getClass()) return false; val id = o as ClassId
return packageFqName == id.packageFqName && relativeClassName == id.relativeClassName && isLocal == id.isLocal
ClassId id = (ClassId) o;
return packageFqName.equals(id.packageFqName) &&
relativeClassName.equals(id.relativeClassName) &&
local == id.local;
} }
@Override override fun hashCode(): Int {
public int hashCode() { var result = packageFqName.hashCode()
int result = packageFqName.hashCode(); result = 31 * result + relativeClassName.hashCode()
result = 31 * result + relativeClassName.hashCode(); result = 31 * result + isLocal.hashCode()
result = 31 * result + Boolean.valueOf(local).hashCode(); return result
return result;
} }
@Override override fun toString(): String {
public String toString() { return if (packageFqName.isRoot) "/" + asString() else asString()
return packageFqName.isRoot() ? "/" + asString() : asString(); }
companion object {
@JvmStatic
fun topLevel(topLevelFqName: FqName): ClassId {
return ClassId(topLevelFqName.parent(), topLevelFqName.shortName())
}
/**
* @param string a string where packages are delimited by '/' and classes by '.', e.g. "kotlin/Map.Entry"
*/
@JvmOverloads
@JvmStatic
fun fromString(string: String, isLocal: Boolean = false): ClassId {
val lastSlashIndex = string.lastIndexOf("/")
val packageName: String
val className: String
if (lastSlashIndex == -1) {
packageName = ""
className = string
} else {
packageName = string.substring(0, lastSlashIndex).replace('/', '.')
className = string.substring(lastSlashIndex + 1)
}
return ClassId(FqName(packageName), FqName(className), isLocal)
}
} }
} }
@@ -54,7 +54,7 @@ fun ModuleDescriptor.findNonGenericClassAcrossDependencies(classId: ClassId, not
if (existingClass != null) return existingClass if (existingClass != null) return existingClass
// Take a list of N zeros, where N is the number of class names in the given ClassId // Take a list of N zeros, where N is the number of class names in the given ClassId
val typeParametersCount = generateSequence(classId, ClassId::getOuterClassId).map { 0 }.toList() val typeParametersCount = generateSequence(classId, ClassId::outerClassId).map { 0 }.toList()
return notFoundClasses.getClass(classId, typeParametersCount) return notFoundClasses.getClass(classId, typeParametersCount)
} }
@@ -15,7 +15,7 @@ import java.io.InputStream
class MetadataClassDataFinder(val finder: KotlinMetadataFinder) : ClassDataFinder { class MetadataClassDataFinder(val finder: KotlinMetadataFinder) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassData? { override fun findClassData(classId: ClassId): ClassData? {
val topLevelClassId = generateSequence(classId, ClassId::getOuterClassId).last() val topLevelClassId = generateSequence(classId, ClassId::outerClassId).last()
val stream = finder.findMetadata(topLevelClassId) ?: return null val stream = finder.findMetadata(topLevelClassId) ?: return null
val (message, nameResolver, version) = readProto(stream) val (message, nameResolver, version) = readProto(stream)
return message.class_List.firstOrNull { classProto -> return message.class_List.firstOrNull { classProto ->
@@ -41,4 +41,4 @@ fun readProto(stream: InputStream): Triple<ProtoBuf.PackageFragment, NameResolve
val message = ProtoBuf.PackageFragment.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry) val message = ProtoBuf.PackageFragment.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry)
val nameResolver = NameResolverImpl(message.strings, message.qualifiedNames) val nameResolver = NameResolverImpl(message.strings, message.qualifiedNames)
return Triple(message, nameResolver, version) return Triple(message, nameResolver, version)
} }
@@ -144,7 +144,7 @@ class TypeDeserializer(
fun notFoundClass(classIdIndex: Int): ClassDescriptor { fun notFoundClass(classIdIndex: Int): ClassDescriptor {
val classId = c.nameResolver.getClassId(classIdIndex) val classId = c.nameResolver.getClassId(classIdIndex)
val typeParametersCount = generateSequence(proto) { it.outerType(c.typeTable) }.map { it.argumentCount }.toMutableList() val typeParametersCount = generateSequence(proto) { it.outerType(c.typeTable) }.map { it.argumentCount }.toMutableList()
val classNestingLevel = generateSequence(classId, ClassId::getOuterClassId).count() val classNestingLevel = generateSequence(classId, ClassId::outerClassId).count()
while (typeParametersCount.size < classNestingLevel) { while (typeParametersCount.size < classNestingLevel) {
typeParametersCount.add(0) typeParametersCount.add(0)
} }