Skip to content

KaUsualClassType

KaUsualClassType represents a generic class type, such as String or List<Int>.

Constructors

KaUsualClassType

constructor()

Properties

abbreviation

The abbreviated type for this expanded KaType, or null if this type has not been expanded from an abbreviated type or the abbreviated type cannot be resolved.

An abbreviated type is a type alias application that has been expanded to some other Kotlin type. For example, if we have a type alias typealias MyString = String and its application MyString, String would be the type alias expansion and MyString its abbreviated type.

The abbreviated type contains the type arguments of a specific type alias application. For example, if we have a typealias MyList<A> = List<A>, for an application MyList<String>, MyList<String> would be the abbreviated type for such a type alias application, not simply MyList.

If this KaType is an unexpanded type alias application, abbreviation is null. Not all type alias applications are currently expanded right away and the Analysis API makes no guarantees about the specific circumstances.

While abbreviation is available for all KaTypes, it can currently only be present in KaClassTypes. However, abbreviated types are a general concept and if the type system changes (e.g. with denotable union/intersection types), other kinds of types may also be expanded from a type alias. This would allow more kinds of types to carry an abbreviated type.

The abbreviation itself is always a KaUsualClassType, as the application of a type alias is always a class type. It cannot be a KaClassErrorType because abbreviation would then be null.

Resolvability

Even when this KaType is an expansion, the abbreviated type may be null if it is not resolvable from this type's use-site module. This can occur when the abbreviated type from a module M1 was expanded at some declaration D in module M2, and the use-site module uses D, but only has a dependency on M2. Then the type alias of M1 remains unresolved and abbreviation is null.

Type arguments and nested abbreviated types

The type arguments of an abbreviated type are not converted to abbreviated types automatically. That is, if a type argument is a type expansion, its abbreviation doesn't automatically replace the expanded type. For example:

typealias MyString = String
typealias MyList<A> = List<A>

val list: MyList<MyString> = listOf()

MyList<MyString> may be expanded to a type List<String> with an abbreviated type MyList<String>, where String also has the abbreviated type MyString. The abbreviated type is not MyList<MyString>, although it might be rendered as such.

Transitive expansion

Types are always expanded to their final form. That is, if we have a chain of type alias expansions, the KaType only represents the final expanded type, and its abbreviation the initial type alias application. For example:

typealias Inner = String
typealias Outer = Inner

val outer: Outer = ""

Here, outer's type would be expanded to String, but its abbreviated type would be Outer. Inner would be lost.

abbreviationOrSelf

The KaType's abbreviated type, or the type itself if it doesn't have an abbreviated type.

A common pattern is to prefer the abbreviated type if it exists, and otherwise take the original type, for example to find the best target for navigation.

allSupertypes

context(session: KaSession)
fun KaType.allSupertypes(shouldApproximate: Boolean): Sequence<KaType>

Returns all supertypes of the given KaType. The resulting sequence is ordered by a breadth-first traversal of the class hierarchy, without duplicates.

Parameters

context(session: KaSession)
val KaType.allSupertypes: Sequence<KaType>

All supertypes of the given KaType. The resulting sequence is ordered by a breadth-first traversal of the class hierarchy, without duplicates.

Denotable types are not approximated.

annotations

A list of annotations applied to the annotated entity.

arrayElementType

context(session: KaSession)
val KaType.arrayElementType: KaType?

The array type's element type if the given KaType is a primitive type array or Array, and null otherwise.

augmentedByWarningLevelAnnotations

A KaType derived from the given type by enforcing warning-level nullability annotations. If the derived type doesn't differ from the original type, the original type is used.

In general, Java type enhancement allows the Kotlin compiler to infer a more specific nullability for a Java type based on its nullability annotations. Normally, only strict nullability annotations have an impact on a resolved type's nullability. These annotations are already taken into account in KaType.

