Skip to content

KaExpressionInformationProvider

@SubclassOptInRequired(markerClass = [KaSessionComponentImplementationDetail::class])
interface KaExpressionInformationProvider : KaSessionComponent

Inheritors

Properties

isStableForSmartCasting

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.

  • val properties without delegation or custom getters, accessed through a stable receiver and declared in the current module.

Unstable smart-cast sinks generally include:

  • Non-local var properties.

  • Delegated properties.

  • Properties with custom getters.

  • Properties from separately compiled modules.

  • open properties 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

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

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

computeMissingCases

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:

fun test() {
    when {
        true -> {}
        else -> {}
    }
}

isValid

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.