Skip to content

Commit

Permalink
[swiftsrc2cpg] Added support for index access of list-like structures (
Browse files Browse the repository at this point in the history
…joernio#3981)

Also: fixes string segment syntax handling.
  • Loading branch information
max-leuthaeuser authored Dec 20, 2023
1 parent 5010415 commit dfa2775
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,16 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) {
case Some(otherBase) =>
astForNodeWithFunctionReference(otherBase)
}
val memberNode = createFieldIdentifierNode(code(member), line(member), column(member))
createFieldAccessCallAst(baseAst, memberNode, line(node), column(node))

member.baseName match {
case l @ integerLiteral(_) =>
val memberNode = astForIntegerLiteralToken(l)
createIndexAccessCallAst(baseAst, memberNode, line(node), column(node))
case other =>
val memberNode = createFieldIdentifierNode(code(other), line(other), column(other))
createFieldAccessCallAst(baseAst, memberNode, line(node), column(node))
}

}

private def astForMissingExprSyntax(node: MissingExprSyntax): Ast = notHandledYet(node)
Expand All @@ -255,9 +263,15 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) {
astForNode(node.segments)
}

private def astForSubscriptCallExprSyntax(node: SubscriptCallExprSyntax): Ast = notHandledYet(node)
private def astForSuperExprSyntax(node: SuperExprSyntax): Ast = notHandledYet(node)
private def astForSwitchExprSyntax(node: SwitchExprSyntax): Ast = notHandledYet(node)
private def astForSubscriptCallExprSyntax(node: SubscriptCallExprSyntax): Ast = {
val baseAst = astForNodeWithFunctionReference(node.calledExpression)
val memberAst = astForNode(node.arguments)
val additionalArgsAst = astForNode(node.additionalTrailingClosures)
createIndexAccessCallAst(baseAst, memberAst, line(node), column(node), additionalArgsAst)
}

private def astForSuperExprSyntax(node: SuperExprSyntax): Ast = notHandledYet(node)
private def astForSwitchExprSyntax(node: SwitchExprSyntax): Ast = notHandledYet(node)