However, there are also warning-level nullability annotations, such as Android's RecentlyNullable and RecentlyNonNull. These annotations have weaker constraints and don't affect a resolved type's nullability. augmentedByWarningLevelAnnotations is a KaType with weak annotations treated as strict ones.

See the list of default report levels for different nullability annotations in NULLABILITY_ANNOTATION_SETTINGS

Examples

classId

abstract val classId: ClassId

The ClassId of the class.

classId

context(session: KaSession)
val KaType.classId: ClassId?

The ClassId provided the type exposes any (it is the case for KaClassType).

defaultInitializer

context(session: KaSession)
val KaType.defaultInitializer: String?

The default initializer for the given KaType, or null if the type is neither nullable, a primitive, nor a string.

directSupertypes

context(session: KaSession)
fun KaType.directSupertypes(shouldApproximate: Boolean): Sequence<KaType>

Returns the direct supertypes of the given KaType.

For flexible types, direct supertypes of both the upper and lower bounds are returned. If that's not desirable, use directSupertypes on KaFlexibleType.upperBound or KaFlexibleType.lowerBound.

Example

Given MutableList<String>, directSupertypes returns List<String> and MutableCollection<String>

Parameters

  • shouldApproximate: Whether to approximate non-denotable types. For example, the supertype of List<out String> is Collection<CAPTURED out String>. With approximation set to true, Collection<out String> is returned instead.
context(session: KaSession)
val KaType.directSupertypes: Sequence<KaType>

The direct supertypes of the given KaType.

For flexible types, direct supertypes of both the upper and lower bounds are included. If that's not desirable, use directSupertypes on KaFlexibleType.upperBound or KaFlexibleType.lowerBound.

Denotable types are not approximated.

Example

Given MutableList<String>, directSupertypes contains List<String> and MutableCollection<String>

expandedSymbol

context(session: KaSession)
val KaType.expandedSymbol: KaClassSymbol?

The class symbol backing the given KaType, if available.

fullyExpandedType

context(session: KaSession)
val KaType.fullyExpandedType: KaType

The type that corresponds to the given KaType with fully expanded type aliases.

Type aliases are usually expanded immediately by the compiler, so most KaTypes should already present in their expanded forms. Nonetheless, it is possible to obtain unexpanded types from the Analysis API, and fullyExpandedType may be used to expand type aliases in such types.

Example

interface Base

typealias FirstAlias = @Anno1 Base
typealias SecondAlias = @Anno2 FirstAlias

fun foo(): @Anno3 SecondAlias = TODO()

The return type of foo() will be @Anno3 @Anno2 @Anno1 Base instead of @Anno3 SecondAlias

See also

functionTypeFamily

The function type family of the given KaType, or null if the type is not a function type.

For example, (Int) -> String belongs to the Function family, while suspend () -> Unit belongs to the SuspendFunction family.

See also

hasFlexibleNullability

Whether the KaType is a org.jetbrains.kotlin.analysis.api.types.KaFlexibleType / org.jetbrains.kotlin.analysis.api.types.KaDynamicType with flexible nullability or org.jetbrains.kotlin.analysis.api.types.KaErrorType with unknown nullability. Both safe and ordinary calls are valid on such types.

Note that a flexible / dynamic type has a flexible nullability when the lower bound is non-nullable and the upper bound is nullable. E.g. T! has T as the lower bound and T? as the upper bound, hence it has a flexible nullability.

isArrayOrPrimitiveArray

Whether the KaType is an array or a primitive array type.

isDenotable

context(session: KaSession)
val KaType.isDenotable: Boolean

Whether the KaType is denotable. A denotable type can be expressed in Kotlin code, as opposed to being only constructible via compiler type operations (such as type inference).

isFunctionalInterface

Whether the KaType is a functional interface type, such as Runnable. Such types are also known as SAM types.

isFunctionType

context(session: KaSession)
val KaType.isFunctionType: Boolean

Whether the KaType is a kotlin.Function type.

isKFunctionType

context(session: KaSession)
val KaType.isKFunctionType: Boolean

