KaExpressionInformationProvider¶
@SubclassOptInRequired(markerClass = [KaSessionComponentImplementationDetail::class])
interface KaExpressionInformationProvider : KaSessionComponent
Inheritors¶
Properties¶
isStableForSmartCasting¶
abstract val KtExpression.isStableForSmartCasting: Boolean
Whether this expression can be used as a stable smart-cast sink at the current program point.
Stability is only one prerequisite for applying a smart cast. A true result does not mean that the expression is currently smart-cast to a more specific type. It only means that data-flow facts about this expression may be applied if such facts are available.
This property is meaningful for expressions that can be represented as data-flow variables, such as local variables, parameters, receivers, and property accesses. It returns false for expressions that are not smart-cast sinks, such as literals, function calls, and other types of expressions.
Stable smart-cast sinks generally include:
-
Local
vals, value parameters, and stable receivers. -
Local
vars that the compiler can treat as effectively immutable at this program point. -
valproperties without delegation or custom getters, accessed through a stable receiver and declared in the current module.
Unstable smart-cast sinks generally include:
-
Non-local
varproperties. -
Delegated properties.
-
Properties with custom getters.
-
Properties from separately compiled modules.
-
openproperties whose receiver is not known to have a final type. -
Local
vars whose captured writes may invalidate the relevant data-flow facts.
See the Kotlin specification section on smart cast sink stability.
Example
class Container(val value: Any?)
open class OpenContainer(open val value: Any?)
fun source(): Any? = ""
fun test(container: Container, openContainer: OpenContainer) {
val local: Any? = ""
var mutableLocal: Any? = ""
mutableLocal = "tracked assignment"
// local.isStableForSmartCasting == true
// mutableLocal.isStableForSmartCasting == true
// container.value.isStableForSmartCasting == true
// openContainer.value.isStableForSmartCasting == false
// source().isStableForSmartCasting == false
}
isUsedAsExpression¶
abstract val KtExpression.isUsedAsExpression: Boolean
Whether the value of the given KtExpression is used. In other words, true if the value of the expression is not safe to discard.
isUsedAsExpression performs a conservative check instead of exhaustive control-flow analysis. For example, x in the following example is possibly used, even though the value is never consumed at runtime: x + try { throw Exception() } finally { return }.
Example
In the following examples, x is used as a value (x.isUsedAsExpression == true):
-
if (x) { ... } else { ... } -
val a = x -
x + 8 -
when (x) { 1 -> ...; else -> ... }
In these expressions, x is not used as a value (x.isUsedAsExpression == false)
-
run { x; println(50) } -
when (x) { else -> ... }
isUsedAsResultOfLambda¶
abstract val KtExpression.isUsedAsResultOfLambda: Boolean
Whether the value of the given KtExpression is used as the resulting expression of some lambda block.
Note that isUsedAsResultOfLambda performs a conservative check instead of exhaustive control-flow analysis and isUsedAsResultOfLambda being true doesn't imply that the containing lambda itself is used.
It's also vital to not confuse lambda expressions with regular scope blocks (like if branches).
Example
In the following examples, x is used as a result of a lambda (x.isUsedAsResultOfLambda == true):
-
{ x -> println(0); x } -
{ { x }; 5 }
In these expressions, x is not used as a result of a lambda (x.isUsedAsResultOfLambda == false)
-
{ x -> println(0); x + 1 } -
{ x; println(50) } -
{ if (true) { x } else { x } } -
fun(x: Int) = x
token¶
abstract val token: KaLifetimeToken
The KaLifetimeToken which determines the lifetime of the lifetime owner.
Functions¶
assertIsValidAndAccessible¶
inline fun KaLifetimeOwner.assertIsValidAndAccessible()
computeMissingCases¶
abstract fun KtWhenExpression.computeMissingCases(): List<KaWhenMissingCase>
Computes the missing cases of the given KtWhenExpression.
The computed missing cases are not affected by the existence or absence of an else branch.
Example
In the following code, Direction.WEST and Direction.EAST are missing branches:
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
foo = when(direction) {
Direction.NORTH -> 1
Direction.SOUTH -> 2
else -> 3
}
If the KtWhenExpression has no subject, then the else is reported as missing even if it is explicitly present:
isValid¶
fun KaLifetimeOwner.isValid(): Boolean
Whether the lifetime owner is still valid, i.e. we are still in the scope of the lifetime owner's regular lifetime.
withValidityAssertion¶
inline fun <R> KaLifetimeOwner.withValidityAssertion(action: () -> R): R
Executes action only if the KaLifetimeOwner is still valid and accessible. Otherwise, throws a validity exception based on the concrete violation.