diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForStatementsCreator.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForStatementsCreator.scala index 040e4a9ffa12..badeda55e61a 100644 --- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForStatementsCreator.scala +++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForStatementsCreator.scala @@ -123,18 +123,21 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t private def astForTryStatement(tryStmt: ICPPASTTryBlockStatement): Ast = { val tryNode = controlStructureNode(tryStmt, ControlStructureTypes.TRY, "try") - val body = nullSafeAst(tryStmt.getTryBody, 1) - val catches = tryStmt.getCatchHandlers.zipWithIndex.map { case (h, index) => - astForCatchHandler(h, index + 2) - }.toIndexedSeq - Ast(tryNode).withChildren(body).withChildren(catches) + val bodyAst = nullSafeAst(tryStmt.getTryBody) match { + case Nil => Ast() + case elem :: Nil => elem + case elements => + setArgumentIndices(elements) + blockAst(blockNode(tryStmt.getTryBody)).withChildren(elements) + } + val catchAsts = tryStmt.getCatchHandlers.toSeq.map(astForCatchHandler) + tryCatchAst(tryNode, bodyAst, catchAsts, None) } - private def astForCatchHandler(catchHandler: ICPPASTCatchHandler, argIndex: Int): Ast = { - val catchNode = - controlStructureNode(catchHandler, ControlStructureTypes.CATCH, "catch").order(argIndex).argumentIndex(argIndex) - val declAst = nullSafeAst(catchHandler.getDeclaration) - val bodyAst = nullSafeAst(catchHandler.getCatchBody) + private def astForCatchHandler(catchHandler: ICPPASTCatchHandler): Ast = { + val catchNode = controlStructureNode(catchHandler, ControlStructureTypes.CATCH, "catch") + val declAst = nullSafeAst(catchHandler.getDeclaration) + val bodyAst = nullSafeAst(catchHandler.getCatchBody) Ast(catchNode).withChildren(declAst).withChildren(bodyAst) } diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForStatementsCreator.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForStatementsCreator.scala index 2a12381aeee3..cf2de044a993 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForStatementsCreator.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForStatementsCreator.scala @@ -12,7 +12,6 @@ import io.shiftleft.codepropertygraph.generated.nodes.NewControlStructure import io.shiftleft.codepropertygraph.generated.nodes.NewIdentifier import scala.:: -import scala.util.Success import scala.util.Try trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { this: AstCreator => @@ -244,11 +243,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForTryStatement(tryStmt: DotNetNodeInfo): Seq[Ast] = { - val tryNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.TRY) - .code(code(tryStmt)) - .lineNumber(line(tryStmt)) - .columnNumber(column(tryStmt)) + val tryNode = controlStructureNode(tryStmt, ControlStructureTypes.TRY, code(tryStmt)) val tryBlockNodeInfo = createDotNetNodeInfo(tryStmt.json(ParserKeys.Block)) val tryAst = astForBlock(tryBlockNodeInfo, Option(code(tryBlockNodeInfo))) @@ -256,31 +251,21 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t .map(_.arr.toSeq) .map { c => c.map { value => - val nodeInfo = createDotNetNodeInfo(value) - val catchNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.CATCH) - .code(code(nodeInfo)) - .lineNumber(line(nodeInfo)) - .columnNumber(column(nodeInfo)) - val children = astForNode(nodeInfo) + val nodeInfo = createDotNetNodeInfo(value) + val catchNode = controlStructureNode(nodeInfo, ControlStructureTypes.CATCH, code(nodeInfo)) + val children = astForNode(nodeInfo) Ast(catchNode).withChildren(children) } } .getOrElse(Seq.empty) - val finallyAst = Try(createDotNetNodeInfo(tryStmt.json(ParserKeys.Finally))) match { - case Success(finallyNodeInfo) => - val finallyNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.FINALLY) - .code(code(finallyNodeInfo)) - .lineNumber(line(finallyNodeInfo)) - .columnNumber(column(finallyNodeInfo)) - val finallyClauseAst = astForFinallyClause(finallyNodeInfo) - Ast(finallyNode).withChildren(finallyClauseAst) - case _ => Ast() + val finallyAst = Try(createDotNetNodeInfo(tryStmt.json(ParserKeys.Finally))).toOption.map { finallyNodeInfo => + val finallyNode = controlStructureNode(finallyNodeInfo, ControlStructureTypes.FINALLY, code(finallyNodeInfo)) + val finallyClauseAst = astForFinallyClause(finallyNodeInfo) + Ast(finallyNode).withChildren(finallyClauseAst) } - val controlStructureAst = tryCatchAst(tryNode, tryAst, catchAsts, Option(finallyAst)) + val controlStructureAst = tryCatchAst(tryNode, tryAst, catchAsts, finallyAst) Seq(controlStructureAst) } @@ -295,11 +280,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t * Thus, this is lowered as a try-finally, with finally making a call to `Dispose` on the declared variable. */ private def astForUsingStatement(usingStmt: DotNetNodeInfo): Seq[Ast] = { - val tryNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.TRY) - .code(code(usingStmt)) - .lineNumber(line(usingStmt)) - .columnNumber(column(usingStmt)) + val tryNode = controlStructureNode(usingStmt, ControlStructureTypes.TRY, code(usingStmt)) val tryNodeInfo = createDotNetNodeInfo(usingStmt.json(ParserKeys.Statement)) val tryAst = astForBlock(tryNodeInfo, Option("try")) val declNode = createDotNetNodeInfo(usingStmt.json(ParserKeys.Declaration)) @@ -319,11 +300,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t ) val disposeAst = callAst(disposeCall, receiver = Option(Ast(id))) val childrenAst = Ast(blockNode(usingStmt)).withChild(disposeAst) - val finallyNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.FINALLY) - .code("finally") - .lineNumber(line(usingStmt)) - .columnNumber(column(usingStmt)) + val finallyNode = controlStructureNode(usingStmt, ControlStructureTypes.FINALLY, "finally") Ast(finallyNode).withChild(childrenAst) } diff --git a/joern-cli/frontends/javasrc2cpg/src/main/scala/io/joern/javasrc2cpg/astcreation/statements/AstForSimpleStatementsCreator.scala b/joern-cli/frontends/javasrc2cpg/src/main/scala/io/joern/javasrc2cpg/astcreation/statements/AstForSimpleStatementsCreator.scala index b01d7c854770..32a151ba2584 100644 --- a/joern-cli/frontends/javasrc2cpg/src/main/scala/io/joern/javasrc2cpg/astcreation/statements/AstForSimpleStatementsCreator.scala +++ b/joern-cli/frontends/javasrc2cpg/src/main/scala/io/joern/javasrc2cpg/astcreation/statements/AstForSimpleStatementsCreator.scala @@ -281,35 +281,19 @@ trait AstForSimpleStatementsCreator { this: AstCreator => } private[statements] def astsForTry(stmt: TryStmt): Seq[Ast] = { - val tryNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.TRY) - .code("try") - .lineNumber(line(stmt)) - .columnNumber(column(stmt)) - + val tryNode = controlStructureNode(stmt, ControlStructureTypes.TRY, "try") val resources = stmt.getResources.asScala.flatMap(astsForExpression(_, expectedType = ExpectedType.empty)).toList val tryAst = astForBlockStatement(stmt.getTryBlock, codeStr = "try") val catchAsts = stmt.getCatchClauses.asScala.toList.map { catchClause => - val catchNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.CATCH) - .code("catch") - .lineNumber(line(catchClause)) - .columnNumber(column(catchClause)) + val catchNode = controlStructureNode(catchClause, ControlStructureTypes.CATCH, "catch") Ast(catchNode).withChild(astForCatchClause(catchClause)) } val finallyAst = stmt.getFinallyBlock.toScala.map { finallyBlock => - val finallyNode = NewControlStructure() - .controlStructureType(ControlStructureTypes.FINALLY) - .code("finally") - .lineNumber(line(finallyBlock)) - .columnNumber(column(finallyBlock)) + val finallyNode = controlStructureNode(finallyBlock, ControlStructureTypes.FINALLY, "finally") Ast(finallyNode).withChild(astForBlockStatement(finallyBlock, "finally")) - }.toList - - val childrenAsts = tryAst +: (catchAsts ++ finallyAst) - setArgumentIndices(childrenAsts) - val controlStructureAst = Ast(tryNode).withChildren(childrenAsts) + } + val controlStructureAst = tryCatchAst(tryNode, tryAst, catchAsts, finallyAst) resources.appended(controlStructureAst) } } diff --git a/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstForStatementsCreator.scala b/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstForStatementsCreator.scala index 5df1c618d119..581dbae31cca 100644 --- a/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstForStatementsCreator.scala +++ b/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstForStatementsCreator.scala @@ -11,7 +11,6 @@ import io.shiftleft.codepropertygraph.generated.DispatchTypes import io.shiftleft.codepropertygraph.generated.EdgeTypes import io.shiftleft.codepropertygraph.generated.Operators import io.shiftleft.codepropertygraph.generated.nodes.NewJumpLabel -import io.shiftleft.codepropertygraph.generated.nodes.NewJumpTarget import ujson.Obj import ujson.Value @@ -102,37 +101,31 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForTryStatement(tryStmt: BabelNodeInfo): Ast = { - val tryNode = createControlStructureNode(tryStmt, ControlStructureTypes.TRY) + val tryNode = controlStructureNode(tryStmt, ControlStructureTypes.TRY, code(tryStmt)) val bodyAst = astForNodeWithFunctionReference(tryStmt.json("block")) - val catchAst = safeObj(tryStmt.json, "handler") + val catchAst = safeObj(tryStmt.json, "handler").toList .map { handler => val catchNodeInfo = createBabelNodeInfo(Obj(handler)) - val catchNode = createControlStructureNode(catchNodeInfo, ControlStructureTypes.CATCH) + val catchNode = controlStructureNode(catchNodeInfo, ControlStructureTypes.CATCH, code(catchNodeInfo)) val catchAst = astForCatchClause(catchNodeInfo) Ast(catchNode).withChild(catchAst) } - .getOrElse(Ast()) val finalizerAst = safeObj(tryStmt.json, "finalizer") .map { finalizer => val finalNodeInfo = createBabelNodeInfo(Obj(finalizer)) - val finalNode = createControlStructureNode(finalNodeInfo, ControlStructureTypes.FINALLY) + val finalNode = controlStructureNode(finalNodeInfo, ControlStructureTypes.FINALLY, code(finalNodeInfo)) val finalAst = astForNodeWithFunctionReference(finalNodeInfo.json) Ast(finalNode).withChild(finalAst) } - .getOrElse(Ast()) - val childrenAsts = List(bodyAst, catchAst, finalizerAst) - setArgumentIndices(childrenAsts) - Ast(tryNode).withChildren(childrenAsts) + tryCatchAst(tryNode, bodyAst, catchAst, finalizerAst) } def astForIfStatement(ifStmt: BabelNodeInfo): Ast = { - val ifNode = createControlStructureNode(ifStmt, ControlStructureTypes.IF) + val ifNode = controlStructureNode(ifStmt, ControlStructureTypes.IF, code(ifStmt)) val testAst = astForNodeWithFunctionReference(ifStmt.json("test")) val consequentAst = astForNodeWithFunctionReference(ifStmt.json("consequent")) val alternateAst = safeObj(ifStmt.json, "alternate") - .map { alternate => - astForNodeWithFunctionReference(Obj(alternate)) - } + .map { alternate => astForNodeWithFunctionReference(Obj(alternate)) } .getOrElse(Ast()) // The semantics of if statement children is partially defined by their order value. // The consequentAst must have order == 2 and alternateAst must have order == 3. @@ -149,7 +142,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForDoWhileStatement(doWhileStmt: BabelNodeInfo): Ast = { - val whileNode = createControlStructureNode(doWhileStmt, ControlStructureTypes.DO) + val whileNode = controlStructureNode(doWhileStmt, ControlStructureTypes.DO, code(doWhileStmt)) val testAst = astForNodeWithFunctionReference(doWhileStmt.json("test")) val bodyAst = astForNodeWithFunctionReference(doWhileStmt.json("body")) // The semantics of do-while statement children is partially defined by their order value. @@ -161,7 +154,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForWhileStatement(whileStmt: BabelNodeInfo): Ast = { - val whileNode = createControlStructureNode(whileStmt, ControlStructureTypes.WHILE) + val whileNode = controlStructureNode(whileStmt, ControlStructureTypes.WHILE, code(whileStmt)) val testAst = astForNodeWithFunctionReference(whileStmt.json("test")) val bodyAst = astForNodeWithFunctionReference(whileStmt.json("body")) // The semantics of while statement children is partially defined by their order value. @@ -173,7 +166,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForForStatement(forStmt: BabelNodeInfo): Ast = { - val forNode = createControlStructureNode(forStmt, ControlStructureTypes.FOR) + val forNode = controlStructureNode(forStmt, ControlStructureTypes.FOR, code(forStmt)) val initAst = safeObj(forStmt.json, "init") .map { init => astForNodeWithFunctionReference(Obj(init)) @@ -202,13 +195,8 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForLabeledStatement(labelStmt: BabelNodeInfo): Ast = { - val labelName = code(labelStmt.json("label")) - val labeledNode = NewJumpTarget() - .parserTypeName(labelStmt.node.toString) - .name(labelName) - .code(s"$labelName:") - .lineNumber(labelStmt.lineNumber) - .columnNumber(labelStmt.columnNumber) + val labelName = code(labelStmt.json("label")) + val labeledNode = jumpTargetNode(labelStmt, labelName, s"$labelName:", Option(labelStmt.node.toString)) val blockNode = createBlockNode(labelStmt) scope.pushNewBlockScope(blockNode) @@ -223,26 +211,24 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForBreakStatement(breakStmt: BabelNodeInfo): Ast = { - val labelAst = safeObj(breakStmt.json, "label") - .map { label => - val labelNode = Obj(label) - val labelCode = code(labelNode) - Ast( - NewJumpLabel() - .parserTypeName(breakStmt.node.toString) - .name(labelCode) - .code(labelCode) - .lineNumber(breakStmt.lineNumber) - .columnNumber(breakStmt.columnNumber) - .order(1) - ) - } - .getOrElse(Ast()) - Ast(createControlStructureNode(breakStmt, ControlStructureTypes.BREAK)).withChild(labelAst) + val labelAst = safeObj(breakStmt.json, "label").toList.map { label => + val labelNode = Obj(label) + val labelCode = code(labelNode) + Ast( + NewJumpLabel() + .parserTypeName(breakStmt.node.toString) + .name(labelCode) + .code(labelCode) + .lineNumber(breakStmt.lineNumber) + .columnNumber(breakStmt.columnNumber) + .order(1) + ) + } + Ast(controlStructureNode(breakStmt, ControlStructureTypes.BREAK, code(breakStmt))).withChildren(labelAst) } protected def astForContinueStatement(continueStmt: BabelNodeInfo): Ast = { - val labelAst = safeObj(continueStmt.json, "label") + val labelAst = safeObj(continueStmt.json, "label").toList .map { label => val labelNode = Obj(label) val labelCode = code(labelNode) @@ -256,8 +242,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t .order(1) ) } - .getOrElse(Ast()) - Ast(createControlStructureNode(continueStmt, ControlStructureTypes.CONTINUE)).withChild(labelAst) + Ast(controlStructureNode(continueStmt, ControlStructureTypes.CONTINUE, code(continueStmt))).withChildren(labelAst) } protected def astForThrowStatement(throwStmt: BabelNodeInfo): Ast = { @@ -276,7 +261,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } protected def astForSwitchStatement(switchStmt: BabelNodeInfo): Ast = { - val switchNode = createControlStructureNode(switchStmt, ControlStructureTypes.SWITCH) + val switchNode = controlStructureNode(switchStmt, ControlStructureTypes.SWITCH, code(switchStmt)) // The semantics of switch statement children is partially defined by their order value. // The blockAst must have order == 2. Only to avoid collision we set switchExpressionAst to 1 @@ -287,10 +272,8 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t val blockNode = createBlockNode(switchStmt).order(2) scope.pushNewBlockScope(blockNode) localAstParentStack.push(blockNode) - val casesAsts = switchStmt.json("cases").arr.flatMap(c => astsForSwitchCase(createBabelNodeInfo(c))) setArgumentIndices(casesAsts.toList) - scope.popScope() localAstParentStack.pop() @@ -364,7 +347,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t scope.addVariableReference(loopVariableName, loopVariableNode) // while loop: - val whileLoopNode = createControlStructureNode(forInOfStmt, ControlStructureTypes.WHILE) + val whileLoopNode = controlStructureNode(forInOfStmt, ControlStructureTypes.WHILE, code(forInOfStmt)) // while loop test: val testCallNode = @@ -507,7 +490,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t scope.addVariableReference(resultName, resultNode) // while loop: - val whileLoopNode = createControlStructureNode(forInOfStmt, ControlStructureTypes.WHILE) + val whileLoopNode = controlStructureNode(forInOfStmt, ControlStructureTypes.WHILE, code(forInOfStmt)) // while loop test: val testCallNode = @@ -658,7 +641,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } // while loop: - val whileLoopNode = createControlStructureNode(forInOfStmt, ControlStructureTypes.WHILE) + val whileLoopNode = controlStructureNode(forInOfStmt, ControlStructureTypes.WHILE, code(forInOfStmt)) // while loop test: val testCallNode = @@ -811,7 +794,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t } // while loop: - val whileLoopNode = createControlStructureNode(forInOfStmt, ControlStructureTypes.WHILE) + val whileLoopNode = controlStructureNode(forInOfStmt, ControlStructureTypes.WHILE, code(forInOfStmt)) // while loop test: val testCallNode = diff --git a/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstNodeBuilder.scala b/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstNodeBuilder.scala index 25267d84e935..ba8dd4d45d14 100644 --- a/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstNodeBuilder.scala +++ b/joern-cli/frontends/jssrc2cpg/src/main/scala/io/joern/jssrc2cpg/astcreation/AstNodeBuilder.scala @@ -35,17 +35,6 @@ trait AstNodeBuilder(implicit withSchemaValidation: ValidationMode) { this: AstC .columnNumber(switchCase.columnNumber) } - protected def createControlStructureNode(node: BabelNodeInfo, controlStructureType: String): NewControlStructure = { - val line = node.lineNumber - val column = node.columnNumber - val code = node.code - NewControlStructure() - .controlStructureType(controlStructureType) - .code(code) - .lineNumber(line) - .columnNumber(column) - } - protected def codeOf(node: NewNode): String = node match { case astNodeNew: AstNodeNew => astNodeNew.code case _ => "" diff --git a/joern-cli/frontends/kotlin2cpg/src/main/scala/io/joern/kotlin2cpg/ast/AstForStatementsCreator.scala b/joern-cli/frontends/kotlin2cpg/src/main/scala/io/joern/kotlin2cpg/ast/AstForStatementsCreator.scala index 34731b0b9e66..65ce497f60a9 100644 --- a/joern-cli/frontends/kotlin2cpg/src/main/scala/io/joern/kotlin2cpg/ast/AstForStatementsCreator.scala +++ b/joern-cli/frontends/kotlin2cpg/src/main/scala/io/joern/kotlin2cpg/ast/AstForStatementsCreator.scala @@ -492,7 +492,7 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { private def astForTryAsStatement(expr: KtTryExpression)(implicit typeInfoProvider: TypeInfoProvider): Ast = { val tryAst = astsForExpression(expr.getTryBlock, None).headOption.getOrElse(Ast()) - val clauseAsts = expr.getCatchClauses.asScala.map { catchClause => + val clauseAsts = expr.getCatchClauses.asScala.toSeq.map { catchClause => val catchNode = controlStructureNode(catchClause, ControlStructureTypes.CATCH, catchClause.getText) val childrenAsts = astsForExpression(catchClause.getCatchBody, None) Ast(catchNode).withChildren(childrenAsts) @@ -504,9 +504,8 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { val childrenAsts = astsForExpression(finallyBlock, None) Ast(finallyNode).withChildren(childrenAsts) } - .getOrElse(Ast()) - val node = controlStructureNode(expr, ControlStructureTypes.TRY, expr.getText) - controlStructureAst(node, None, (tryAst +: clauseAsts :+ finallyAst).toList) + val tryNode = controlStructureNode(expr, ControlStructureTypes.TRY, expr.getText) + tryCatchAst(tryNode, tryAst, clauseAsts, finallyAst) } private def astForTryAsExpression( diff --git a/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala b/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala index 101e27f80168..df0473678ab2 100644 --- a/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala +++ b/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala @@ -431,7 +431,6 @@ class AstCreator(filename: String, phpAst: PhpFile, fileContent: Option[String], } val tryNode = controlStructureNode(stmt, ControlStructureTypes.TRY, "try { ... }") - setArgumentIndices(tryBody +: (catches ++ finallyBody.toSeq)) tryCatchAst(tryNode, tryBody, catches, finallyBody) } diff --git a/joern-cli/frontends/pysrc2cpg/src/main/scala/io/joern/pysrc2cpg/PythonAstVisitorHelpers.scala b/joern-cli/frontends/pysrc2cpg/src/main/scala/io/joern/pysrc2cpg/PythonAstVisitorHelpers.scala index 005f92ad64f7..fc66232a2103 100644 --- a/joern-cli/frontends/pysrc2cpg/src/main/scala/io/joern/pysrc2cpg/PythonAstVisitorHelpers.scala +++ b/joern-cli/frontends/pysrc2cpg/src/main/scala/io/joern/pysrc2cpg/PythonAstVisitorHelpers.scala @@ -53,8 +53,7 @@ trait PythonAstVisitorHelpers(implicit withSchemaValidation: ValidationMode) { t orElseBlock: Iterable[NewNode], lineAndColumn: LineAndColumn ): NewNode = { - val controlStructureNode = - nodeBuilder.controlStructureNode("try: ...", ControlStructureTypes.TRY, lineAndColumn) + val controlStructureNode = nodeBuilder.controlStructureNode("try: ...", ControlStructureTypes.TRY, lineAndColumn) val bodyBlockNode = createBlock(body, lineAndColumn).asInstanceOf[NewBlock] val handlersBlockNodes = handlers.map(x => createBlock(Iterable(x), lineAndColumn).asInstanceOf[NewBlock]).toSeq diff --git a/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/astcreation/AstForExpressionsCreator.scala b/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/astcreation/AstForExpressionsCreator.scala index 9384c96696ea..c7e35c2e949b 100644 --- a/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/astcreation/AstForExpressionsCreator.scala +++ b/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/astcreation/AstForExpressionsCreator.scala @@ -627,7 +627,7 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) { } val elseAst = node.elseClause.map { x => astForStatementList(x.thenClause.asStatementList) } val ensureAst = node.ensureClause.map { x => astForStatementList(x.thenClause.asStatementList) } - tryCatchAst( + tryCatchAstWithOrder( NewControlStructure() .controlStructureType(ControlStructureTypes.TRY) .code(code(node)), diff --git a/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/deprecated/astcreation/AstForControlStructuresCreator.scala b/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/deprecated/astcreation/AstForControlStructuresCreator.scala index a118e72dbaeb..89424fad8c9b 100644 --- a/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/deprecated/astcreation/AstForControlStructuresCreator.scala +++ b/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/deprecated/astcreation/AstForControlStructuresCreator.scala @@ -129,7 +129,7 @@ trait AstForControlStructuresCreator(implicit withSchemaValidation: ValidationMo .toSeq val tryNode = controlStructureNode(ctx, ControlStructureTypes.TRY, "try") - tryCatchAst(tryNode, tryBodyAst, catchAsts, finallyAst) + tryCatchAstWithOrder(tryNode, tryBodyAst, catchAsts, finallyAst) } } diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala index e3ebefe4b845..e5079f6f7985 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala @@ -494,11 +494,7 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { private def astForTryExprSyntax(node: TryExprSyntax): Ast = { val tryNode = controlStructureNode(node, ControlStructureTypes.TRY, code(node)) val bodyAst = astForNode(node.expression) - // The semantics of try statement children is defined by their order value. - // Thus we set the here explicitly and do not rely on the usual consecutive - // ordering. - setOrderExplicitly(bodyAst, 1) - Ast(tryNode).withChild(bodyAst) + tryCatchAst(tryNode, bodyAst, Seq.empty, None) } private def astForTupleExprSyntax(node: TupleExprSyntax): Ast = { diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala index 85883687dbf1..df0b6da1b806 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala @@ -54,22 +54,17 @@ trait AstForStmtSyntaxCreator(implicit withSchemaValidation: ValidationMode) { private def astForDiscardStmtSyntax(node: DiscardStmtSyntax): Ast = notHandledYet(node) private def astForDoStmtSyntax(node: DoStmtSyntax): Ast = { - val tryNode = controlStructureNode(node, ControlStructureTypes.TRY, code(node)) - val bodyAst = astForNode(node.body) - setOrderExplicitly(bodyAst, 1) - val catchAsts = node.catchClauses.children.zipWithIndex.map { case (h, index) => - astForCatchHandler(h, index + 2) - }.toIndexedSeq - Ast(tryNode).withChild(bodyAst).withChildren(catchAsts) + val tryNode = controlStructureNode(node, ControlStructureTypes.TRY, code(node)) + val bodyAst = astForNode(node.body) + val catchAsts = node.catchClauses.children.map(astForCatchHandler) + tryCatchAst(tryNode, bodyAst, catchAsts, None) } - private def astForCatchHandler(catchClause: CatchClauseSyntax, argIndex: Int): Ast = { - val catchNode = - controlStructureNode(catchClause, ControlStructureTypes.CATCH, code(catchClause)) - .order(argIndex) - .argumentIndex(argIndex) - val declAst = astForNode(catchClause.catchItems) - val bodyAst = astForNode(catchClause.body) + private def astForCatchHandler(catchClause: CatchClauseSyntax): Ast = { + val catchNode = controlStructureNode(catchClause, ControlStructureTypes.CATCH, code(catchClause)) + val declAst = astForNode(catchClause.catchItems) + val bodyAst = astForNode(catchClause.body) + setArgumentIndices(List(declAst, bodyAst)) Ast(catchNode).withChild(declAst).withChild(bodyAst) } diff --git a/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/AstCreatorBase.scala b/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/AstCreatorBase.scala index d9bcab90807f..1304ca5b559e 100644 --- a/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/AstCreatorBase.scala +++ b/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/AstCreatorBase.scala @@ -220,7 +220,15 @@ abstract class AstCreatorBase(filename: String)(implicit withSchemaValidation: V /** For the given try body, catch ASTs and finally AST, create a try-catch-finally AST with orders set correctly for * the ossdataflow engine. */ - def tryCatchAst(tryNode: NewControlStructure, tryBodyAst: Ast, catchAsts: Seq[Ast], finallyAst: Option[Ast]): Ast = { + @deprecated( + "This will be removed once all frontends switched to `tryCatchAst` using ControlStructure nodes for catches/finally. Use `tryCatchAst` instead." + ) + def tryCatchAstWithOrder( + tryNode: NewControlStructure, + tryBodyAst: Ast, + catchAsts: Seq[Ast], + finallyAst: Option[Ast] + ): Ast = { tryBodyAst.root.collect { case x: ExpressionNew => x }.foreach(_.order = 1) catchAsts.flatMap(_.root).collect { case x: ExpressionNew => x }.foreach(_.order = 2) finallyAst.flatMap(_.root).collect { case x: ExpressionNew => x }.foreach(_.order = 3) @@ -230,6 +238,16 @@ abstract class AstCreatorBase(filename: String)(implicit withSchemaValidation: V .withChildren(finallyAst.toList) } + /** For the given try body, catch ASTs, and finally AST, create a try-catch-finally AST. + */ + def tryCatchAst(tryNode: NewControlStructure, tryBodyAst: Ast, catchAsts: Seq[Ast], finallyAst: Option[Ast]): Ast = { + setArgumentIndices(tryBodyAst +: (catchAsts ++ finallyAst.toSeq)) + Ast(tryNode) + .withChild(tryBodyAst) + .withChildren(catchAsts) + .withChildren(finallyAst.toSeq) + } + /** For a given block node and statement ASTs, create an AST that represents the block. The main purpose of this * method is to increase the readability of the code which creates block asts. */