@@ -4,6 +4,7 @@ import io.joern.swiftsrc2cpg.parser.SwiftNodeSyntax.*
44import io .joern .swiftsrc2cpg .passes .GlobalBuiltins
55import io .joern .x2cpg
66import io .joern .x2cpg .datastructures .Stack .*
7+ import io .joern .x2cpg .datastructures .VariableScopeManager
78import io .joern .x2cpg .frontendspecific .swiftsrc2cpg .Defines
89import io .joern .x2cpg .{Ast , ValidationMode }
910import io .shiftleft .codepropertygraph .generated .*
@@ -230,6 +231,55 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) {
230231 callAst(callNode_, args, Option (baseAst))
231232 }
232233
234+ private def constructorInvocationBlockAst (expr : FunctionCallExprSyntax ): Ast = {
235+ // get call is safe as this function is guarded by isRefToConstructor
236+ val tpe = fullnameProvider.typeFullname(expr).get
237+ registerType(tpe)
238+
239+ val callExprCode = code(expr)
240+ val blockNode_ = blockNode(expr, callExprCode, tpe)
241+ scope.pushNewBlockScope(blockNode_)
242+
243+ val tmpNodeName = scopeLocalUniqueName(" tmp" )
244+ val tmpNode = identifierNode(expr, tmpNodeName, tmpNodeName, tpe)
245+ val localTmpNode = localNode(expr, tmpNodeName, tmpNodeName, tpe)
246+ scope.addVariable(tmpNodeName, localTmpNode, tpe, VariableScopeManager .ScopeType .BlockScope )
247+
248+ val allocOp = Operators .alloc
249+ val allocCallNode = callNode(expr, allocOp, allocOp, allocOp, DispatchTypes .STATIC_DISPATCH )
250+ val assignmentCallOp = Operators .assignment
251+ val assignmentCallNode =
252+ callNode(expr, s " $tmpNodeName = $allocOp" , assignmentCallOp, assignmentCallOp, DispatchTypes .STATIC_DISPATCH )
253+ val assignmentAst = callAst(assignmentCallNode, List (Ast (tmpNode), Ast (allocCallNode)))
254+
255+ val baseNode = identifierNode(expr, tmpNodeName, tmpNodeName, tpe)
256+ scope.addVariableReference(tmpNodeName, baseNode, tpe, EvaluationStrategies .BY_SHARING )
257+
258+ val constructorCallNode = callNode(
259+ expr,
260+ callExprCode,
261+ " init" ,
262+ x2cpg.Defines .UnresolvedNamespace ,
263+ DispatchTypes .STATIC_DISPATCH ,
264+ Some (x2cpg.Defines .UnresolvedSignature ),
265+ Some (Defines .Void )
266+ )
267+ setFullNameInfoForCall(expr, constructorCallNode)
268+
269+ val trailingClosureAsts = expr.trailingClosure.toList.map(astForNode)
270+ val additionalTrailingClosuresAsts = expr.additionalTrailingClosures.children.map(c => astForNode(c.closure))
271+ val args = expr.arguments.children.map(astForNode) ++ trailingClosureAsts ++ additionalTrailingClosuresAsts
272+
273+ val constructorCallAst = callAst(constructorCallNode, args, base = Some (Ast (baseNode)))
274+
275+ val retNode = identifierNode(expr, tmpNodeName, tmpNodeName, tpe)
276+ scope.addVariableReference(tmpNodeName, retNode, tpe, EvaluationStrategies .BY_SHARING )
277+ val retAst = Ast (retNode)
278+
279+ scope.popScope()
280+ Ast (blockNode_).withChildren(Seq (assignmentAst, constructorCallAst, retAst))
281+ }
282+
233283 private def astForFunctionCallExprSyntax (node : FunctionCallExprSyntax ): Ast = {
234284 val callee = node.calledExpression
235285 val calleeCode = code(callee)
@@ -248,6 +298,8 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) {
248298 case m : MemberAccessExprSyntax =>
249299 val memberCode = code(m.declName)
250300 handleCallNodeArgs(node, astForNode(m.base.get), memberCode)
301+ case other if isRefToConstructor(node, other) =>
302+ constructorInvocationBlockAst(node)
251303 case other if isRefToClosure(node, other) =>
252304 astForClosureCall(node)
253305 case declReferenceExprSyntax : DeclReferenceExprSyntax if code(declReferenceExprSyntax) != " self" =>
@@ -271,7 +323,6 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) {
271323
272324 val trailingClosureAsts = expr.trailingClosure.toList.map(astForNode)
273325 val additionalTrailingClosuresAsts = expr.additionalTrailingClosures.children.map(c => astForNode(c.closure))
274-
275326 val args = expr.arguments.children.map(astForNode) ++ trailingClosureAsts ++ additionalTrailingClosuresAsts
276327
277328 val callExprCode = code(expr)
@@ -290,19 +341,37 @@ trait AstForExprSyntaxCreator(implicit withSchemaValidation: ValidationMode) {
290341 private def isRefToClosure (func : FunctionCallExprSyntax , node : ExprSyntax ): Boolean = {
291342 if (! config.swiftBuild) {
292343 // Early exit; without types from the compiler we will be unable to identify closure calls anyway.
293- // This saves us the typeFullname lookup below.
344+ // This saves us the fullnameProvider lookups below.
294345 return false
295346 }
296347 node match {
297348 case refExpr : DeclReferenceExprSyntax
298- if refExpr.baseName.isInstanceOf [identifier] && refExpr.argumentNames.isEmpty &&
349+ if refExpr.baseName.isInstanceOf [identifier] &&
299350 fullnameProvider.declFullname(func).isEmpty &&
300351 fullnameProvider.typeFullname(refExpr).exists(_.startsWith(s " ${Defines .Function }< " )) =>
301352 true
302353 case _ => false
303354 }
304355 }
305356
357+ private def isRefToConstructor (func : FunctionCallExprSyntax , node : ExprSyntax ): Boolean = {
358+ if (! config.swiftBuild) {
359+ // Early exit; without types from the compiler we will be unable to identify constructor calls anyway.
360+ // This saves us the fullnameProvider lookups below.
361+ return false
362+ }
363+ node match {
364+ case refExpr : DeclReferenceExprSyntax
365+ if refExpr.baseName.isInstanceOf [identifier] &&
366+ fullnameProvider.typeFullname(func).nonEmpty &&
367+ fullnameProvider.declFullname(func).exists { fullName =>
368+ fullName.contains(" .init(" ) && fullName.contains(" )->" )
369+ } =>
370+ true
371+ case _ => false
372+ }
373+ }
374+
306375 private def astForGenericSpecializationExprSyntax (node : GenericSpecializationExprSyntax ): Ast = {
307376 astForNode(node.expression)
308377 }
0 commit comments