From 15194258c0d3913a597134510417dec05c6bc500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20Leuth=C3=A4user?= <1417198+max-leuthaeuser@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:23:08 +0100 Subject: [PATCH] [swiftsrc2cpg] Improved support for previously missed Swift AST elements (#4132) Discovered them testing on https://github.com/apple/swift itself. --- .../swiftsrc2cpg/astcreation/AstCreator.scala | 3 +- .../astcreation/AstForDeclSyntaxCreator.scala | 89 +++++++++++++++---- .../astcreation/AstForExprSyntaxCreator.scala | 88 ++++++++++++++---- .../astcreation/AstForStmtSyntaxCreator.scala | 27 ++++-- .../astcreation/AstForSyntaxCreator.scala | 27 +++++- .../astcreation/AstNodeBuilder.scala | 39 +++++++- 6 files changed, 229 insertions(+), 44 deletions(-) diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstCreator.scala index 4f79b2a5cfe7..9e991de87fcc 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstCreator.scala @@ -107,7 +107,8 @@ class AstCreator(val config: Config, val global: SwiftGlobal, val parserResult: protected def astForNodeWithFunctionReference(node: SwiftNode): Ast = { node match { - case func @ (_: FunctionDeclSyntax | _: ClosureExprSyntax) => + case func @ (_: FunctionDeclSyntax | _: AccessorDeclSyntax | _: InitializerDeclSyntax | + _: DeinitializerDeclSyntax | _: ClosureExprSyntax) => astForFunctionLike(func, shouldCreateFunctionReference = true).ast case _ => astForNode(node) } diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForDeclSyntaxCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForDeclSyntaxCreator.scala index be8411009196..d7485a1b8252 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForDeclSyntaxCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForDeclSyntaxCreator.scala @@ -22,10 +22,13 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { this: AstCreator => private def astForAccessorDeclSyntax(node: AccessorDeclSyntax): Ast = { - astForFunctionLike(node).ast + astForNodeWithFunctionReference(node) + } + + private def astForActorDeclSyntax(node: ActorDeclSyntax): Ast = { + astForTypeDeclSyntax(node) } - private def astForActorDeclSyntax(node: ActorDeclSyntax): Ast = notHandledYet(node) private def astForAssociatedTypeDeclSyntax(node: AssociatedTypeDeclSyntax): Ast = notHandledYet(node) private def isConstructor(node: SwiftNode): Boolean = node match { @@ -34,7 +37,8 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } private def declMembers( - decl: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax, + decl: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | + ActorDeclSyntax, withConstructor: Boolean = true ): Seq[DeclSyntax] = { val memberBlock = decl match { @@ -43,6 +47,7 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case p: ProtocolDeclSyntax => p.memberBlock case s: StructDeclSyntax => s.memberBlock case e: EnumDeclSyntax => e.memberBlock + case a: ActorDeclSyntax => a.memberBlock } val allMembers = memberBlock.members.children.map(_.decl) if (withConstructor) { @@ -103,7 +108,8 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } private def createFakeConstructor( - node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax, + node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | + ActorDeclSyntax, methodBlockContent: List[Ast] = List.empty ): AstAndMethod = { val constructorName = io.joern.x2cpg.Defines.ConstructorMethodName @@ -138,6 +144,39 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { AstAndMethod(Ast(), methodNode_, bAst) } + private def declSyntaxFromIfConfigClauseSyntax(node: IfConfigClauseSyntax): Seq[DeclSyntax] = { + node.elements match { + case Some(value: CodeBlockItemListSyntax) => + value.children.collect { case elem if elem.item.isInstanceOf[DeclSyntax] => elem.item.asInstanceOf[DeclSyntax] } + case Some(value: MemberBlockItemListSyntax) => value.children.map(_.decl) + case _ => Seq.empty + } + } + + private def declSyntaxFromIfConfigDeclSyntax(node: IfConfigDeclSyntax): Seq[DeclSyntax] = { + val children = node.clauses.children + val ifIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#if") + val elseIfIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#elseif") + val elseIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#else") + ifIfConfigClauses match { + case Nil => Seq.empty + case ifIfConfigClause :: Nil if ifConfigDeclConditionIsSatisfied(ifIfConfigClause) => + declSyntaxFromIfConfigClauseSyntax(ifIfConfigClause) + case _ :: Nil => + val firstElseIfSatisfied = elseIfIfConfigClauses.find(ifConfigDeclConditionIsSatisfied) + firstElseIfSatisfied match { + case Some(elseIfIfConfigClause) => declSyntaxFromIfConfigClauseSyntax(elseIfIfConfigClause) + case None => + elseIfConfigClauses match { + case Nil => Seq.empty + case elseIfConfigClause :: Nil => declSyntaxFromIfConfigClauseSyntax(elseIfConfigClause) + case _ => Seq.empty + } + } + case _ => Seq.empty + } + } + private def astForDeclMember(node: DeclSyntax, typeDeclNode: NewTypeDecl): Ast = { val typeFullName = typeNameForDeclSyntax(node) node match { @@ -149,10 +188,13 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { val memberNode_ = memberNode(d, function.name, code(d), typeFullName, Seq(function.fullName)) diffGraph.addEdge(typeDeclNode, memberNode_, EdgeTypes.AST) Ast() + case ifConf: IfConfigDeclSyntax => + val declElements = declSyntaxFromIfConfigDeclSyntax(ifConf) + declElements.foldLeft(Ast()) { (ast, decl) => ast.merge(astForDeclMember(decl, typeDeclNode)) } case _: (ActorDeclSyntax | AssociatedTypeDeclSyntax | ClassDeclSyntax | EnumDeclSyntax | ExtensionDeclSyntax | ImportDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | MacroDeclSyntax | MacroExpansionDeclSyntax | OperatorDeclSyntax | PoundSourceLocationSyntax | PrecedenceGroupDeclSyntax | SubscriptDeclSyntax | - TypeAliasDeclSyntax | IfConfigDeclSyntax) => + TypeAliasDeclSyntax) => val ast = astForNode(node) Ast.storeInDiffGraph(ast, diffGraph) ast.root.foreach(r => diffGraph.addEdge(typeDeclNode, r, EdgeTypes.AST)) @@ -178,12 +220,14 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } private def findDeclConstructor( - decl: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax + decl: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | + ActorDeclSyntax ): Option[DeclSyntax] = declMembers(decl).find(isConstructor) private def createDeclConstructor( - node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax, + node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | + ActorDeclSyntax, constructorContent: List[Ast], constructorBlock: Ast = Ast() ): Option[AstAndMethod] = @@ -212,7 +256,8 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { !isInitializedMember(node) private def astForDeclAttributes( - node: ClassDeclSyntax | ProtocolDeclSyntax | VariableDeclSyntax | StructDeclSyntax | EnumDeclSyntax + node: ClassDeclSyntax | ProtocolDeclSyntax | VariableDeclSyntax | StructDeclSyntax | EnumDeclSyntax | + ActorDeclSyntax ): Seq[Ast] = { node match { case c: ClassDeclSyntax => c.attributes.children.map(astForNode) @@ -220,11 +265,12 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case v: VariableDeclSyntax => v.attributes.children.map(astForNode) case s: StructDeclSyntax => s.attributes.children.map(astForNode) case e: EnumDeclSyntax => e.attributes.children.map(astForNode) + case a: ActorDeclSyntax => a.attributes.children.map(astForNode) } } private def astForTypeDeclSyntax( - node: ClassDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax + node: ClassDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | ActorDeclSyntax ): Ast = { // TODO: // - handle genericParameterClause @@ -374,7 +420,10 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } } - private def astForDeinitializerDeclSyntax(node: DeinitializerDeclSyntax): Ast = notHandledYet(node) + private def astForDeinitializerDeclSyntax(node: DeinitializerDeclSyntax): Ast = { + astForNodeWithFunctionReference(node) + } + private def astForEditorPlaceholderDeclSyntax(node: EditorPlaceholderDeclSyntax): Ast = notHandledYet(node) private def astForEnumCaseDeclSyntax(node: EnumCaseDeclSyntax): Ast = { @@ -420,7 +469,8 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } private def inheritsFrom( - node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax + node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | + ActorDeclSyntax ): Seq[String] = { val clause = node match { case c: ClassDeclSyntax => c.inheritanceClause @@ -428,6 +478,7 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case p: ProtocolDeclSyntax => p.inheritanceClause case s: StructDeclSyntax => s.inheritanceClause case e: EnumDeclSyntax => e.inheritanceClause + case a: ActorDeclSyntax => a.inheritanceClause } val inheritsFrom = clause match { case Some(value) => value.inheritedTypes.children.map(c => code(c.`type`)) @@ -595,7 +646,7 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { private def modifiersForDecl( node: ClassDeclSyntax | ExtensionDeclSyntax | ProtocolDeclSyntax | StructDeclSyntax | EnumDeclSyntax | - EnumCaseDeclSyntax + EnumCaseDeclSyntax | ActorDeclSyntax ): Seq[NewModifier] = { val modifierList = node match { case c: ClassDeclSyntax => c.modifiers.children @@ -604,6 +655,7 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case s: StructDeclSyntax => s.modifiers.children case e: EnumDeclSyntax => e.modifiers.children case ec: EnumCaseDeclSyntax => ec.modifiers.children + case a: ActorDeclSyntax => a.modifiers.children } val modifiers = modifierList.flatMap(c => astForNode(c).root.map(_.asInstanceOf[NewModifier])) val allModifier = if (modifiers.isEmpty) { @@ -803,7 +855,7 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { || definedSymbols.get(code(node.condition.get)).contains("1") } - private def astForIfConfigDeclSyntax(node: IfConfigDeclSyntax): Ast = { + protected def astForIfConfigDeclSyntax(node: IfConfigDeclSyntax): Ast = { val children = node.clauses.children val ifIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#if") val elseIfIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#elseif") @@ -846,7 +898,10 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } } - private def astForInitializerDeclSyntax(node: InitializerDeclSyntax): Ast = notHandledYet(node) + private def astForInitializerDeclSyntax(node: InitializerDeclSyntax): Ast = { + astForNodeWithFunctionReference(node) + } + private def astForMacroDeclSyntax(node: MacroDeclSyntax): Ast = notHandledYet(node) private def astForMacroExpansionDeclSyntax(node: MacroExpansionDeclSyntax): Ast = notHandledYet(node) private def astForOperatorDeclSyntax(node: OperatorDeclSyntax): Ast = notHandledYet(node) @@ -884,7 +939,6 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { notHandledYet(valueBinding) code(valueBinding) case wildcard: WildcardPatternSyntax => - notHandledYet(wildcard) generateUnusedVariableName(usedVariableNames, "wildcard") } val typeFullName = binding.typeAnnotation.fold(Defines.Any)(t => code(t.`type`)) @@ -896,7 +950,10 @@ trait AstForDeclSyntaxCreator(implicit withSchemaValidation: ValidationMode) { if (initAsts.isEmpty) { Ast() } else { - val patternAst = astForNode(binding.pattern) + val patternAst = binding.pattern match { + case wildcard: WildcardPatternSyntax => Ast(identifierNode(wildcard, name)) + case other => astForNode(other) + } patternAst.root.collect { case i: NewIdentifier => i }.foreach(_.typeFullName(typeFullName)) modifiers.foreach { mod => patternAst.root.foreach { r => diffGraph.addEdge(r, mod, EdgeTypes.AST) } diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala index 9ca631dbab15..ce3bf4daa22d 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForExprSyntaxCreator.scala @@ -9,6 +9,7 @@ import io.joern.x2cpg.ValidationMode import io.shiftleft.codepropertygraph.generated.ControlStructureTypes import io.shiftleft.codepropertygraph.generated.DispatchTypes import io.shiftleft.codepropertygraph.generated.Operators +import io.shiftleft.codepropertygraph.generated.nodes.NewCall import io.shiftleft.codepropertygraph.generated.nodes.NewNode trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { @@ -96,14 +97,19 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { Ast(idNode) } - private def astForDoExprSyntax(node: DoExprSyntax): Ast = notHandledYet(node) - private def astForEditorPlaceholderExprSyntax(node: EditorPlaceholderExprSyntax): Ast = notHandledYet(node) + private def astForDoExprSyntax(node: DoExprSyntax): Ast = notHandledYet(node) + + private def astForEditorPlaceholderExprSyntax(node: EditorPlaceholderExprSyntax): Ast = { + Ast(literalNode(node, code(node), Option(Defines.String))) + } private def astForFloatLiteralExprSyntax(node: FloatLiteralExprSyntax): Ast = { astForNode(node.literal) } - private def astForForceUnwrapExprSyntax(node: ForceUnwrapExprSyntax): Ast = notHandledYet(node) + private def astForForceUnwrapExprSyntax(node: ForceUnwrapExprSyntax): Ast = { + astForNode(node.expression) + } private def createBuiltinStaticCall(callExpr: FunctionCallExprSyntax, callee: ExprSyntax, fullName: String): Ast = { val callName = callee match { @@ -197,7 +203,9 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { } } - private def astForGenericSpecializationExprSyntax(node: GenericSpecializationExprSyntax): Ast = notHandledYet(node) + private def astForGenericSpecializationExprSyntax(node: GenericSpecializationExprSyntax): Ast = { + astForNode(node.expression) + } private def astForIfExprSyntax(node: IfExprSyntax): Ast = { val code = this.code(node) @@ -211,7 +219,9 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { controlStructureAst(ifNode, Option(conditionAst), Seq(thenAst, elseAst)) } - private def astForInOutExprSyntax(node: InOutExprSyntax): Ast = notHandledYet(node) + private def astForInOutExprSyntax(node: InOutExprSyntax): Ast = { + astForNode(node.expression) + } private def astForInfixOperatorExprSyntax(node: InfixOperatorExprSyntax): Ast = { val op = code(node.operator) match { @@ -222,11 +232,12 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case "/=" => Operators.assignmentDivision case "%=" => Operators.assignmentModulo case "**=" => Operators.assignmentExponentiation + case "&&" => Operators.logicalAnd case "&=" => Operators.assignmentAnd case "&&=" => Operators.assignmentAnd case "|=" => Operators.assignmentOr case "||=" => Operators.assignmentOr - case "||" => Operators.or + case "||" => Operators.logicalOr case "^=" => Operators.assignmentXor case "<<=" => Operators.assignmentShiftLeft case ">>=" => Operators.assignmentArithmeticShiftRight @@ -237,6 +248,7 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case "<" => Operators.lessThan case ">" => Operators.greaterThan case "==" => Operators.equals + case "===" => Operators.equals case "+" => Operators.plus case "-" => Operators.minus case "/" => Operators.division @@ -245,6 +257,8 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case "%" => Operators.modulo case "!" => Operators.logicalNot case "!=" => Operators.notEquals + case "^" => Operators.xor + case "??" => Operators.elvis case _ => notHandledYet(node) ".unknown" @@ -269,8 +283,24 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { callAst(callNode_, argAsts) } - private def astForKeyPathExprSyntax(node: KeyPathExprSyntax): Ast = notHandledYet(node) - private def astForMacroExpansionExprSyntax(node: MacroExpansionExprSyntax): Ast = notHandledYet(node) + private def astForKeyPathExprSyntax(node: KeyPathExprSyntax): Ast = notHandledYet(node) + + private def astForMacroExpansionExprSyntax(node: MacroExpansionExprSyntax): Ast = { + val name = code(node.macroName) + val argAsts = astForNode(node.arguments) +: + node.trailingClosure.toList.map(astForNodeWithFunctionReference) :+ + astForNode(node.additionalTrailingClosures) + val callNode = + NewCall() + .name(name) + .dispatchType(DispatchTypes.INLINED) + .methodFullName(name) + .code(code(node)) + .typeFullName(Defines.Any) + .lineNumber(line(node)) + .columnNumber(column(node)) + callAst(callNode, argAsts) + } private def astForMemberAccessExprSyntax(node: MemberAccessExprSyntax): Ast = { val base = node.base @@ -306,10 +336,21 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { Ast(literalNode(node, code(node), Option(Defines.Nil))) } - private def astForOptionalChainingExprSyntax(node: OptionalChainingExprSyntax): Ast = notHandledYet(node) - private def astForPackElementExprSyntax(node: PackElementExprSyntax): Ast = notHandledYet(node) - private def astForPackExpansionExprSyntax(node: PackExpansionExprSyntax): Ast = notHandledYet(node) - private def astForPatternExprSyntax(node: PatternExprSyntax): Ast = notHandledYet(node) + private def astForOptionalChainingExprSyntax(node: OptionalChainingExprSyntax): Ast = { + astForNodeWithFunctionReference(node.expression) + } + + private def astForPackElementExprSyntax(node: PackElementExprSyntax): Ast = { + astForNodeWithFunctionReference(node.pack) + } + + private def astForPackExpansionExprSyntax(node: PackExpansionExprSyntax): Ast = { + astForNodeWithFunctionReference(node.repetitionPattern) + } + + private def astForPatternExprSyntax(node: PatternExprSyntax): Ast = { + astForNode(node.pattern) + } private def astForPostfixIfConfigExprSyntax(node: PostfixIfConfigExprSyntax): Ast = { val children = node.config.clauses.children @@ -366,7 +407,23 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { callAst(unaryCall, List(expressionAst)) } - private def astForPrefixOperatorExprSyntax(node: PrefixOperatorExprSyntax): Ast = notHandledYet(node) + private def astForPrefixOperatorExprSyntax(node: PrefixOperatorExprSyntax): Ast = { + val operatorMethod = code(node.operator) match { + case "-" => Operators.preDecrement + case "+" => Operators.preIncrement + case "~" => Operators.not + case "!" => Operators.logicalNot + case "<" => Operators.lessThan + case ">" => Operators.greaterThan + case _ => + notHandledYet(node) + ".unknown" + } + val unaryCall = callNode(node, code(node), operatorMethod, operatorMethod, DispatchTypes.STATIC_DISPATCH) + val expressionAst = astForNodeWithFunctionReference(node.expression) + callAst(unaryCall, List(expressionAst)) + } + private def astForRegexLiteralExprSyntax(node: RegexLiteralExprSyntax): Ast = notHandledYet(node) private def astForSequenceExprSyntax(node: SequenceExprSyntax): Ast = notHandledYet(node) private def astForSimpleStringLiteralExprSyntax(node: SimpleStringLiteralExprSyntax): Ast = notHandledYet(node) @@ -430,10 +487,7 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) { setArgumentIndices(cAsts) (tAsts.toList, cAsts.toList) case i: IfConfigDeclSyntax => - val children = i.clauses.children - val childrenTestAsts = children.flatMap(c => c.condition.map(astForNode)).toList - val childrenElementAsts = children.flatMap(c => c.elements.map(astForNode)).toList - (childrenTestAsts, childrenElementAsts) + (List.empty, List(astForIfConfigDeclSyntax(i))) } labelAst +: (testAsts ++ consequentAsts) } diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala index cd31661fc9f6..64ece7a02406 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForStmtSyntaxCreator.scala @@ -533,7 +533,15 @@ trait AstForStmtSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case _ => notHandledYet(node) } - private def astForGuardStmtSyntax(node: GuardStmtSyntax): Ast = notHandledYet(node) + private def astForGuardStmtSyntax(node: GuardStmtSyntax): Ast = { + val code = this.code(node) + val ifNode = controlStructureNode(node, ControlStructureTypes.IF, code) + val conditionAst = astForNode(node.conditions) + val thenAst = Ast() + val elseAst = astForNode(node.body) + setOrderExplicitly(elseAst, 3) + controlStructureAst(ifNode, Option(conditionAst), Seq(thenAst, elseAst)) + } private def astForLabeledStmtSyntax(node: LabeledStmtSyntax): Ast = { val labeledNode = jumpTargetNode(node, code(node.label), code(node)) @@ -572,11 +580,16 @@ trait AstForStmtSyntaxCreator(implicit withSchemaValidation: ValidationMode) { case None => Ast(cpgReturn) } - } - private def astForThenStmtSyntax(node: ThenStmtSyntax): Ast = notHandledYet(node) - private def astForThrowStmtSyntax(node: ThrowStmtSyntax): Ast = notHandledYet(node) + private def astForThenStmtSyntax(node: ThenStmtSyntax): Ast = notHandledYet(node) + + private def astForThrowStmtSyntax(node: ThrowStmtSyntax): Ast = { + val op = ".throw" + val callNode_ = callNode(node, code(node), op, op, DispatchTypes.STATIC_DISPATCH) + val exprAst = astForNodeWithFunctionReference(node.expression) + callAst(callNode_, List(exprAst)) + } private def astForWhileStmtSyntax(node: WhileStmtSyntax): Ast = { val code = this.code(node) @@ -593,7 +606,11 @@ trait AstForStmtSyntaxCreator(implicit withSchemaValidation: ValidationMode) { ) } - private def astForYieldStmtSyntax(node: YieldStmtSyntax): Ast = notHandledYet(node) + private def astForYieldStmtSyntax(node: YieldStmtSyntax): Ast = { + val cpgReturn = returnNode(node, code(node)) + val expr = astForNodeWithFunctionReference(node.yieldedExpressions) + Ast(cpgReturn).withChild(expr).withArgEdge(cpgReturn, expr.root) + } protected def astForStmtSyntax(stmtSyntax: StmtSyntax): Ast = stmtSyntax match { case node: BreakStmtSyntax => astForBreakStmtSyntax(node) diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForSyntaxCreator.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForSyntaxCreator.scala index 61571df69f00..f036121fd89f 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForSyntaxCreator.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstForSyntaxCreator.scala @@ -21,7 +21,21 @@ trait AstForSyntaxCreator(implicit withSchemaValidation: ValidationMode) { this: } private def astForAccessorEffectSpecifiersSyntax(node: AccessorEffectSpecifiersSyntax): Ast = notHandledYet(node) - private def astForAccessorParametersSyntax(node: AccessorParametersSyntax): Ast = notHandledYet(node) + + private def astForAccessorParametersSyntax(node: AccessorParametersSyntax): Ast = { + val name = code(node.name).stripSuffix(",") + val parameterNode = + parameterInNode( + node, + name, + code(node).stripSuffix(","), + node.json("index").num.toInt + 1, + false, + EvaluationStrategies.BY_VALUE + ) + scope.addVariable(name, parameterNode, MethodScope) + Ast(parameterNode) + } private def astForArrayElementSyntax(node: ArrayElementSyntax): Ast = { astForNodeWithFunctionReference(node.expression) @@ -43,7 +57,10 @@ trait AstForSyntaxCreator(implicit withSchemaValidation: ValidationMode) { this: annotationAst(annotationNode(node, attributeCode, name, name), argumentAsts) } - private def astForAvailabilityArgumentSyntax(node: AvailabilityArgumentSyntax): Ast = notHandledYet(node) + private def astForAvailabilityArgumentSyntax(node: AvailabilityArgumentSyntax): Ast = { + Ast(literalNode(node, code(node).stripSuffix(","), Option(Defines.String))) + } + private def astForAvailabilityConditionSyntax(node: AvailabilityConditionSyntax): Ast = notHandledYet(node) private def astForAvailabilityLabeledArgumentSyntax(node: AvailabilityLabeledArgumentSyntax): Ast = notHandledYet( node @@ -166,7 +183,11 @@ trait AstForSyntaxCreator(implicit withSchemaValidation: ValidationMode) { this: private def astForEnumCaseParameterClauseSyntax(node: EnumCaseParameterClauseSyntax): Ast = notHandledYet(node) private def astForEnumCaseParameterSyntax(node: EnumCaseParameterSyntax): Ast = notHandledYet(node) private def astForExposeAttributeArgumentsSyntax(node: ExposeAttributeArgumentsSyntax): Ast = notHandledYet(node) - private def astForExpressionSegmentSyntax(node: ExpressionSegmentSyntax): Ast = notHandledYet(node) + + private def astForExpressionSegmentSyntax(node: ExpressionSegmentSyntax): Ast = { + astForNode(node.expressions) + } + private def astForFunctionEffectSpecifiersSyntax(node: FunctionEffectSpecifiersSyntax): Ast = notHandledYet(node) private def astForFunctionParameterClauseSyntax(node: FunctionParameterClauseSyntax): Ast = notHandledYet(node) diff --git a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstNodeBuilder.scala b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstNodeBuilder.scala index 1a52b40eeae2..246e33e0eb0a 100644 --- a/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstNodeBuilder.scala +++ b/joern-cli/frontends/swiftsrc2cpg/src/main/scala/io/joern/swiftsrc2cpg/astcreation/AstNodeBuilder.scala @@ -22,14 +22,49 @@ trait AstNodeBuilder(implicit withSchemaValidation: ValidationMode) { this: AstC case _ => "" } + private def jumpTargetFromIfConfigClauseSyntax(node: IfConfigClauseSyntax): Seq[SwiftNode] = { + node.elements match { + case Some(value: CodeBlockItemListSyntax) => value.children.map(_.item) + case Some(value: MemberBlockItemListSyntax) => value.children.map(_.decl) + case Some(value: SwitchCaseListSyntax) => value.children + case Some(value: ExprSyntax) => Seq(value) + case Some(value: AttributeListSyntax) => value.children + case _ => Seq.empty + } + } + + private def jumpTargetFromIfConfigDeclSyntax(node: IfConfigDeclSyntax): Seq[SwiftNode] = { + val children = node.clauses.children + val ifIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#if") + val elseIfIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#elseif") + val elseIfConfigClauses = children.filter(c => code(c.poundKeyword) == "#else") + ifIfConfigClauses match { + case Nil => Seq.empty + case ifIfConfigClause :: Nil if ifConfigDeclConditionIsSatisfied(ifIfConfigClause) => + jumpTargetFromIfConfigClauseSyntax(ifIfConfigClause) + case _ :: Nil => + val firstElseIfSatisfied = elseIfIfConfigClauses.find(ifConfigDeclConditionIsSatisfied) + firstElseIfSatisfied match { + case Some(elseIfIfConfigClause) => jumpTargetFromIfConfigClauseSyntax(elseIfIfConfigClause) + case None => + elseIfConfigClauses match { + case Nil => Seq.empty + case elseIfConfigClause :: Nil => jumpTargetFromIfConfigClauseSyntax(elseIfConfigClause) + case _ => Seq.empty + } + } + case _ => Seq.empty + } + } + protected def createJumpTarget(switchCase: SwitchCaseSyntax | IfConfigDeclSyntax): NewJumpTarget = { val (switchName, switchCode) = switchCase match { case s: SwitchCaseSyntax => val c = code(s.label) (c.stripSuffix(":"), c) case i: IfConfigDeclSyntax => - notHandledYet(i) - val c = code(i.clauses.children.head) + val elements = jumpTargetFromIfConfigDeclSyntax(i) + val c = elements.headOption.fold(code(i.clauses.children.head))(code) (c.stripSuffix(":"), c) } NewJumpTarget()