Whether the KaType is a kotlin.reflect.KFunction type.

isKSuspendFunctionType

Whether the KaType is a KSuspendFunction type.

isMarkedNullable

context(session: KaSession)
val KaType.isMarkedNullable: Boolean

Whether the KaType is explicitly marked as nullable, i.e., is represented as T?.

Note that this property just reflects the presence of nullability in the type signature, and sometimes isMarkedNullable being false doesn't imply that the given type cannot hold null or be assigned with it.

For example, isMarkedNullable doesn't expand type aliases to check the nullability of their underlying type:

typealias NonMarkedNullableAlias = String?

fun main() {
    val x: NonMarkedNullableAlias = null
}

The type of x is NonMarkedNullableAlias, which is not marked as nullable. However, it still represents a nullable type and can hold null and can be assigned with that.

To explicitly check whether a type can potentially hold null, use isNullable.

isNestedArray

context(session: KaSession)
val KaType.isNestedArray: Boolean

Whether the KaType is an array or a primitive array type, and its element is also an array type.

isNullable

context(session: KaSession)
val KaType.isNullable: Boolean

Whether a public value of the KaType can potentially be null.

If a type can be null, it means that this type is not a subtype of Any. However, it does not mean one can assign null to a variable of this type. It may be unknown whether this type can accept null.

Example

A public value of type T : Any? can potentially be null. But one cannot assign null to such a variable because the instantiated type may not be nullable.

isPrimitiveBacked

context(session: KaSession)
val KaType.isPrimitiveBacked: Boolean

Whether the given KaType is backed by a single JVM primitive type.

isSuspendFunctionType

Whether the KaType is a suspend function type.

qualifiers

The list of KaResolvedClassTypeQualifiers describing the segments of the class type.

See also

scope

context(session: KaSession)
val KaType.scope: KaTypeScope?

A KaTypeScope for the given KaType, or null if the type is erroneous. The scope includes all members which are callable on a given type. It also includes synthetic Java properties.

symbol

abstract val symbol: KaClassLikeSymbol

The class symbol which this class type is an instance of.

symbol

A KaClassLikeSymbol for this KaType if the type represents a uniquely resolvable class/object/type alias.

syntheticJavaPropertiesScope

A KaTypeScope containing the synthetic Java properties created for a given KaType.

token

abstract val token: KaLifetimeToken

The KaLifetimeToken which determines the lifetime of the lifetime owner.

typeArguments

The type arguments of the class type.

Type arguments should not be confused with the symbol's type parameters (for some subtypes of KaClassLikeSymbol).

Functions

approximateToDenotableSubtype

Approximates KaType to a denotable subtype.

The function returns null if the type is already denotable and does not need approximation. Otherwise, for a type T, returns a denotable type S such that S <: T, with all type arguments of S also being denotable.

approximateToDenotableSubtypeOrSelf

Approximates KaType to a denotable subtype, or returns the given type itself if it is already denotable.

See also

approximateToDenotableSupertype

context(session: KaSession)
fun KaType.approximateToDenotableSupertype(allowLocalDenotableTypes: Boolean): KaType?

Approximates KaType to a denotable supertype.

The function returns null if the type is already denotable and does not need approximation. Otherwise, for a type T, returns a denotable type S such that T <: S, with all type arguments of S also being denotable.

Parameters

  • allowLocalDenotableTypes: Whether locally declared types should be approximated to local supertypes instead of non-local ones. Local type approximation is sensible when the resulting KaType is analyzed in the same local context.
context(session: KaSession)
fun KaType.approximateToDenotableSupertype(position: KtElement): KaType?

Approximates KaType to a denotable supertype based on the given position.

This position is used when approximating local types. If the given type is local, then the function returns the first supertype, which is visible from the given position. Note that position is required to be within KaAnalysisScopeProvider.analysisScope, otherwise, an exception is thrown.

The function returns null if the type is already denotable and does not need approximation. Otherwise, for a type T, returns a denotable type S such that T <: S, with all type arguments of S also being denotable.

