Skip to content

Commit

Permalink
Add isStatic handling on if/while/do-while
Browse files Browse the repository at this point in the history
  • Loading branch information
kjonescertinia committed Sep 20, 2023
1 parent 3d0a1e5 commit 5432026
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 40 deletions.
71 changes: 38 additions & 33 deletions jvm/src/main/scala/com/nawforce/apexlink/cst/Statements.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,39 @@ import scala.collection.mutable

abstract class Statement extends CST with ControlFlow {
def verify(context: BlockVerifyContext): Unit

/** Verify an expression result type matches a specific type logging an issue if not
*
* @param expression to verify
* @param context verify context to use
* @param typeName to check for
* @param isStatic check for static or instance value
* @param prefix for the log issue
*/
def verifyExpressionIs(
expression: Expression,
context: BlockVerifyContext,
typeName: TypeName,
isStatic: Boolean,
prefix: String
): (Boolean, ExprContext) = {
val expr = expression.verify(context)
if (expr.isDefined && (!expr.isStatic.contains(isStatic) || expr.typeName != typeName)) {
val qualifier = if (isStatic) "type" else "instance"
val resultQualifier = if (expr.isStatic.contains(true)) "type" else "instance"
context.log(
Issue(
ERROR_CATEGORY,
expression.location,
s"$prefix expression should return a '$typeName' $qualifier, not a '${expr.typeName}' $resultQualifier"
)
)
(false, expr)
} else {
(true, expr)
}
}

}

// Treat Block as Statement for blocks in blocks
Expand Down Expand Up @@ -151,16 +184,8 @@ object LocalVariableDeclarationStatement {

final case class IfStatement(expression: Expression, statements: Seq[Statement]) extends Statement {
override def verify(context: BlockVerifyContext): Unit = {
val expr = expression.verify(context)
if (expr.isDefined && expr.typeName != TypeNames.Boolean) {
context.log(
Issue(
ERROR_CATEGORY,
expression.location,
s"If expression should return a Boolean value, not a '${expr.typeName}'"
)
)
}
val exprResult =
verifyExpressionIs(expression, context, TypeNames.Boolean, isStatic = false, "If")

// This is replicating a feature where non-block statements can pass declarations forward
val stmtRootContext = new InnerBlockVerifyContext(context).withBranchingControl()
Expand All @@ -177,7 +202,7 @@ final case class IfStatement(expression: Expression, statements: Seq[Statement])
)
})

verifyControlPath(stmtRootContext, BranchControlPattern(Some(expr), 2))
verifyControlPath(stmtRootContext, BranchControlPattern(Some(exprResult._2), 2))
}
}

