From 88f35277e577b7d444f210fef58ba4833f9dcb0f Mon Sep 17 00:00:00 2001 From: Karan Batavia Date: Mon, 22 Jul 2024 14:58:32 +0530 Subject: [PATCH 1/2] c# ast structure for coalesce expression --- .../AstForExpressionsCreator.scala | 8 +++++ .../csharpsrc2cpg/parser/DotNetJsonAst.scala | 2 ++ .../querying/ast/CallTests.scala | 30 ++++++++++++++++ .../joern/pysrc2cpg/cpg/IdentifierTests.scala | 36 +++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala index 5c22db90103e..48f3bf6d5661 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.scala @@ -37,11 +37,19 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) { case InterpolatedStringExpression => astForInterpolatedStringExpression(expr) case ConditionalAccessExpression => astForConditionalAccessExpression(expr) case SuppressNullableWarningExpression => astForSuppressNullableWarningExpression(expr) + case CoalesceExpression => astForCoalesceExpression(expr) case _: BaseLambdaExpression => astForSimpleLambdaExpression(expr) case _ => notHandledYet(expr) } } + private def astForCoalesceExpression(coalesceExpression: DotNetNodeInfo): Seq[Ast] = { + val leftAst = astForExpression(createDotNetNodeInfo(coalesceExpression.json(ParserKeys.Left))) + val rightAst = astForExpression(createDotNetNodeInfo(coalesceExpression.json(ParserKeys.Right))) + + leftAst ++ rightAst + } + private def astForAwaitExpression(awaitExpr: DotNetNodeInfo): Seq[Ast] = { /* fullName is the name in case of STATIC_DISPATCH */ val node = diff --git a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/parser/DotNetJsonAst.scala b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/parser/DotNetJsonAst.scala index 67ebeadaa1a8..e3aeaec69d6c 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/parser/DotNetJsonAst.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/parser/DotNetJsonAst.scala @@ -270,6 +270,8 @@ object DotNetJsonAst { object Attribute extends BaseExpr + object CoalesceExpression extends BaseExpr + object Unknown extends DotNetParserNode } diff --git a/joern-cli/frontends/csharpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/querying/ast/CallTests.scala b/joern-cli/frontends/csharpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/querying/ast/CallTests.scala index 96f14f2a4a4e..03ec7cb47171 100644 --- a/joern-cli/frontends/csharpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/querying/ast/CallTests.scala +++ b/joern-cli/frontends/csharpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/querying/ast/CallTests.scala @@ -196,4 +196,34 @@ class CallTests extends CSharpCode2CpgFixture { } } + "null-coalescing operator" should { + val cpg = code(""" + |namespace Baz + |{ + | public class Foo + | { + | private readonly IDatabase db; + | + | public async AnyValue GetValue(string x) + | { + | var value = await db.get(x) ?? new AnyValue(); + | return value; + | } + | } + |} + |""".stripMargin).moreCode(""" + |namespace Baz; + | + |public interface IDatabase { + | public AnyValue get(string x) {} + |} + |""".stripMargin) + + "resolve methodFullName" in { + inside(cpg.call.name("get").methodFullName.l) { + case x :: Nil => x shouldBe "Baz.IDatabase.get:AnyValue(System.String)" + case _ => fail("Unexpected call node structure") + } + } + } } diff --git a/joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala b/joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala new file mode 100644 index 000000000000..9bb9ef66fb06 --- /dev/null +++ b/joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala @@ -0,0 +1,36 @@ +package io.joern.pysrc2cpg.cpg + +import io.joern.pysrc2cpg.PySrc2CpgFixture +import io.shiftleft.semanticcpg.language.* + +import java.io.File + +class IdentifierTests extends PySrc2CpgFixture(withOssDataflow = false) { + "an identifier assigned to a class object" should { + val cpg = code( + """ + |class Foo: + | pass + |""".stripMargin, + "foo.py" + ).moreCode( + """ + |from foo import Foo + |""".stripMargin, + Seq("bar", "__init__.py").mkString(File.separator) + ).moreCode( + """ + |import bar + | + |baz = bar.Foo() + |""".stripMargin, + "baz.py" + ) + + "have correct typeFullName" in { + inside(cpg.identifier("baz").l) { case baz :: Nil => + baz.typeFullName shouldBe "foo.py:.Foo" + } + } + } +} From 70d4768948babc2ff94a9c2b0281ed430bf12385 Mon Sep 17 00:00:00 2001 From: Karan Batavia Date: Mon, 22 Jul 2024 15:13:25 +0530 Subject: [PATCH 2/2] remove IdentifierTests.scala --- .../joern/pysrc2cpg/cpg/IdentifierTests.scala | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala diff --git a/joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala b/joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala deleted file mode 100644 index 9bb9ef66fb06..000000000000 --- a/joern-cli/frontends/pysrc2cpg/src/test/scala/io/joern/pysrc2cpg/cpg/IdentifierTests.scala +++ /dev/null @@ -1,36 +0,0 @@ -package io.joern.pysrc2cpg.cpg - -import io.joern.pysrc2cpg.PySrc2CpgFixture -import io.shiftleft.semanticcpg.language.* - -import java.io.File - -class IdentifierTests extends PySrc2CpgFixture(withOssDataflow = false) { - "an identifier assigned to a class object" should { - val cpg = code( - """ - |class Foo: - | pass - |""".stripMargin, - "foo.py" - ).moreCode( - """ - |from foo import Foo - |""".stripMargin, - Seq("bar", "__init__.py").mkString(File.separator) - ).moreCode( - """ - |import bar - | - |baz = bar.Foo() - |""".stripMargin, - "baz.py" - ) - - "have correct typeFullName" in { - inside(cpg.identifier("baz").l) { case baz :: Nil => - baz.typeFullName shouldBe "foo.py:.Foo" - } - } - } -}