Example:

<position_1>
fun foo() {
    open class <position_2> A

    fun bar() = <expr>object: A() {}</expr>
}

In the example above we are trying to approximate the type of object: A() {} expression, which is a local type <anonymous>: A. When this type is approximated using <position_2> the function returns A, as this type is visible from this position. However, when approximating from <position_1>, the function returns Any, as A is not visible from this position, so the only option left is Any.

approximateToDenotableSupertypeOrSelf

context(session: KaSession)
fun KaType.approximateToDenotableSupertypeOrSelf(allowLocalDenotableTypes: Boolean): KaType

Approximates KaType to a denotable supertype, or returns the given type itself if it is already denotable.

See also

Approximates KaType to a denotable subtype based on the given position, or returns the given type itself if it is already denotable.

See also

asPsiType

context(session: KaSession)
fun KaType.asPsiType(
    useSitePosition: PsiElement, 
    allowErrorTypes: Boolean, 
    mode: KaTypeMappingMode = KaTypeMappingMode.DEFAULT, 
    isAnnotationMethod: Boolean = false, 
    suppressWildcards: Boolean? = null, 
    preserveAnnotations: Boolean = true, 
    allowNonJvmPlatforms: Boolean = false
): PsiType?

Converts the given KaType to a PsiType in the context of the useSitePosition.

assertIsValidAndAccessible

copy

Creates a copy of this KaUsualClassType with modifications applied via the init block.

createPointer

abstract override fun createPointer(): KaTypePointer<KaUsualClassType>

Creates a type pointer.

Unlike KaType, a KaTypePointer may be safely stored and passed around outside the (analyze)org.jetbrains.kotlin.analysis.api.session.analyze block. Use the KaSession.restore function to get the type instance back. Note that depending on the use-site session (analysisScope)KaSession.analysisScope, a type might not be restored.

hasCommonSubtypeWith

context(session: KaSession)
fun KaType.hasCommonSubtypeWith(that: KaType): Boolean

Checks whether this KaType is compatible with that other type. If they are compatible, the types can have a common subtype.

isSubtypeOf

context(session: KaSession)
fun KaType.isSubtypeOf(supertype: KaType): Boolean

Returns whether this KaType is a subtype of supertype. The relation is non-strict, i.e. any type t is a subtype of itself.

context(session: KaSession)
fun KaType.isSubtypeOf(supertype: KaType, errorTypePolicy: KaSubtypingErrorTypePolicy): Boolean

Returns whether this KaType is a subtype of supertype. The relation is non-strict, i.e. any type t is a subtype of itself.

The errorTypePolicy determines the treatment of error types in the subtyping check.

context(session: KaSession)
fun KaType.isSubtypeOf(classId: ClassId): Boolean

Returns whether this KaType is a subtype of a class called classId.

This function provides a convenient way to check if a class extends a certain base class or interface while disregarding type arguments. For example, one may check if this KaType is a subtype of StandardClassIds.Iterable.

See the overload taking a KaSubtypingErrorTypePolicy for the treatment of error types.

context(session: KaSession)
fun KaType.isSubtypeOf(classId: ClassId, errorTypePolicy: KaSubtypingErrorTypePolicy): Boolean

Returns whether this KaType is a subtype of a class called classId.

This function provides a convenient way to check if a class extends a certain base class or interface while disregarding type arguments. For example, one may check if this KaType is a subtype of StandardClassIds.Iterable.

The errorTypePolicy is applied as such: If this KaType is an error type, the LENIENT policy leads to a trivially true result. Errors in type arguments are not considered, as the subclass check is concerned with the applied class type and not its type arguments.

This function for ClassIds is a convenient dual to other isSubtypeOf functions. As such, its result is the same as a call to isSubtypeOf with the following right-hand KaType: a.b.Class<*, *, ...>? given a class ID a.b.Class with all type arguments instantiated to a star projection.

