Optimize siblings()

This commit is contained in:
Ilya Ryzhenkov
2015-09-02 00:48:01 +03:00
parent 4ca127ecb3
commit 970bd46544
@@ -22,7 +22,7 @@ import com.intellij.psi.search.PsiSearchScopeUtil
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import java.util.ArrayList import java.util.*
// NOTE: in this file we collect only LANGUAGE INDEPENDENT methods working with PSI and not modifying it // NOTE: in this file we collect only LANGUAGE INDEPENDENT methods working with PSI and not modifying it
@@ -33,10 +33,28 @@ public val PsiElement.allChildren: PsiChildRange
val first = getFirstChild() val first = getFirstChild()
return if (first != null) PsiChildRange(first, getLastChild()) else PsiChildRange.EMPTY return if (first != null) PsiChildRange(first, getLastChild()) else PsiChildRange.EMPTY
} }
public fun PsiElement.siblings(forward: Boolean = true, withItself: Boolean = true): Sequence<PsiElement> { public fun PsiElement.siblings(forward: Boolean = true, withItself: Boolean = true): Sequence<PsiElement> {
val stepFun = if (forward) { e: PsiElement -> e.getNextSibling() } else { e: PsiElement -> e.getPrevSibling() } return object : Sequence<PsiElement> {
val sequence = sequence(this, stepFun) override fun iterator(): Iterator<PsiElement> {
return if (withItself) sequence else sequence.drop(1) var next: PsiElement? = this@siblings
return object : Iterator<PsiElement> {
init {
if (!withItself) next()
}
override fun hasNext(): Boolean = next != null
override fun next(): PsiElement {
val result = next ?: throw NoSuchElementException()
if (forward)
next = result.nextSibling
else
next = result.prevSibling
return result
}
}
}
}
} }
public val PsiElement.parentsWithSelf: Sequence<PsiElement> public val PsiElement.parentsWithSelf: Sequence<PsiElement>
@@ -67,14 +85,14 @@ public fun PsiElement.nextLeaf(filter: (PsiElement) -> Boolean): PsiElement? {
return leaf return leaf
} }
public fun PsiElement.getParentOfTypesAndPredicate<T: PsiElement>( public fun PsiElement.getParentOfTypesAndPredicate<T : PsiElement>(
strict : Boolean = false, vararg parentClasses : Class<T>, predicate: (T) -> Boolean strict: Boolean = false, vararg parentClasses: Class<T>, predicate: (T) -> Boolean
) : T? { ): T? {
var element = if (strict) getParent() else this var element = if (strict) getParent() else this
while (element != null) { while (element != null) {
@suppress("UNCHECKED_CAST") @suppress("UNCHECKED_CAST")
when { when {
(parentClasses.isEmpty() || parentClasses.any {parentClass -> parentClass.isInstance(element)}) && predicate(element!! as T) -> (parentClasses.isEmpty() || parentClasses.any { parentClass -> parentClass.isInstance(element) }) && predicate(element!! as T) ->
return element as T return element as T
element is PsiFile -> element is PsiFile ->
return null return null
@@ -86,27 +104,27 @@ public fun PsiElement.getParentOfTypesAndPredicate<T: PsiElement>(
return null return null
} }
public fun PsiElement.getNonStrictParentOfType<T: PsiElement>(parentClass : Class<T>) : T? { public fun PsiElement.getNonStrictParentOfType<T : PsiElement>(parentClass: Class<T>): T? {
return PsiTreeUtil.getParentOfType(this, parentClass, false) return PsiTreeUtil.getParentOfType(this, parentClass, false)
} }
inline public fun PsiElement.getParentOfType<reified T: PsiElement>(strict: Boolean): T? { inline public fun PsiElement.getParentOfType<reified T : PsiElement>(strict: Boolean): T? {
return PsiTreeUtil.getParentOfType(this, javaClass<T>(), strict) return PsiTreeUtil.getParentOfType(this, javaClass<T>(), strict)
} }
inline public fun PsiElement.getStrictParentOfType<reified T: PsiElement>(): T? { inline public fun PsiElement.getStrictParentOfType<reified T : PsiElement>(): T? {
return PsiTreeUtil.getParentOfType(this, javaClass<T>(), true) return PsiTreeUtil.getParentOfType(this, javaClass<T>(), true)
} }
inline public fun PsiElement.getNonStrictParentOfType<reified T: PsiElement>(): T? { inline public fun PsiElement.getNonStrictParentOfType<reified T : PsiElement>(): T? {
return PsiTreeUtil.getParentOfType(this, javaClass<T>(), false) return PsiTreeUtil.getParentOfType(this, javaClass<T>(), false)
} }
inline public fun PsiElement.getChildOfType<reified T: PsiElement>(): T? { inline public fun PsiElement.getChildOfType<reified T : PsiElement>(): T? {
return PsiTreeUtil.getChildOfType(this, javaClass<T>()) return PsiTreeUtil.getChildOfType(this, javaClass<T>())
} }
inline public fun PsiElement.getChildrenOfType<reified T: PsiElement>(): Array<T> { inline public fun PsiElement.getChildrenOfType<reified T : PsiElement>(): Array<T> {
return PsiTreeUtil.getChildrenOfType(this, javaClass<T>()) ?: arrayOf() return PsiTreeUtil.getChildrenOfType(this, javaClass<T>()) ?: arrayOf()
} }
@@ -118,11 +136,11 @@ public fun PsiElement?.isAncestor(element: PsiElement, strict: Boolean = false):
return PsiTreeUtil.isAncestor(this, element, strict) return PsiTreeUtil.isAncestor(this, element, strict)
} }
public fun <T: PsiElement> T.getIfChildIsInBranch(element: PsiElement, branch: T.() -> PsiElement?): T? { public fun <T : PsiElement> T.getIfChildIsInBranch(element: PsiElement, branch: T.() -> PsiElement?): T? {
return if (branch().isAncestor(element)) this else null return if (branch().isAncestor(element)) this else null
} }
public inline fun PsiElement.getParentOfTypeAndBranch<reified T: PsiElement>(strict: Boolean = false, noinline branch: T.() -> PsiElement?) : T? { public inline fun PsiElement.getParentOfTypeAndBranch<reified T : PsiElement>(strict: Boolean = false, noinline branch: T.() -> PsiElement?): T? {
return getParentOfType<T>(strict)?.getIfChildIsInBranch(this, branch) return getParentOfType<T>(strict)?.getIfChildIsInBranch(this, branch)
} }
@@ -136,11 +154,11 @@ public fun PsiElement.isInsideOf(elements: Iterable<PsiElement>): Boolean = elem
// -------------------- Recursive tree visiting -------------------------------------------------------------------------------------------- // -------------------- Recursive tree visiting --------------------------------------------------------------------------------------------
public inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline action: (T) -> Unit) { public inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline action: (T) -> Unit) {
forEachDescendantOfType<T>({true}, action) forEachDescendantOfType<T>({ true }, action)
} }
public inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) canGoInside: (PsiElement) -> Boolean, noinline action: (T) -> Unit) { public inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) canGoInside: (PsiElement) -> Boolean, noinline action: (T) -> Unit) {
this.accept(object : PsiRecursiveElementVisitor(){ this.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
if (canGoInside(element)) { if (canGoInside(element)) {
super.visitElement(element) super.visitElement(element)
@@ -162,12 +180,12 @@ public inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(inline
} }
public inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(noinline predicate: (T) -> Boolean = { true }): T? { public inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(noinline predicate: (T) -> Boolean = { true }): T? {
return findDescendantOfType<T>({ true}, predicate) return findDescendantOfType<T>({ true }, predicate)
} }
public inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): T? { public inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): T? {
var result: T? = null var result: T? = null
this.accept(object : PsiRecursiveElementVisitor(){ this.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
if (result != null) return if (result != null) return
@@ -291,5 +309,5 @@ public fun PsiElement.getTextWithLocation(): String = "'${this.getText()}' at ${
public fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element) public fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element)
public fun <E: PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> = public fun <E : PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> =
SmartPointerManager.getInstance(getProject()).createSmartPsiElementPointer(this) SmartPointerManager.getInstance(getProject()).createSmartPsiElementPointer(this)