-
Notifications
You must be signed in to change notification settings - Fork 302
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[C#] Pattern Matching for
IfExpr
(#4415)
* [c#] Pattern Matching Statements * Initial WIP * bump DotNetAstGen version * [c#] Added lowering for pattern expressions in if statements. Handles declaration and constant patterns * [c#] pr comments * [c#] bump dotnetastgen version * [c#] rollback version on dotnetastgen --------- Co-authored-by: David Baker Effendi <[email protected]>
- Loading branch information
1 parent
cdcf180
commit 93567c7
Showing
6 changed files
with
262 additions
and
69 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
joern-cli/frontends/csharpsrc2cpg/src/main/resources/application.conf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
csharpsrc2cpg { | ||
dotnetastgen_version: "0.28.0" | ||
dotnetastgen_version: "0.29.0" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
...harpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/querying/ast/PatternMatchingTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package io.joern.csharpsrc2cpg.querying.ast | ||
|
||
import io.joern.csharpsrc2cpg.testfixtures.CSharpCode2CpgFixture | ||
import io.shiftleft.codepropertygraph.generated.nodes.{Call, Identifier, Literal, TypeRef} | ||
import io.shiftleft.codepropertygraph.generated.{ControlStructureTypes, NodeTypes, Operators} | ||
import io.shiftleft.semanticcpg.language.* | ||
|
||
class PatternMatchingTests extends CSharpCode2CpgFixture { | ||
|
||
"Pattern matching to extract the non-null value in an if-statement" should { | ||
val cpg = code(basicBoilerplate(""" | ||
|int? maybe = 12; | ||
| | ||
|if (maybe is int number) | ||
|{ | ||
| Console.WriteLine($"The nullable int 'maybe' has the value {number}"); | ||
|} | ||
|else | ||
|{ | ||
| Console.WriteLine("The nullable int 'maybe' doesn't hold a value"); | ||
|} | ||
|""".stripMargin)) | ||
|
||
"lower an assignment from `maybe` to `number` as the first statement of the if-body" in { | ||
inside(cpg.assignment.where(_.target.isIdentifier.name("number")).headOption) { | ||
case Some(assignment) => | ||
assignment.order shouldBe 1 | ||
assignment.inAst.exists(_.label == NodeTypes.CONTROL_STRUCTURE) shouldBe true | ||
|
||
inside(assignment.argument.l) { | ||
case (number: Identifier) :: (maybe: Identifier) :: Nil => | ||
number.name shouldBe "number" | ||
number.typeFullName shouldBe "System.Int32" | ||
|
||
maybe.name shouldBe "maybe" | ||
maybe.typeFullName shouldBe "System.Int32" | ||
case xs => fail(s"Expected two identifier arguments, instead got [${xs.code.mkString(",")}]") | ||
} | ||
|
||
case None => fail("Expected an assignment `number = maybe`") | ||
} | ||
} | ||
|
||
"have an instanceOf-style check as the if-condition" in { | ||
inside(cpg.controlStructure.controlStructureType(ControlStructureTypes.IF).condition.headOption) { | ||
case Some(condition: Call) => | ||
condition.name shouldBe Operators.instanceOf | ||
inside(condition.argument.l) { | ||
case (maybe: Identifier) :: (intType: TypeRef) :: Nil => | ||
maybe.name shouldBe "maybe" | ||
maybe.typeFullName shouldBe "System.Int32" | ||
|
||
intType.typeFullName shouldBe "System.Int32" | ||
case xs => | ||
fail( | ||
s"Expected an identifier and type ref argument to `instanceOf`, instead got [${xs.code.mkString(",")}]" | ||
) | ||
} | ||
case _ => fail("Expected an if-statement with a condition call") | ||
|
||
} | ||
} | ||
} | ||
|
||
"Pattern matching with null type check" should { | ||
val cpg = code(basicBoilerplate(""" | ||
|int? maybe = 12; | ||
| | ||
|if (maybe is null) | ||
|{ | ||
| Console.WriteLine($"The nullable int 'maybe' has the value {number}"); | ||
|} | ||
|""".stripMargin)) | ||
|
||
"have equals check in if statement" in { | ||
inside(cpg.controlStructure.controlStructureType(ControlStructureTypes.IF).condition.headOption) { | ||
case Some(condition: Call) => | ||
condition.name shouldBe Operators.equals | ||
|
||
inside(condition.argument.l) { | ||
case (maybe: Identifier) :: (nullType: Literal) :: Nil => | ||
maybe.name shouldBe "maybe" | ||
maybe.typeFullName shouldBe "System.Int32" | ||
|
||
nullType.typeFullName shouldBe "null" | ||
case xs => fail(s"Expect identifier and literal, instead got [${xs.code.mkString(", ")}]") | ||
} | ||
case _ => fail("Expected an if-statement with condition call") | ||
} | ||
} | ||
} | ||
|
||
} |