Skip to content

Commit

Permalink
[swiftsrc2cpg] Improved support for previously missed Swift AST eleme…
Browse files Browse the repository at this point in the history
…nts (joernio#4132)

Discovered them testing on https://github.com/apple/swift itself.
  • Loading branch information
max-leuthaeuser authored Feb 7, 2024
1 parent 078d1c5 commit 1519425
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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))
Expand All @@ -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] =
Expand Down Expand Up @@ -212,19 +256,21 @@ 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)
case p: ProtocolDeclSyntax => p.attributes.children.map(astForNode)
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
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -420,14 +469,16 @@ 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
case e: ExtensionDeclSyntax => e.inheritanceClause
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`))
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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`))
Expand All @@ -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) }
Expand Down
Loading

0 comments on commit 1519425

Please sign in to comment.