-
Notifications
You must be signed in to change notification settings - Fork 296
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a5f3198
commit 965b769
Showing
7 changed files
with
276 additions
and
6 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.11.0" | ||
dotnetastgen_version: "0.12.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
76 changes: 75 additions & 1 deletion
76
...psrc2cpg/src/main/scala/io/joern/csharpsrc2cpg/astcreation/AstForExpressionsCreator.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 |
---|---|---|
@@ -1,16 +1,90 @@ | ||
package io.joern.csharpsrc2cpg.astcreation | ||
|
||
import io.joern.csharpsrc2cpg.parser.DotNetJsonAst.LiteralExpr | ||
import io.joern.csharpsrc2cpg.parser.DotNetJsonAst.* | ||
import io.joern.csharpsrc2cpg.parser.{DotNetNodeInfo, ParserKeys} | ||
import io.joern.x2cpg.{Ast, ValidationMode} | ||
import io.shiftleft.codepropertygraph.generated.nodes.NewCall | ||
import io.shiftleft.codepropertygraph.generated.{DispatchTypes, Operators} | ||
|
||
trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) { this: AstCreator => | ||
|
||
def astForExpression(expr: DotNetNodeInfo): Seq[Ast] = { | ||
// TODO: Handle identifiers in operators | ||
val expressionNode = createDotNetNodeInfo(expr.json(ParserKeys.Expression)) | ||
expressionNode.node match | ||
case _: UnaryExpr => astForUnaryExpression(expressionNode) | ||
case _: BinaryExpr => astForBinaryExpression(expressionNode) | ||
case _ => notHandledYet(expressionNode) | ||
} | ||
|
||
private def astForUnaryExpression(unaryExpr: DotNetNodeInfo): Seq[Ast] = { | ||
val operatorToken = unaryExpr.json(ParserKeys.OperatorToken)(ParserKeys.Value).toString.replaceAll("\"", "") | ||
val operatorName = operatorToken match | ||
case "+" => Operators.plus | ||
case "-" => Operators.minus | ||
case "++" => | ||
if (unaryExpr.node.getClass == PostIncrementExpression.getClass) Operators.postIncrement | ||
else Operators.preIncrement | ||
case "--" => | ||
if (unaryExpr.node.getClass == PostDecrementExpression.getClass) Operators.postDecrement | ||
else Operators.preDecrement | ||
case "~" => Operators.not | ||
case "!" => Operators.logicalNot | ||
case "&" => Operators.addressOf | ||
|
||
Seq(callAst(createCallNodeForOperator(unaryExpr, operatorName, typeFullName = Some("")))) // TODO: typeFullName | ||
} | ||
private def astForBinaryExpression(binaryExpr: DotNetNodeInfo): Seq[Ast] = { | ||
val operatorToken = binaryExpr.json(ParserKeys.OperatorToken)(ParserKeys.Value).toString.replaceAll("\"", "") | ||
val operatorName = operatorToken match | ||
case "+" => Operators.addition | ||
case "-" => Operators.subtraction | ||
case "*" => Operators.multiplication | ||
case "/" => Operators.division | ||
case "%" => Operators.modulo | ||
case "==" => Operators.equals | ||
case "!=" => Operators.notEquals | ||
case "&&" => Operators.logicalAnd | ||
case "||" => Operators.logicalOr | ||
case "+=" => Operators.assignmentPlus | ||
case "-=" => Operators.assignmentMinus | ||
case "*=" => Operators.assignmentMultiplication | ||
case "/=" => Operators.assignmentDivision | ||
case "%=" => Operators.assignmentModulo | ||
case "&=" => Operators.assignmentAnd | ||
case "|=" => Operators.assignmentOr | ||
case "^=" => Operators.assignmentXor | ||
case ">>=" => Operators.assignmentLogicalShiftRight | ||
case "<<=" => Operators.assignmentShiftLeft | ||
case ">" => Operators.greaterThan | ||
case "<" => Operators.lessThan | ||
case ">=" => Operators.greaterEqualsThan | ||
case "<=" => Operators.lessEqualsThan | ||
case "|" => Operators.or | ||
case "&" => Operators.and | ||
case "^" => Operators.xor | ||
|
||
val args = astForNode(binaryExpr.json(ParserKeys.Left)) ++: astForNode(binaryExpr.json(ParserKeys.Right)) | ||
val cNode = | ||
createCallNodeForOperator(binaryExpr, operatorName, typeFullName = Some("")) // TODO: Resolve typeFullName | ||
Seq(callAst(cNode, args)) | ||
} | ||
|
||
protected def astForEqualsValueClause(clause: DotNetNodeInfo): Seq[Ast] = { | ||
val rhsNode = createDotNetNodeInfo(clause.json(ParserKeys.Value)) | ||
rhsNode.node match | ||
case _: LiteralExpr => Seq(Ast(literalNode(rhsNode, code(rhsNode), nodeTypeFullName(rhsNode)))) | ||
case _ => notHandledYet(rhsNode) | ||
} | ||
|
||
private def createCallNodeForOperator( | ||
node: DotNetNodeInfo, | ||
operatorMethod: String, | ||
DispatchType: String = DispatchTypes.STATIC_DISPATCH, | ||
signature: Option[String] = None, | ||
typeFullName: Option[String] = None | ||
): NewCall = { | ||
callNode(node, node.code, operatorMethod, operatorMethod, DispatchType, signature, typeFullName) | ||
} | ||
|
||
} |
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
148 changes: 148 additions & 0 deletions
148
...tends/csharpsrc2cpg/src/test/scala/io/joern/csharpsrc2cpg/passes/ast/OperatorsTests.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,148 @@ | ||
package io.joern.csharpsrc2cpg.passes.ast | ||
|
||
import io.joern.csharpsrc2cpg.parser.DotNetJsonAst.LiteralExpr | ||
import io.joern.csharpsrc2cpg.testfixtures.CSharpCode2CpgFixture | ||
import io.shiftleft.codepropertygraph.generated.Operators | ||
import io.shiftleft.codepropertygraph.generated.nodes.Identifier | ||
import io.shiftleft.semanticcpg.language.* | ||
|
||
class OperatorsTests extends CSharpCode2CpgFixture { | ||
"AST nodes for operators" should { | ||
"be created for unary operators" in { | ||
val cpg = code( | ||
basicBoilerplate(""" | ||
|int i = 3; | ||
|i++; | ||
|i--; | ||
|++i; | ||
|--i; | ||
|!i; | ||
|~i; | ||
|+5; | ||
|-5; | ||
|&i; | ||
|""".stripMargin), | ||
"Program.cs" | ||
) | ||
|
||
val operatorCalls = cpg.method("Main").ast.isCall.nameNot(Operators.assignment).l | ||
operatorCalls.size shouldBe 9 | ||
operatorCalls.name.l shouldBe List( | ||
"<operator>.postIncrement", | ||
"<operator>.postDecrement", | ||
"<operator>.preIncrement", | ||
"<operator>.preDecrement", | ||
"<operator>.logicalNot", | ||
"<operator>.not", | ||
"<operator>.plus", | ||
"<operator>.minus", | ||
"<operator>.addressOf" | ||
) | ||
operatorCalls.code.l shouldBe List("i++", "i--", "++i", "--i", "!i", "~i", "+5", "-5", "&i") | ||
// TODO: Tests for operands | ||
} | ||
} | ||
|
||
"be created for binary operators" in { | ||
val cpg = code( | ||
basicBoilerplate(""" | ||
|int a = 3; | ||
|int b = 5; | ||
|a+b; | ||
|a-b; | ||
|a/b; | ||
|a%b; | ||
|a==b; | ||
|a!=b; | ||
|a&&b; | ||
|a||b; | ||
|a&b; | ||
|a|b; | ||
|a^b; | ||
|""".stripMargin), | ||
fileName = "Program.cs" | ||
) | ||
val operatorCalls = cpg.method("Main").ast.isCall.nameNot(Operators.assignment).l | ||
operatorCalls.size shouldBe 11 | ||
operatorCalls.name.l shouldBe List( | ||
"<operator>.addition", | ||
"<operator>.subtraction", | ||
"<operator>.division", | ||
"<operator>.modulo", | ||
"<operator>.equals", | ||
"<operator>.notEquals", | ||
"<operator>.logicalAnd", | ||
"<operator>.logicalOr", | ||
"<operator>.and", | ||
"<operator>.or", | ||
"<operator>.xor" | ||
) | ||
operatorCalls.code.l shouldBe List("a+b", "a-b", "a/b", "a%b", "a==b", "a!=b", "a&&b", "a||b", "a&b", "a|b", "a^b") | ||
|
||
// TODO: Tests for operands | ||
} | ||
|
||
"be created for shorthand assignment operators" in { | ||
val cpg = code( | ||
basicBoilerplate(""" | ||
|int a = 3; | ||
|int b = 5; | ||
|a+=b; | ||
|a-=b; | ||
|a*=b; | ||
|a/=b; | ||
|a%=b; | ||
|a&=b; | ||
|a|=b; | ||
|a^=b; | ||
|a>>=b; | ||
|a<<=b; | ||
|""".stripMargin), | ||
fileName = "Program.cs" | ||
) | ||
val operatorCalls = cpg.method("Main").ast.isCall.nameNot(Operators.assignment).l | ||
operatorCalls.size shouldBe 10 | ||
operatorCalls.name.l shouldBe List( | ||
"<operator>.assignmentPlus", | ||
"<operator>.assignmentMinus", | ||
"<operator>.assignmentMultiplication", | ||
"<operator>.assignmentDivision", | ||
"<operators>.assignmentModulo", | ||
"<operators>.assignmentAnd", | ||
"<operators>.assignmentOr", | ||
"<operators>.assignmentXor", | ||
"<operators>.assignmentLogicalShiftRight", | ||
"<operators>.assignmentShiftLeft" | ||
) | ||
operatorCalls.code.l shouldBe List("a+=b", "a-=b", "a*=b", "a/=b", "a%=b", "a&=b", "a|=b", "a^=b", "a>>=b", "a<<=b") | ||
|
||
// TODO: Tests for operands | ||
} | ||
|
||
"be created for comparison operators" in { | ||
val cpg = code( | ||
basicBoilerplate(""" | ||
|int a = 3; | ||
|int b = 5; | ||
|a > b; | ||
|a < b; | ||
|a == b; | ||
|a >= b; | ||
|a <= b; | ||
|""".stripMargin), | ||
fileName = "Program.cs" | ||
) | ||
val operatorCalls = cpg.method("Main").ast.isCall.nameNot(Operators.assignment).l | ||
operatorCalls.size shouldBe 5 | ||
operatorCalls.name.l shouldBe List( | ||
"<operator>.greaterThan", | ||
"<operator>.lessThan", | ||
"<operator>.equals", | ||
"<operator>.greaterEqualsThan", | ||
"<operator>.lessEqualsThan" | ||
) | ||
operatorCalls.code.l shouldBe List("a > b", "a < b", "a == b", "a >= b", "a <= b") | ||
|
||
// TODO: Tests for operands | ||
} | ||
} |
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