[IR] Add documentation comments for IdSignatures

This commit is contained in:
Sergej Jaskiewicz
2022-11-23 14:22:31 +01:00
committed by Space Team
parent 1fbc478833
commit 77e197d46a
@@ -11,8 +11,219 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.name.FqName
/**
* [IdSignature] is a unique key that corresponds to each Kotlin Declaration. It is used to reference declarations in klib.
* It has to be stable and unique. Its a bit similar to JVM signature but more Kotlin-specific.
*
* In general, distinguishable declarations in Kotlin have to have different signatures.
*
* Some way to look at klib could be a map of [IdSignature] as a key and [org.jetbrains.kotlin.ir.declarations.IrDeclaration] as a value.
*
* There is a bunch of existing signatures which are used to reference different kinds of declaration.
* Some of them may look weird because of some Kotlin specifics on one hand, and on the other hand, klib structure now is something similar
* to a russian doll, where an inner declaration is nested inside its parent (a member inside a class), so we need a way to figure out
* from a signature what the signature of its parent is. Moving to a flat structure could simplify signatures.
*
* One important definition needed is a *publicly-accessible declaration*, which means that there is a unique reference to a declaration `D`
* outside the file in which the declaration `D` is declared, and the declaration `D` could be navigated across different files
* (and modules) using that reference.
*
* ## Signature computation
* First, let's consider a top-level non-private class `C` in a package `foo.bar`:
* ```kotlin
* package foo.bar
* public class C<TP1, TP2> {
* fun qux() { ... }
* val p
* }
* ```
*
* The signatures of the class `C` and its type parameters `TPn` are going to be:
* ```
* CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C'
* hashCode = null
* flags = 0
* }
*
* CompositeSignature { // TP1
* container = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C'
* hashCode = null
* flags = 0
* }
* inner = LocalSignature {
* localFqn = '<TP>'
* hashCode = 0
* }
* }
*
* CompositeSignature { // TP2
* container = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C'
* hashCode = null
* flags = 0
* }
* inner = LocalSignature {
* localFqn = '<TP>'
* hashCode = 1
* }
* }
* ```
*
* The signature of the method `qux()` is:
* ```
* CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C.qux'
* hashCode = 0x..... // some hash code corresponding to the qux's signature
* flags = 0
* }
* ```
*
* The signature of the property `p` and the get-accessor of `p` are:
* ```
* CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C.p'
* hashCode = 0x..... // some hash code corresponding to the p's signature
* flags = 0
* }
*
* AccessorSignature {
* propertySignature = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C.p'
* hashCode = 0x..... // some hash code corresponding to the p's signature
* flags = 0
* }
* accessorSignature = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C.p.<get-p>'
* hashCode = 0x..... // some hash code corresponding to the p.get's signature
* flags = 0
* }
* }
*
* CompositeSignature {
* container = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'C.p'
* hashCode = 0x..... // some hash code corresponding to the p's signature
* flags = 0
* }
* inner = LocalSignature {
* localFqn = '<BF>'
* hashCode = null
* }
* }
* ```
*
* So, most of the cases are covered with [CommonSignature] and [AccessorSignature].
* Now let take a look into less trivial cases.
*
* ```kotlin
* // f1.kt
* package foo.bar
*
* private class P {
*
* }
*
* private fun qux() { ... }
*
* // f2.kt
* package foo.bar
*
* private fun qux() { ... }
*
* private class P {
*
* }
* ```
*
* Here the signatures of `P` and `qux()` in `f1.kt` are going to be:
* ```
* CompositeSignature {
* container = FileSignature {
* file = f1.kt
* }
* inner = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'P'
* hashCode = null
* flags = 0
* }
* }
*
*
* CompositeSignature {
* container = FileSignature {
* file = f1.kt
* }
* inner = CommonSignature {
* packageFqn = 'foo.bar'
* classFqn = 'qux'
* hashCode = 0x....
* flags = 0
* }
* }
* ```
*
* So, here we need a special factor `file` that allows us to distinguish signatures with the same FQN in different files.
* In a klib such file-private declarations cant be referenced from files other than the file where the private declaration is declared in.
*
* The last case is a local declaration:
* ```kotlin
* package foo.bar
* fun qux() {
* class L {
* fun meh() { .. }
* }
* }
* ```
*
* Here the signatures are going to be:
* ```
* CommonSignature { // qux()
* packageFqn = 'foo.bar'
* classFqn = 'qux'
* hashCode = 0x....
* flags = 0
* }
*
* FileLocalSignature { // class L
* container = CommonSignature { // qux()
* packageFqn = 'foo.bar'
* classFqn = 'qux'
* hashCode = 0x....
* flags = 0
* }
* id = 0
* }
*
* FileLocalSignature { // L.meh()
* container = FileLocalSignature { // class L
* container = CommonSignature { // qux()
* packageFqn = 'foo.bar'
* classFqn = 'qux'
* hashCode = 0x....
* flags = 0
* }
* id = 0
* }
* id = 0x123... // hash of L.meh() signature
* }
* ```
*/
sealed class IdSignature {
/**
* Used for some special kinds of declarations like `expect`, or synthetic Java accessors.
*/
enum class Flags(val recursive: Boolean) {
IS_EXPECT(true),
IS_JAVA_FOR_KOTLIN_OVERRIDE_PROPERTY(false),
@@ -24,7 +235,7 @@ sealed class IdSignature {
}
/**
* Means that signature has cross-module visibility. In other words referencing declaration could found in klib if property is `true`
* Whether the signature has cross-module visibility.
*/
abstract val isPubliclyVisible: Boolean
@@ -53,6 +264,9 @@ sealed class IdSignature {
override fun toString(): String =
"${if (isLocal) "local " else ""}${render()}"
/**
* This signature corresponds to a publicly accessible Kotlin declaration.
*/
class CommonSignature(val packageFqName: String, val declarationFqName: String, val id: Long?, val mask: Long) : IdSignature() {
override val isPubliclyVisible: Boolean get() = true
@@ -103,6 +317,9 @@ sealed class IdSignature {
override fun hashCode(): Int = hashCode
}
/**
* This signature is a container that contains 2 signatures ([container] and [inner] parts)
*/
class CompositeSignature(val container: IdSignature, val inner: IdSignature) : IdSignature() {
override val isPubliclyVisible: Boolean
get() = true
@@ -143,6 +360,15 @@ sealed class IdSignature {
}
/**
* This is a special signature to reference accessors of a property.
* It differs from [CommonSignature] because otherwise its not clear how to compute the container.
*
* TODO: Could be replaced with [CompositeSignature]
*
* @property propertySignature A signature of the property that this accessor corresponds to.
* @property accessorSignature A signature of the accessor function for the property.
*/
class AccessorSignature(val propertySignature: IdSignature, val accessorSignature: CommonSignature) : IdSignature() {
override val isPubliclyVisible: Boolean get() = true
@@ -167,6 +393,16 @@ sealed class IdSignature {
override fun hashCode(): Int = hashCode
}
/**
* Used to represent a file which is required in case of top-level private declarations.
* This signature is needed because 2 different top-level private declarations can have the same FQN.
*
* This signature is not navigatable through files.
*
* @property id A unique object to differentiate two file signatures with the same names. For example, an [IrFileSymbol].
* @property fqName The name of the package this file belongs to.
* @property fileName The name/path of the file entry.
*/
class FileSignature(
private val id: Any,
private val fqName: FqName,
@@ -205,6 +441,11 @@ sealed class IdSignature {
get() = false
}
/**
* This signature represents some internal part of a declaration, like a backing field or a type parameter.
*
* This signature is not navigatable through files.
*/
class LocalSignature(val localFqn: String, val hashSig: Long?, val description: String?) : IdSignature() {
override val isPubliclyVisible: Boolean
get() = false
@@ -251,23 +492,28 @@ sealed class IdSignature {
}
}
// KT-42020
// This special signature is required to disambiguate fake overrides 'foo(x: T)[T = String]' and 'foo(x: String)' in the code below:
//
// open class Base<T> {
// fun foo(x: T) {}
// fun foo(x: String) {}
// }
//
// class Derived : Base<String>()
//
// (NB similar clash is possible for generic member extension properties as well)
//
// For each fake override 'foo' we collect non-fake overrides overridden by 'foo'
// such that their value parameter types contain type parameters of 'Base',
// sorted by the fully-qualified name of the containing class.
//
// NB this special case of IdSignature is JVM-specific.
/**
* [KT-42020](https://youtrack.jetbrains.com/issue/KT-42020)
*
* This special signature is required to disambiguate fake overrides 'foo(x: T)[T = String]' and 'foo(x: String)' in the code below:
*
* ```kotlin
* open class Base<T> {
* fun foo(x: T) {}
* fun foo(x: String) {}
* }
*
* class Derived : Base<String>()
* ```
*
* NB: A similar clash is possible for generic member extension properties as well
*
* For each fake override `foo` we collect non-fake overrides overridden by `foo`
* such that their value parameter types contain type parameters of 'Base',
* sorted by the fully-qualified name of the containing class.
*
* NB: this special case of [IdSignature] is JVM-specific.
*/
class SpecialFakeOverrideSignature(
val memberSignature: IdSignature,
val overriddenSignatures: List<IdSignature>
@@ -307,6 +553,14 @@ sealed class IdSignature {
override fun hashCode(): Int = hashCode
}
/**
* A deprecated signature used for local classes and their members to make it possible to build fake overridden declarations for such
* local classes.
*
* This signature is not navigatable through files.
*
* @property id A hash of the members signature, not an ordered index, because it has to be stable.
*/
class FileLocalSignature(val container: IdSignature, val id: Long, val description: String? = null) : IdSignature() {
override val isPubliclyVisible: Boolean get() = false
@@ -338,7 +592,11 @@ sealed class IdSignature {
override fun hashCode(): Int = hashCode
}
// Used to reference local variable and value parameters in function
/**
* Used to reference local declarations like a variable, value parameters, or anonymous initializers.
*
* This signature is not navigatable through files.
*/
class ScopeLocalDeclaration(val id: Int, _description: String? = null) : IdSignature() {
val description: String = _description ?: "<no description>"
@@ -364,6 +622,9 @@ sealed class IdSignature {
override fun hashCode(): Int = id
}
/**
* A special signature to reference lowered declarations in PIR incremental cache.
*/
class LoweredDeclarationSignature(val original: IdSignature, val stage: Int, val index: Int) : IdSignature() {
override val isPubliclyVisible: Boolean get() = original.isPubliclyVisible