Skip to content

Commit

Permalink
Refactor firstParentOrNull to accept type parameter and optional pred…
Browse files Browse the repository at this point in the history
…icate (#2018)

* Refactor firstParentOrNull

* Fix error

* Review feedback
  • Loading branch information
KuechA authored Jan 31, 2025
1 parent eafa496 commit bc4d52b
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private fun Node?.toSarifMessage(): Message? {
* current function.
*/
private fun Node.toSarifCallStack(): List<Stack> {
val currentFunc = this.firstParentOrNull { it is FunctionDeclaration }
val currentFunc = this.firstParentOrNull<FunctionDeclaration>()
return listOf(
Stack(
message = Message(text = "Stack"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@ class ScopeManager : ScopeProvider {

/** The current block, according to the scope that is currently active. */
val currentBlock: Block?
get() =
currentScope?.astNode as? Block
?: currentScope?.astNode?.firstParentOrNull { it is Block } as? Block
get() = currentScope?.astNode as? Block ?: currentScope?.astNode?.firstParentOrNull<Block>()

/**
* The current method in the active scope tree, this ensures that 'this' keywords are mapped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1062,18 +1062,22 @@ val Node?.assigns: List<AssignExpression>
get() = this.allChildren()

/**
* This function tries to find the first parent node that satisfies the condition specified in
* [predicate]. It starts searching in [this], moving upwards using the [Node.astParent] attribute.
* This function tries to find the first parent node of type [T] that satisfies the optional
* condition specified in [predicate]. If [predicate] is `null`, the first AST parent node of type
* [T] is returned. It starts searching in [this], moving upwards using the [Node.astParent]
* attribute.
*
* @param predicate the search predicate
* @param predicate the optional search predicate
*/
fun Node.firstParentOrNull(predicate: (Node) -> Boolean): Node? {
inline fun <reified T : Node> Node.firstParentOrNull(
noinline predicate: ((T) -> Boolean)? = null
): T? {

// start at searchNodes parent
var node: Node? = this.astParent
var node = this.astParent

while (node != null) {
if (predicate(node)) {
if (node is T && (predicate == null || predicate(node))) {
return node
}

Expand All @@ -1085,15 +1089,20 @@ fun Node.firstParentOrNull(predicate: (Node) -> Boolean): Node? {
}

/**
* This function returns the first parent scope that matches the given [predicate]. If no parent
* scope matches the predicate, null is returned.
* This function tries to find the first parent scope of type [T] that satisfies the optional
* condition specified in [predicate]. If [predicate] is `null`, the first parent scope of type [T]
* is returned. It starts searching in [this], moving upwards using the [Scope.parent] attribute.
*
* If no parent scope matches the predicate, null is returned.
*
* @param predicate The predicate to match the parent scope against
* @param predicate The predicate optional to match the parent scope against
*/
fun Scope.firstScopeParentOrNull(predicate: (Scope) -> Boolean): Scope? {
inline fun <reified T : Scope> Scope.firstScopeParentOrNull(
noinline predicate: ((T) -> Boolean)? = null
): T? {
var scope = this.parent
while (scope != null) {
if (predicate(scope)) {
if (scope is T && (predicate == null || predicate(scope))) {
return scope
}

Expand Down Expand Up @@ -1272,7 +1281,7 @@ fun Expression?.unwrapReference(): Reference? {
/** Returns the [TranslationUnitDeclaration] where this node is located in. */
val Node.translationUnit: TranslationUnitDeclaration?
get() {
return firstParentOrNull { it is TranslationUnitDeclaration } as? TranslationUnitDeclaration
return firstParentOrNull<TranslationUnitDeclaration>()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,9 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
}
// Forwards all open and uncaught throwing nodes to the outer scope that may handle them
val outerCatchingNode =
node.firstParentOrNull { parent -> parent is TryStatement || parent is LoopStatement }
node.firstParentOrNull<Node> { parent ->
parent is TryStatement || parent is LoopStatement
}
if (outerCatchingNode != null) {
// Forwarding is done by merging the currently associated throws to a type with the new
// throws based on their type
Expand Down Expand Up @@ -1311,7 +1313,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
if (throwType != null) {
// Here, we identify the encapsulating ast node that can handle or relay a throw
val handlingOrRelayingParent =
throwExpression.firstParentOrNull { parent ->
throwExpression.firstParentOrNull<Node> { parent ->
parent is TryStatement || parent is FunctionDeclaration
}
if (handlingOrRelayingParent != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,8 +597,7 @@ class Inference internal constructor(val start: Node, override val ctx: Translat
}
is ReturnStatement -> {
// If this is part of a return statement, we can take the return type
val func =
hint.firstParentOrNull { it is FunctionDeclaration } as? FunctionDeclaration
val func = hint.firstParentOrNull<FunctionDeclaration>()
val returnTypes = func?.returnTypes

return if (returnTypes != null && returnTypes.size > 1) {
Expand Down

0 comments on commit bc4d52b

Please sign in to comment.