From c7ffcd244fef3e69539c1a346c6ab23572fb3202 Mon Sep 17 00:00:00 2001 From: Pandurang Patil Date: Wed, 20 Sep 2023 21:42:17 +0530 Subject: [PATCH] [GO] - Fix for ticket #3678 (#3680) Fix for issue #3678. For now, this PR fixes the issue related to the breaking error for the Local node being pushed to as a condition AST node for switch AST. Fixed the issue and resolved the breaking error. This will still require a proper fix to push the Assign AST as the first child of which block AST. We will handle this issue at a later stage. --- .../astcreation/AstForStatementsCreator.scala | 23 +++++++--- .../joern/go2cpg/passes/ast/SwitchTests.scala | 44 +++++++++---------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForStatementsCreator.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForStatementsCreator.scala index 4f1123932da5..4e5a58d77606 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForStatementsCreator.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForStatementsCreator.scala @@ -3,13 +3,11 @@ package io.joern.gosrc2cpg.astcreation import io.joern.gosrc2cpg.parser.ParserAst.* import io.joern.gosrc2cpg.parser.{ParserKeys, ParserNodeInfo} import io.joern.gosrc2cpg.utils.Operator -import io.joern.x2cpg.utils.NodeBuilders.{newCallNode, newOperatorCallNode} import io.joern.x2cpg.{Ast, ValidationMode} -import io.shiftleft.codepropertygraph.generated.nodes.{ExpressionNew, NewCall, NewIdentifier, NewLiteral, NewLocal} +import io.shiftleft.codepropertygraph.generated.nodes.{ExpressionNew, NewIdentifier, NewLocal} import io.shiftleft.codepropertygraph.generated.{ControlStructureTypes, DispatchTypes, Operators} import ujson.Value -import scala.annotation.tailrec import scala.util.Try trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { this: AstCreator => @@ -185,12 +183,25 @@ trait AstForStatementsCreator(implicit withSchemaValidation: ValidationMode) { t val conditionParserNode = Try(createParserNodeInfo(typeSwitchStmt.json(ParserKeys.Assign))) val (code, conditionAst) = conditionParserNode.toOption match { - case Some(node) => (node.code, Some(astForConditionExpression(node))) - case _ => ("", None) + case Some(node) => (node.code, astForNode(node)) + case _ => ("", Seq.empty) } val switchNode = controlStructureNode(typeSwitchStmt, ControlStructureTypes.SWITCH, s"switch $code") val stmtAsts = astsForStatement(createParserNodeInfo(typeSwitchStmt.json(ParserKeys.Body))) - controlStructureAst(switchNode, conditionAst, stmtAsts) + val id = conditionAst + .flatMap(_.root) + .collectFirst { + case x: NewIdentifier => identifierNode(conditionParserNode.get, x.name, x.code, x.typeFullName) + case x: NewLocal => identifierNode(conditionParserNode.get, x.name, x.code, x.typeFullName) + } + .get + val identifier = Ast(id) + val isOp = + callNode(conditionParserNode.get, s"${id.name}.(type)", Operators.is, Operators.is, DispatchTypes.STATIC_DISPATCH) + val condition = Option(callAst(isOp, Seq(identifier))) + + val newStmtAst = stmtAsts // TODO: Push conditionAst to the front of the block + controlStructureAst(switchNode, condition, newStmtAst) } private def astForCaseClause(caseStmt: ParserNodeInfo): Seq[Ast] = { diff --git a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/SwitchTests.scala b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/SwitchTests.scala index df74a3cc98e2..f8e76fa5edcc 100644 --- a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/SwitchTests.scala +++ b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/SwitchTests.scala @@ -1,10 +1,9 @@ package io.joern.go2cpg.passes.ast import io.joern.go2cpg.testfixtures.GoCodeToCpgSuite +import io.shiftleft.codepropertygraph.generated.ControlStructureTypes import io.shiftleft.codepropertygraph.generated.nodes.* -import io.shiftleft.codepropertygraph.generated.{ControlStructureTypes, Operators} import io.shiftleft.semanticcpg.language.* -import io.shiftleft.semanticcpg.language.operatorextension.OpNodes class SwitchTests extends GoCodeToCpgSuite { "AST Creation for switch case" should { @@ -78,7 +77,7 @@ class SwitchTests extends GoCodeToCpgSuite { } } - "be correct for switch case 3" ignore { + "be correct for switch case 3" in { val cpg = code(""" |package main @@ -91,28 +90,26 @@ class SwitchTests extends GoCodeToCpgSuite { | case int: | y = 8 | case float64: - | y= 12 + | y = 12 | } |} """.stripMargin) - inside(cpg.method.name("method").controlStructure.l) { case List(controlStruct: ControlStructure) => - controlStruct.code shouldBe "switch i := x.(type)" - controlStruct.controlStructureType shouldBe ControlStructureTypes.SWITCH - inside(controlStruct.astChildren.l) { case List(assignment: Call, switchBlock: Block) => - switchBlock.astChildren.size shouldBe 9 - switchBlock.astChildren.code.l shouldBe List( - "case nil", - "nil", - "y = 5", - "case int", - "int", - "y = 8", - "case float64", - "float64", - "y = 12" - ) - } - } + val List(controlStruct: ControlStructure) = cpg.method.name("method").controlStructure.l + controlStruct.code shouldBe "switch i := x.(type)" + controlStruct.controlStructureType shouldBe ControlStructureTypes.SWITCH + val List(assignment: Call, switchBlock: Block) = controlStruct.astChildren.l + switchBlock.astChildren.size shouldBe 9 + switchBlock.astChildren.code.l shouldBe List( + "case nil", + "nil", + "y = 5", + "case int", + "int", + "y = 8", + "case float64", + "float64", + "y = 12" + ) } "be correct for switch case 4" in { @@ -135,8 +132,7 @@ class SwitchTests extends GoCodeToCpgSuite { val List(controlStruct: ControlStructure) = cpg.method.name("method").controlStructure.l controlStruct.code shouldBe "switch x.(type)" controlStruct.controlStructureType shouldBe ControlStructureTypes.SWITCH - val List(identifier: Identifier, switchBlock: Block) = controlStruct.astChildren.l - identifier.code shouldBe "x" + val List(identifier: Call, switchBlock: Block) = controlStruct.astChildren.l switchBlock.astChildren.size shouldBe 9 // TODO: something is wrong here. Identifier is being created for int, nil and float64 switchBlock.astChildren.code.l shouldBe List(