[IR] Add documentation comments for IdSignatures
This commit is contained in:
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. It’s 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 can’t 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 it’s 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 member’s 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user