Skip to content

KtPsiUtil

open class KtPsiUtil

A collection of static helper methods for working with the Kotlin PSI.

The utilities here cover common low-level operations such as unwrapping parenthesized expressions (deparenthesize), inspecting names and identifiers, and testing structural properties of elements (for example, whether a declaration is local). This class is not instantiable.

Types

KtExpressionWrapper

An element that wraps a base expression, such as a parenthesized or annotated expression.

Companion functions

ascendIfPropertyAccessor

open fun ascendIfPropertyAccessor(element: PsiElement): PsiElement

If element is a property accessor, returns its owning property; otherwise returns element unchanged.

checkVariableDeclarationInBlock

open fun checkVariableDeclarationInBlock(@NotNull block: KtBlockExpression, @NotNull varName: String): Boolean

Returns true if block contains a variable declaration named varName.

checkWhenExpressionHasSingleElse

open fun checkWhenExpressionHasSingleElse(@NotNull whenExpression: KtWhenExpression): Boolean

Returns true if whenExpression has exactly one else branch.

deparenthesize

@Nullable
open fun deparenthesize(@Nullable expression: KtExpression): KtExpression

Recursively unwraps parentheses, labels, and annotations from the given expression.

@Nullable
open fun deparenthesize(@Nullable expression: KtExpression, keepAnnotations: Boolean): KtExpression

Recursively unwraps parentheses and labels (and annotations unless keepAnnotations is true) from the given expression, returning the innermost wrapped expression.

deparenthesizeOnce

@Nullable
open fun deparenthesizeOnce(@Nullable expression: KtExpression): KtExpression

Unwraps a single layer of parentheses, label, or annotation from the given expression.

@Nullable
open fun deparenthesizeOnce(@Nullable expression: KtExpression, keepAnnotations: Boolean): KtExpression

Unwraps a single layer of parentheses or label (and annotation unless keepAnnotations is true) from the given expression.

findChildByType

@Nullable
open fun findChildByType(@NotNull element: PsiElement, @NotNull type: IElementType): PsiElement

Returns the first direct child of element with the given node type, or null if there is none.

findRootExpressions

@NotNull
open fun findRootExpressions(@NotNull unreachableElements: Collection<KtElement>): Set<KtElement>

Returns the subset of unreachableElements that are not contained within any other element of the set.

getClassIfParameterIsProperty

@Nullable
open fun getClassIfParameterIsProperty(@NotNull ktParameter: KtParameter): KtClassOrObject

If ktParameter is a primary-constructor val/var property parameter, returns the class or object that declares it; otherwise returns null.

getDirectParentOfTypeForBlock

@Nullable
open fun <T : PsiElement?> getDirectParentOfTypeForBlock(@NotNull block: KtBlockExpression, @NotNull aClass: Class<T>): T

Returns the enclosing element of type aClass for which block is a direct body (an if branch, a when entry, a lambda body, or a try/catch body), or null otherwise.

getEnclosingElementForLocalDeclaration

@Nullable
open fun getEnclosingElementForLocalDeclaration(@NotNull declaration: KtDeclaration): KtElement

Returns the innermost element that scopes declaration as a local declaration (a block, parameter, and so on), or null if the declaration is not local. See getEnclosingElementForLocalDeclaration with skipParameters.

@Nullable
open fun getEnclosingElementForLocalDeclaration(@NotNull declaration: KtDeclaration, skipParameters: Boolean): KtElement

Returns the innermost element that scopes declaration as a local declaration, or null if it is not local. When skipParameters is true, type and value parameters delegate to their owning declaration.

getExpressionOrLastStatementInBlock

@Nullable
open fun getExpressionOrLastStatementInBlock(@Nullable expression: KtExpression): KtExpression

Returns the last statement of expression if it is a block, otherwise expression itself.

getLastChildByType

@SafeVarargs
open fun <T : PsiElement?> getLastChildByType(@NotNull root: PsiElement, @NotNull elementTypes: Array<Class<out T>>): T

Returns the last direct child of root whose type is one of elementTypes, or null if there is none.

getLastElementDeparenthesized

@Nullable
open fun getLastElementDeparenthesized(@Nullable expression: KtExpression, @NotNull statementFilter: StatementFilter): KtExpression

Deparenthesizes expression and, if it is a block, recurses into the block's last statement (respecting statementFilter), returning the innermost "result" expression.

getLastReference

@Nullable
open fun getLastReference(@NotNull importedReference: KtExpression): KtSimpleNameExpression

Returns the last (rightmost) simple-name reference of the given qualified importedReference, or null.

getLastStatementInABlock

@Nullable
open fun getLastStatementInABlock(@Nullable blockExpression: KtBlockExpression): KtExpression

Returns the last statement of the given block, or null if the block is null or empty.

getNullableText

@Nullable
open fun getNullableText(@Nullable element: PsiElement): String

Returns the text of element, or null if element is null.

getOperationToken

@Nullable
open fun getOperationToken(@NotNull expression: KtOperationExpression): KtToken