private def astForTernaryExprSyntax(node: TernaryExprSyntax): Ast = {
val name = Operators.conditional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ trait AstForSwiftTokenCreator(implicit withSchemaValidation: ValidationMode) { t

private def astForInfixQuestionMarkToken(node: infixQuestionMark): Ast = Ast()

private def astForIntegerLiteralToken(node: integerLiteral): Ast = {
protected def astForIntegerLiteralToken(node: integerLiteral): Ast = {
Ast(literalNode(node, code(node), Option(Defines.Int)))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ trait AstForSyntaxCollectionCreator(implicit withSchemaValidation: ValidationMod
}

private def astForMemberBlockItemListSyntax(node: MemberBlockItemListSyntax): Ast = notHandledYet(node)
private def astForMultipleTrailingClosureElementListSyntax(node: MultipleTrailingClosureElementListSyntax): Ast =
notHandledYet(node)

private def astForMultipleTrailingClosureElementListSyntax(node: MultipleTrailingClosureElementListSyntax): Ast = {
astForListSyntaxChildren(node, node.children)
}

private def astForObjCSelectorPieceListSyntax(node: ObjCSelectorPieceListSyntax): Ast = notHandledYet(node)
private def astForPatternBindingListSyntax(node: PatternBindingListSyntax): Ast = notHandledYet(node)
private def astForPlatformVersionItemListSyntax(node: PlatformVersionItemListSyntax): Ast = notHandledYet(node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ trait AstForSyntaxCreator(implicit withSchemaValidation: ValidationMode) { this:
notHandledYet(node)

private def astForStringSegmentSyntax(node: StringSegmentSyntax): Ast = {
Ast(literalNode(node, code(node), Option(Defines.String)))
Ast(literalNode(node, s"\"${code(node)}\"", Option(Defines.String)))
}

private def astForSwitchCaseItemSyntax(node: SwitchCaseItemSyntax): Ast = notHandledYet(node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ trait AstNodeBuilder(implicit withSchemaValidation: ValidationMode) { this: AstC
baseAst: Ast,
partAst: Ast,
line: Option[Integer],
column: Option[Integer]
column: Option[Integer],
additionalArgsAst: Ast = Ast()
): Ast = {
val callNode = createCallNode(
s"${codeOf(baseAst.nodes.head)}[${codeOf(partAst.nodes.head)}]",
Expand All @@ -50,7 +51,7 @@ trait AstNodeBuilder(implicit withSchemaValidation: ValidationMode) { this: AstC
line,
column
)
val arguments = List(baseAst, partAst)
val arguments = List(baseAst, partAst, additionalArgsAst)
callAst(callNode, arguments)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.joern.swiftsrc2cpg.passes

import io.joern.x2cpg.X2Cpg
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.generated.nodes.Call
import io.shiftleft.codepropertygraph.generated.nodes.NewDependency
Expand All @@ -21,24 +22,24 @@ class DependenciesPass(cpg: Cpg) extends CpgPass(cpg) {
call.argument.l match
case Nil => // Do nothing
case _ :: (pathArg: Call) :: Nil if pathArg.argument(1).code == "path" =>
val name = pathArg.argument(2).code
val name = X2Cpg.stripQuotes(pathArg.argument(2).code)
val dep = NewDependency().name(name)
diffGraph.addNode(dep)
case _ :: (nameArg: Call) :: (pathArg: Call) :: Nil
if nameArg.argument(1).code == "name" && pathArg.argument(1).code == "path" =>
val name = nameArg.argument(2).code
val path = pathArg.argument(2).code
val name = X2Cpg.stripQuotes(nameArg.argument(2).code)
val path = X2Cpg.stripQuotes(pathArg.argument(2).code)
val dep = NewDependency().name(name).dependencyGroupId(path)
diffGraph.addNode(dep)
case _ :: (urlArg: Call) :: (versionArg: Call) :: Nil
if urlArg.argument(1).code == "url" && versionIds.contains(versionArg.argument(1).code) =>
val name = urlArg.argument(2).code
val version = versionArg.argument(2).code
val name = X2Cpg.stripQuotes(urlArg.argument(2).code)
val version = X2Cpg.stripQuotes(versionArg.argument(2).code)
val dep = NewDependency().name(name).version(version)
diffGraph.addNode(dep)
case _ :: (urlArg: Call) :: (versionRange: Call) :: Nil if urlArg.argument(1).code == "url" =>
val name = urlArg.argument(2).code
val version = versionRange.code
val name = X2Cpg.stripQuotes(urlArg.argument(2).code)
val version = versionRange.code.replaceAll("[\"']", "")
val dep = NewDependency().name(name).version(version)
diffGraph.addNode(dep)
case call =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,11 +388,24 @@ class DeclarationTests extends AbstractPassTest {
arrayCall.argument.isCall.code.l shouldBe List("1: \"One\",", "2: \"Two\",", "3: \"Three\"")
}

"testAddDictionaryElements" ignore AstFixture("""
|var capitalCity = ["Nepal": "Kathmandu", "England": "London"]
|capitalCity["Japan"] = "Tokyo"
|print(capitalCity["Japan"])
|""".stripMargin) { cpg => ??? }
"testAddDictionaryElements" in AstFixture("""
|var elements = ["A": "1", "B": "2"]
|elements["A"] = "3"
|print(elements["A"])
|""".stripMargin) { cpg =>
val List(elementsAccess1, elementsAccess2) = cpg.call(Operators.indexAccess).l
elementsAccess1.code shouldBe "elements[\"A\"]"
val List(arg11) = elementsAccess1.argument(1).start.isIdentifier.l
arg11.name shouldBe "elements"
val List(arg12) = elementsAccess1.argument(2).start.isLiteral.l
arg12.code shouldBe "\"A\""

elementsAccess2.code shouldBe "elements[\"A\"]"
val List(arg21) = elementsAccess2.argument(1).start.isIdentifier.l
arg21.name shouldBe "elements"
val List(arg22) = elementsAccess2.argument(2).start.isLiteral.l
arg22.code shouldBe "\"A\""
}

"testTupleDeclaration" in AstFixture("var product = (\"MacBook\", 1099.99)") { cpg =>
val List(method) = cpg.method.nameExact("<global>").l
Expand All @@ -405,14 +418,27 @@ class DeclarationTests extends AbstractPassTest {
arrayCall.name shouldBe Operators.arrayInitializer
arrayCall.code shouldBe "(\"MacBook\", 1099.99)"
arrayCall.dispatchType shouldBe DispatchTypes.STATIC_DISPATCH
arrayCall.argument.isLiteral.code.l shouldBe List("MacBook", "1099.99")
arrayCall.argument.isLiteral.code.l shouldBe List("\"MacBook\"", "1099.99")
}

"testTupleAccess" ignore AstFixture("""
"testTupleAccess" in AstFixture("""
|var product = ("MacBook", 1099.99)
|print("Name:", product.0)
|print("Price:", product.1)
|""".stripMargin) { cpg => ??? }
|""".stripMargin) { cpg =>
val List(elementsAccess1, elementsAccess2) = cpg.call(Operators.indexAccess).l
elementsAccess1.code shouldBe "product[0]"
val List(arg11) = elementsAccess1.argument(1).start.isIdentifier.l
arg11.name shouldBe "product"
val List(arg12) = elementsAccess1.argument(2).start.isLiteral.l
arg12.code shouldBe "0"

elementsAccess2.code shouldBe "product[1]"
val List(arg21) = elementsAccess2.argument(1).start.isIdentifier.l
arg21.name shouldBe "product"
val List(arg22) = elementsAccess2.argument(2).start.isLiteral.l
arg22.code shouldBe "1"
}

"testInitAccessorsWithDefaultValues" ignore AstFixture("""
|struct Test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ class DependenciesPassTests extends SwiftSrc2CpgSuite {
depB.dependencyGroupId shouldBe None

depC.name shouldBe "https://github.com/DepC"
depC.version shouldBe """"1.2.3"..<"1.2.6""""
depC.version shouldBe "1.2.3..<1.2.6"
depC.dependencyGroupId shouldBe None

depD.name shouldBe "https://github.com/DepD"
depD.version shouldBe """"1.2.3"..."1.2.6""""
depD.version shouldBe "1.2.3...1.2.6"
depD.dependencyGroupId shouldBe None

depE.name shouldBe "https://github.com/DepE"
Expand Down

0 comments on commit dfa2775

Please sign in to comment.