This has the following interesting implications:

  • If the classId points to or actualizes to a type alias, subclassing is checked for the expanded type, as other isSubtypeOf implementations also take expansion into account. If the type alias doesn't expand to a KaClassType, isSubtypeOf is trivially false.

  • If the classId cannot be resolved, it effectively means that we would have an "unresolved symbol" error KaType on the right-hand side of isSubtypeOf. Hence, with a LENIENT error type policy, isSubtypeOf is true for all unresolved class IDs.

context(session: KaSession)
fun KaType.isSubtypeOf(symbol: KaClassLikeSymbol): Boolean

Returns whether this KaType is a subtype of a class represented by symbol.

This function provides a convenient way to check if a class extends a certain base class or interface while disregarding type arguments.

See the overload taking a KaSubtypingErrorTypePolicy for the treatment of error types.

context(session: KaSession)
fun KaType.isSubtypeOf(symbol: KaClassLikeSymbol, errorTypePolicy: KaSubtypingErrorTypePolicy): Boolean

Returns whether this KaType is a subtype of a class represented by symbol.

This function provides a convenient way to check if a class extends a certain base class or interface while disregarding type arguments.

The errorTypePolicy is applied as such: If this KaType is an error type, the LENIENT policy leads to a trivially true result. Errors in type arguments are not considered, as the subclass check is concerned with the applied class type and not its type arguments.

This function for KaClassLikeSymbols is a convenient dual to other isSubtypeOf functions. As such, its result is the same as a call to isSubtypeOf with the following right-hand KaType: a.b.Class<*, *, ...>? given a class called a.b.Class with all type arguments instantiated to a star projection.

This has the following interesting implication: If the symbol points to or actualizes to a type alias, subclassing is checked for the expanded type, as other isSubtypeOf implementations also take expansion into account. If the type alias doesn't expand to a KaClassType, isSubtypeOf is trivially false.

isValid

Whether the lifetime owner is still valid, i.e. we are still in the scope of the lifetime owner's regular lifetime.

lowerBoundIfFlexible

context(session: KaSession)
fun KaType.lowerBoundIfFlexible(): KaType

Returns the KaFlexibleType's lower bound, or the type itself if it is not flexible.

mapToJvmTypeDescriptor

context(session: KaSession)
fun KaType.mapToJvmTypeDescriptor(): String

Convert the given KaType to a JVM type descriptor with the KaTypeMappingMode.DEFAULT. To learn more about JVM descriptors, check out the JVM specification.

render

context(session: KaSession)
fun KaType.render(position: Variance): String

Renders the given KaType into a string using the default rendering strategy (KaTypeRendererForSource.WITH_QUALIFIED_NAMES).

context(session: KaSession)
fun KaType.render(renderer: KaTypeRenderer, position: Variance): String

Renders the given KaType into a string. The particular rendering strategy is defined by the renderer.

semanticallyEquals

context(session: KaSession)
fun KaType.semanticallyEquals(other: KaType): Boolean

Returns whether this KaType is semantically equal to other.

Semantic equality stands in contrast to the structural equality implemented by KaType.equals. See KaType for a detailed discussion about structural vs. semantic type equality.

context(session: KaSession)
fun KaType.semanticallyEquals(other: KaType, errorTypePolicy: KaSubtypingErrorTypePolicy): Boolean

Returns whether this KaType is semantically equal to other.

Semantic equality stands in contrast to the structural equality implemented by KaType.equals. See KaType for a detailed discussion about structural vs. semantic type equality.

The errorTypePolicy determines the treatment of error types in the equality check.

upperBoundIfFlexible

context(session: KaSession)
fun KaType.upperBoundIfFlexible(): KaType

Returns the KaFlexibleType's upper bound, or the type itself if it is not flexible.

withNullability

context(session: KaSession)
fun KaType.withNullability(isMarkedNullable: Boolean): KaType

Creates a new KaType based on the given type with the updated nullability specified by isMarkedNullable.

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.