Expand Down Expand Up @@ -347,17 +372,7 @@ object ForUpdate {
final case class WhileStatement(expression: Expression, statement: Option[Statement])
extends Statement {
override def verify(context: BlockVerifyContext): Unit = {
val expr = expression.verify(context)
if (expr.isDefined && expr.typeName != TypeNames.Boolean) {
context.log(
Issue(
ERROR_CATEGORY,
expression.location,
s"While expression should return a Boolean value, not a '${expr.typeName}'"
)
)
}

verifyExpressionIs(expression, context, TypeNames.Boolean, isStatic = false, "While")
statement.foreach(_.verify(context))
}
}
Expand All @@ -374,17 +389,7 @@ object WhileStatement {
final case class DoWhileStatement(statement: Option[Statement], expression: Expression)
extends Statement {
override def verify(context: BlockVerifyContext): Unit = {
val expr = expression.verify(context)
if (expr.isDefined && expr.typeName != TypeNames.Boolean) {
context.log(
Issue(
ERROR_CATEGORY,
expression.location,
s"While expression should return a Boolean value, not a '${expr.typeName}'"
)
)
}

verifyExpressionIs(expression, context, TypeNames.Boolean, isStatic = false, "While")
statement.foreach(_.verify(context))
}
}
Expand Down
11 changes: 9 additions & 2 deletions jvm/src/test/scala/com/nawforce/apexlink/cst/DoWhileTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@ class DoWhileTest extends AnyFunSuite with TestHelper {
test("Non boolean conditional") {
typeDeclaration("public class Dummy {{ do {} while (''); }}")
assert(
dummyIssues == "Error: line 1 at 35-37: While expression should return a Boolean value, not a 'System.String'\n"
dummyIssues == "Error: line 1 at 35-37: While expression should return a 'System.Boolean' instance, not a 'System.String' instance\n"
)
}

test("Null boolean conditional") {
typeDeclaration("public class Dummy {{ do {} while (null); }}")
assert(
dummyIssues == "Error: line 1 at 35-39: While expression should return a Boolean value, not a 'null'\n"
dummyIssues == "Error: line 1 at 35-39: While expression should return a 'System.Boolean' instance, not a 'null' instance\n"
)
}

test("Static boolean conditional") {
typeDeclaration("public class Dummy {{ do {} while (Boolean); }}")
assert(
dummyIssues == "Error: line 1 at 35-42: While expression should return a 'System.Boolean' instance, not a 'System.Boolean' type\n"
)
}

Expand Down
11 changes: 9 additions & 2 deletions jvm/src/test/scala/com/nawforce/apexlink/cst/IfTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,21 @@ class IfTest extends AnyFunSuite with TestHelper {
test("Non boolean conditional") {
typeDeclaration("public class Dummy {{ if ('') {} }}")
assert(
dummyIssues == "Error: line 1 at 26-28: If expression should return a Boolean value, not a 'System.String'\n"
dummyIssues == "Error: line 1 at 26-28: If expression should return a 'System.Boolean' instance, not a 'System.String' instance\n"
)
}

test("Null boolean conditional") {
typeDeclaration("public class Dummy {{ if (null) {} }}")
assert(
dummyIssues == "Error: line 1 at 26-30: If expression should return a Boolean value, not a 'null'\n"
dummyIssues == "Error: line 1 at 26-30: If expression should return a 'System.Boolean' instance, not a 'null' instance\n"
)
}

test("Static boolean conditional") {
typeDeclaration("public class Dummy {{ if (Boolean) {} }}")
assert(
dummyIssues == "Error: line 1 at 26-33: If expression should return a 'System.Boolean' instance, not a 'System.Boolean' type\n"
)
}

Expand Down
12 changes: 9 additions & 3 deletions jvm/src/test/scala/com/nawforce/apexlink/cst/WhileTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@ class WhileTest extends AnyFunSuite with TestHelper {
test("Non boolean conditional") {
typeDeclaration("public class Dummy {{ while ('') {} }}")
assert(
dummyIssues == "Error: line 1 at 29-31: While expression should return a Boolean value, not a 'System.String'\n"
dummyIssues == "Error: line 1 at 29-31: While expression should return a 'System.Boolean' instance, not a 'System.String' instance\n"
)
}

test("Null boolean conditional") {
typeDeclaration("public class Dummy {{ while (null) {} }}")
assert(
dummyIssues == "Error: line 1 at 29-33: While expression should return a Boolean value, not a 'null'\n"
dummyIssues == "Error: line 1 at 29-33: While expression should return a 'System.Boolean' instance, not a 'null' instance\n"
)
}

test("Static boolean conditional") {
typeDeclaration("public class Dummy {{ while (Boolean) {} }}")
assert(
dummyIssues == "Error: line 1 at 29-36: While expression should return a 'System.Boolean' instance, not a 'System.Boolean' type\n"
)
}

Expand All @@ -36,5 +43,4 @@ class WhileTest extends AnyFunSuite with TestHelper {
test("Single block") {
happyTypeDeclaration("public class Dummy {{ while (true) {System.debug('');} }}")
}

}

0 comments on commit 5432026

Please sign in to comment.