Skip to content

forEachDescendantOfType

inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline action: (T) -> Unit)

Applies action to this element and every descendant of type T, in post-order (children before parents).

inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline action: (T) -> Unit)

Applies action to this element and every descendant of type T, in post-order. canGoInside controls whether each visited element's children are traversed; the element itself is still passed to action when it is a T, even if canGoInside returns false for it.

Example:

Given outerClass representing:

class Outer {
    class Inner
}

The receiver participates in both traversal orders:

val postOrder = mutableListOf<String>()
outerClass.forEachDescendantOfType<KtClass> { postOrder += it.name.orEmpty() }
check(postOrder == listOf("Inner", "Outer"))

val preOrder = mutableListOf<String>()
outerClass.forEachDescendantOfTypeInPreorder<KtClass> { preOrder += it.name.orEmpty() }
check(preOrder == listOf("Outer", "Inner"))

Returning false from canGoInside prevents traversal into the element's children, but does not prevent the element itself from being passed to action:

val pruned = mutableListOf<String>()
outerClass.forEachDescendantOfType<KtClass>(
    canGoInside = { it !== outerClass },
    action = { pruned += it.name.orEmpty() },
)
check(pruned == listOf("Outer"))