From bd8e47edd1013d80b784b093edcfd391e144a6d4 Mon Sep 17 00:00:00 2001 From: Edward Klimoshenko Date: Fri, 19 Aug 2022 09:40:03 +0000 Subject: [PATCH] Build `if` statements Change-Id: I4db2d2dfd028ae820c73f9fcb5fff4fa5e6c3ece --- .../lang/apex/ast/ASTIfBlockStatement.java | 9 +-- .../apex/ast/ASTIfElseBlockStatement.java | 16 ++--- .../pmd/lang/apex/ast/ApexTreeBuilder.kt | 58 +++++++++++++++++++ 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java index a6f43c7239..ef70958fc6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java @@ -4,15 +4,16 @@ package net.sourceforge.pmd.lang.apex.ast; -import com.google.summit.ast.Node; import net.sourceforge.pmd.annotation.InternalApi; -public class ASTIfBlockStatement extends AbstractApexNode.Single { +import com.google.summit.ast.statement.IfStatement; + +public class ASTIfBlockStatement extends AbstractApexNode.Single { @Deprecated @InternalApi - public ASTIfBlockStatement(Node ifBlockStatement) { - super(ifBlockStatement); + public ASTIfBlockStatement(IfStatement ifStatement) { + super(ifStatement); } @Override diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java index c6575516fb..d8c76ac583 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java @@ -4,15 +4,19 @@ package net.sourceforge.pmd.lang.apex.ast; -import com.google.summit.ast.Node; import net.sourceforge.pmd.annotation.InternalApi; -public class ASTIfElseBlockStatement extends AbstractApexNode.Single { +import com.google.summit.ast.statement.IfStatement; + +public class ASTIfElseBlockStatement extends AbstractApexNode.Single { + + private final boolean hasElseStatement; @Deprecated @InternalApi - public ASTIfElseBlockStatement(Node ifElseBlockStatement) { - super(ifElseBlockStatement); + public ASTIfElseBlockStatement(IfStatement ifStatement, boolean hasElseStatement) { + super(ifStatement); + this.hasElseStatement = hasElseStatement; } @Override @@ -21,8 +25,6 @@ public class ASTIfElseBlockStatement extends AbstractApexNode.Single { } public boolean hasElseStatement() { - // return node.hasElseStatement(); - // TODO(b/239648780) - return false; + return hasElseStatement; } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt index d232815b76..bacbf48a21 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt @@ -46,6 +46,8 @@ import com.google.summit.ast.modifier.KeywordModifier.Keyword import com.google.summit.ast.modifier.Modifier import com.google.summit.ast.statement.CompoundStatement import com.google.summit.ast.statement.ExpressionStatement +import com.google.summit.ast.statement.IfStatement +import com.google.summit.ast.statement.Statement @Deprecated("internal") @InternalApi @@ -117,6 +119,8 @@ class ApexTreeBuilder(val sourceCode: String, val parserOptions: ApexParserOptio is ValuesInitializer -> buildValuesInitializer(node) is MapInitializer -> buildMapInitializer(node) is SizedArrayInitializer -> buildSizedArrayInitializer(node) + is DmlStatement -> buildDmlStatement(node) + is IfStatement -> buildIfStatement(node) is Identifier, is KeywordModifier, is TypeRef -> null @@ -424,6 +428,60 @@ class ApexTreeBuilder(val sourceCode: String, val parserOptions: ApexParserOptio private fun buildSizedArrayInitializer(node: SizedArrayInitializer) = ASTNewListInitExpression(node).apply { buildChildren(node, parent = this) } + /** Builds an [ApexNode] wrapper for the [DmlStatement]. */ + private fun buildDmlStatement(node: DmlStatement) = + when (node) { + is DmlStatement.Insert -> ASTDmlInsertStatement(node) + is DmlStatement.Update -> ASTDmlUpdateStatement(node) + is DmlStatement.Delete -> ASTDmlDeleteStatement(node) + is DmlStatement.Undelete -> ASTDmlUndeleteStatement(node) + is DmlStatement.Upsert -> ASTDmlUpsertStatement(node) + is DmlStatement.Merge -> ASTDmlMergeStatement(node) + }.apply { buildChildren(node, parent = this) } + + /** Wraps the body of a control statement with an [ASTBlockStatement] if it isn't already one. */ + private fun wrapBody(body: Statement, parent: ApexNode<*>) = + when (body) { + is CompoundStatement -> build(body, parent) as ASTBlockStatement + else -> ASTBlockStatement(body).apply { buildAndSetParent(body, parent = this) } + } + + /** Builds an [ASTIfElseBlockStatement] wrapper for the [IfStatement]. */ + private fun buildIfStatement(node: IfStatement): ASTIfElseBlockStatement { + val (ifBlocks, elseBlock) = flattenIfStatement(node) + + /** Builds an [ASTIfBlockStatement] wrapper for the [if block][IfStatement]. */ + fun buildIfBlock(ifBlock: IfStatement) = + ASTIfBlockStatement(ifBlock).apply { + buildCondition(ifBlock.condition).also { it.setParent(this) } + wrapBody(ifBlock.thenStatement, parent = this).also { it.setParent(this) } + } + + return ASTIfElseBlockStatement(node, elseBlock != null).apply { + ifBlocks.forEach { ifBlock -> buildIfBlock(ifBlock).also { it.setParent(this) } } + if (elseBlock != null) { + wrapBody(elseBlock, parent = this).also { it.setParent(this) } + } + } + } + + /** Result of [flattenIfStatement]. */ + private data class FlatIfStatement(val ifBlocks: List, val elseBlock: Statement?) + + /** Flattens an [IfStatement] into a list of [IfStatement]s. */ + private fun flattenIfStatement( + node: Statement?, + ifBlocks: List = emptyList() + ): FlatIfStatement = + when (node) { + is IfStatement -> + // Extract node and continue flattening + flattenIfStatement(node = node.elseStatement, ifBlocks = ifBlocks + node) + else -> + // Can't flatten + FlatIfStatement(ifBlocks, elseBlock = node) + } + /** Builds an [ASTStandardCondition] wrapper for the [condition]. */ private fun buildCondition(condition: Node?) = ASTStandardCondition(condition).apply { buildAndSetParent(condition, this) }