Returns the operation token of expression (for example, PLUS), or null if unavailable.

getOutermostClassOrObject

@NotNull
open fun getOutermostClassOrObject(@NotNull classOrObject: KtClassOrObject): KtClassOrObject

Returns the outermost class that lexically encloses (and includes) the given class.

Starting from classOrObject, this repeatedly ascends to the enclosing class and returns the last one reached — the top of the class-nesting chain.

The walk stops as soon as a declaration has no enclosing class; in particular:

  • a top-level class is returned unchanged;
  • a nested or inner class resolves to the top-level class that contains it;
  • a local class (declared inside a code block) is returned unchanged, and the walk never crosses out of a local class into its surrounding block — so a class nested inside a local class resolves to that local class rather than to any top-level declaration. Note: a class declared inside a companion { } block (which is invalid code) is treated as nested directly in the class that owns the block. Example:
class Top {
    class Nested

    fun build() {
        class Local {
            inner class InsideLocal
        }
    }
}

For these declarations, getOutermostClassOrObject(nested) returns top, while calls for local and insideLocal both return local. The search does not cross the local-class boundary.

Return

the outermost enclosing class; never null — at minimum classOrObject itself

Parameters

  • classOrObject: the class to start the search from

getOutermostDescendantElement

@Nullable
open fun getOutermostDescendantElement(
    @Nullable root: PsiElement, 
    first: Boolean, 
    @NotNull predicate: Predicate<KtElement>
): KtElement

Traverses root and its subtree, collecting the outermost elements that satisfy predicate without descending into a match. Returns the first or last match in depth-first traversal order, as selected by first, or null if there is none. If root matches, it is the only result.

Example:

class First {
    class Nested
}
class Second

Given the containing file, the following searches return First and Second, respectively:

KtElement firstClass = getOutermostDescendantElement(file, true, element -> element instanceof KtClass);
KtElement lastClass = getOutermostDescendantElement(file, false, element -> element instanceof KtClass);

Nested is not considered because the traversal does not descend into First after it matches.

getOutermostParent

@Nullable
open fun getOutermostParent(
    @NotNull element: PsiElement, 
    @NotNull upperBound: PsiElement, 
    strict: Boolean
): PsiElement

Returns the outermost ancestor of element that is still a direct child of upperBound, or null. When strict is false, element itself is considered.

getPackageName

@Nullable
open fun getPackageName(@NotNull element: KtElement): String

Returns the dot-separated package name of the file containing element, or null if unavailable.

getParentCallIfPresent

@Nullable
open fun getParentCallIfPresent(@NotNull expression: KtExpression): KtExpression

Returns the nearest enclosing call-like expression that expression is an operand or argument of, looking through parentheses, casts, argument lists, lambdas, and labels, or null if there is none.

Example:

consume((value as String))
consume(left + right)

For the first statement, calling this method on the value expression returns the consume(...) call because casts and parentheses are skipped. For the second statement, calling it on left returns the nearer binary expression left + right rather than the outer consume(...) call.

getPreviousWord

@Nullable
open fun getPreviousWord(@NotNull element: PsiElement, @NotNull word: String): PsiElement

Returns the previous leaf if it is the identifier word (skipping whitespace and comments), or null.

getScript

@Nullable
open fun getScript(@NotNull namedDeclaration: KtDeclaration): KtScript

Returns the script this declaration is a top-level member of, or null if it is not in a script.

getText

@NotNull
open fun getText(@Nullable element: PsiElement): String

Returns the text of element, or an empty string if element is null.

getTopmostParentOfTypes

@Nullable
@SafeVarargs
@Contract(value = "null, _ -> null")
open fun getTopmostParentOfTypes(@Nullable element: PsiElement, @NotNull parentTypes: Array<Class<out PsiElement>>): PsiElement

Returns the topmost ancestor of element (or the enclosing file) whose type is one of parentTypes, or null if there is none.

isAbstract

open fun isAbstract(@NotNull declaration: KtDeclarationWithBody): Boolean

Returns true if declaration has no body expression. This is a syntactic check; it does not inspect the abstract modifier or determine whether the declaration is semantically abstract.

isAssignment

open fun isAssignment(@NotNull element: PsiElement): Boolean

Returns true if element is an assignment (= or an augmented assignment such as +=).

isBooleanConstant

open fun isBooleanConstant(@Nullable condition: KtExpression): Boolean

Returns true if condition is a boolean literal (true or false).

isCast

open fun isCast(@NotNull expression: KtBinaryExpressionWithTypeRHS): Boolean

Returns true if expression is a cast, whether safe (as?) or unsafe (as).

isDeprecated

open fun isDeprecated(@NotNull owner: KtModifierListOwner): Boolean

Returns true if owner is syntactically annotated with @Deprecated (by short name only).

isFalseConstant

open fun isFalseConstant(@Nullable condition: KtExpression): Boolean

Returns true if condition is the boolean literal false.

isInComment

open fun isInComment(element: PsiElement): Boolean

Returns true if element is a comment or is inside a KDoc comment.

isComment does not recognize elements inside a comment. KDoc tokens cannot be added to the general comment token set because the parser ignores every token in that set.

isInOrNotInOperation

open fun isInOrNotInOperation(@NotNull binaryExpression: KtBinaryExpression): Boolean

Returns true if binaryExpression is an in or !in membership check.

isLabeledFunctionLiteral

open fun isLabeledFunctionLiteral(@NotNull functionLiteral: KtFunctionLiteral): Boolean

Returns true if functionLiteral's enclosing lambda expression carries a label.

isLabelIdentifierExpression

open fun isLabelIdentifierExpression(element: PsiElement): Boolean

Returns true if element is a label reference expression.

isLHSOfDot

open fun isLHSOfDot(@NotNull expression: KtExpression): Boolean

Returns true if expression is on the left-hand side (the receiver) of a qualified ./?. expression.

isLocal

open fun isLocal(@NotNull declaration: KtDeclaration): Boolean

Returns true if declaration is local (declared inside a function body or other local scope).

isNotInOperation

open fun isNotInOperation(@NotNull binaryExpression: KtBinaryExpression): Boolean

Returns true if binaryExpression is a !in (not-in) membership check.

isNullConstant

open fun isNullConstant(@NotNull expression: KtExpression): Boolean

Returns true if expression (after deparenthesizing) is the null literal.

isOrdinaryAssignment

open fun isOrdinaryAssignment(@NotNull element: PsiElement): Boolean

Returns true if element is a plain assignment (=), excluding augmented assignments.

isRemovableVariableDeclaration

open fun isRemovableVariableDeclaration(@NotNull declaration: KtDeclaration): Boolean

Returns true if declaration has a PSI form supported by unused-variable cleanup: a property can be removed and a destructuring entry can be replaced with _. This is a syntactic classification; it does not determine whether the declaration is unused or whether removing it preserves behavior.

isSafeCast

open fun isSafeCast(@NotNull expression: KtBinaryExpressionWithTypeRHS): Boolean

Returns true if expression is a safe cast (as?).

isScriptDeclaration

open fun isScriptDeclaration(@NotNull namedDeclaration: KtDeclaration): Boolean

Returns true if namedDeclaration is a top-level declaration of a script.

isSelectorInQualified

open fun isSelectorInQualified(@NotNull nameExpression: KtSimpleNameExpression): Boolean

Returns true if nameExpression is the selector of a qualified expression or qualified user type.

isStatement

open fun isStatement(@NotNull element: PsiElement): Boolean

Returns true if element appears in a statement position (its parent is a statement container).

isStatementContainer

open fun isStatementContainer(@Nullable container: PsiElement): Boolean

Returns true if container is an element whose children are statements (a block, control-structure body, or when entry).

isTrait

open fun isTrait(@NotNull classOrObject: KtClassOrObject): Boolean

Returns true if classOrObject is an interface.

isTrueConstant

open fun isTrueConstant(@Nullable condition: KtExpression): Boolean

Returns true if condition is the boolean literal true.

isUnsafeCast

open fun isUnsafeCast(@NotNull expression: KtBinaryExpressionWithTypeRHS): Boolean

Returns true if expression is an unsafe cast (as).

prevLeafIgnoringWhitespaceAndComments

@Nullable
open fun prevLeafIgnoringWhitespaceAndComments(@NotNull element: PsiElement): PsiElement

Returns the previous leaf before element, skipping whitespace and comments, or null.

safeDeparenthesize

@NotNull
open fun safeDeparenthesize(@NotNull expression: KtExpression): KtExpression

@NotNull
open fun safeDeparenthesize(@NotNull expression: KtExpression, keepAnnotations: Boolean): KtExpression

Like deparenthesize, but returns expression itself if there is nothing to unwrap.

safeName

@NotNull
open fun safeName(@Nullable name: String): Name

Returns name as a Name, or the special "no name provided" name if name is null.

skipSiblingsBackwardByPredicate

@Nullable
open fun skipSiblingsBackwardByPredicate(@Nullable element: PsiElement, elementsToSkip: Predicate<PsiElement>): PsiElement

Returns the first preceding sibling of element not matched by elementsToSkip, or null.

skipTrailingWhitespacesAndComments

@Nullable
open fun skipTrailingWhitespacesAndComments(@Nullable element: PsiElement): PsiElement

Returns the first following sibling of element that is neither whitespace nor a comment, or null.

unquoteIdentifier

@NotNull
open fun unquoteIdentifier(@NotNull quoted: String): String

Removes surrounding backticks from a backtick-quoted identifier, returning quoted unchanged if it has none.

unquoteIdentifierOrFieldReference

@NotNull
open fun unquoteIdentifierOrFieldReference(@NotNull quoted: String): String

Like unquoteIdentifier, but also handles a leading $ field-reference prefix.

visitChildren

open fun <D> visitChildren(
    @NotNull element: KtElement, 
    @NotNull visitor: KtVisitor<Void, D>, 
    data: D
)

Dispatches each direct KtElement child of the given element to the visitor.