From 8dcd1be8ee2dd87b7637a2d01b0bf65e1c2e932f Mon Sep 17 00:00:00 2001 From: Petr Pucil Date: Wed, 29 Jun 2022 14:06:25 +0200 Subject: [PATCH] Check that the referenced enum member exists It detects problems such as the following: - https://github.com/kaitai-io/kaitai_struct_formats/pull/349#discussion_r506987218 - https://github.com/kaitai-io/kaitai_struct_formats/pull/591#issue-1168568324 --- .../src/main/scala/io/kaitai/struct/format/EnumSpec.scala | 4 ++-- .../scala/io/kaitai/struct/precompile/Exceptions.scala | 2 ++ .../io/kaitai/struct/translators/ExpressionValidator.scala | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/shared/src/main/scala/io/kaitai/struct/format/EnumSpec.scala b/shared/src/main/scala/io/kaitai/struct/format/EnumSpec.scala index 675b9765c..d41b77b43 100644 --- a/shared/src/main/scala/io/kaitai/struct/format/EnumSpec.scala +++ b/shared/src/main/scala/io/kaitai/struct/format/EnumSpec.scala @@ -4,7 +4,7 @@ import io.kaitai.struct.problems.KSYParseError import scala.collection.mutable -case class EnumSpec(map: Map[Long, EnumValueSpec]) { +case class EnumSpec(path: List[String], map: Map[Long, EnumValueSpec]) extends YAMLPath { var name = List[String]() /** @@ -24,7 +24,7 @@ object EnumSpec { def fromYaml(src: Any, path: List[String]): EnumSpec = { val srcMap = ParseUtils.asMap(src, path) val memberNameMap = mutable.Map[String, Long]() - EnumSpec(srcMap.map { case (id, desc) => + EnumSpec(path, srcMap.map { case (id, desc) => val idLong = ParseUtils.asLong(id, path) val value = EnumValueSpec.fromYaml(desc, path ++ List(idLong.toString)) diff --git a/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala b/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala index fe921f700..32411d9b4 100644 --- a/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala +++ b/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala @@ -18,6 +18,8 @@ class FieldNotFoundError(val name: String, val curClass: ClassSpec) extends NotFoundError(s"unable to access '$name' in ${curClass.nameAsStr} context") class EnumNotFoundError(val name: String, val curClass: ClassSpec) extends NotFoundError(s"unable to find enum '$name', searching from ${curClass.nameAsStr}") +class EnumMemberNotFoundError(val label: String, val enum: String, val enumDefPath: String) + extends NotFoundError(s"unable to find enum member '$enum::$label' (enum '$enum' defined at /$enumDefPath)") class MethodNotFoundError(val name: String, val dataType: DataType) extends NotFoundError(s"don't know how to call method '$name' of object type '$dataType'") diff --git a/shared/src/main/scala/io/kaitai/struct/translators/ExpressionValidator.scala b/shared/src/main/scala/io/kaitai/struct/translators/ExpressionValidator.scala index e767bf361..fc8b50cf9 100644 --- a/shared/src/main/scala/io/kaitai/struct/translators/ExpressionValidator.scala +++ b/shared/src/main/scala/io/kaitai/struct/translators/ExpressionValidator.scala @@ -3,6 +3,7 @@ package io.kaitai.struct.translators import io.kaitai.struct.datatype.DataType import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format.Identifier +import io.kaitai.struct.precompile.EnumMemberNotFoundError /** * Validates expressions usage of types (in typecasting operator, @@ -33,8 +34,10 @@ class ExpressionValidator(val provider: TypeProvider) provider.resolveEnum(inType, enumType.name) validate(id) case Ast.expr.EnumByLabel(enumType, label, inType) => - provider.resolveEnum(inType, enumType.name) - // TODO: check that label belongs to that enum + val enumSpec = provider.resolveEnum(inType, enumType.name) + if (!enumSpec.map.values.exists(_.name == label.name)) { + throw new EnumMemberNotFoundError(label.name, enumType.name, enumSpec.path.mkString("/")) + } case Ast.expr.Name(name: Ast.identifier) => if (name.name == Identifier.SIZEOF) { CommonSizeOf.getByteSizeOfClassSpec(provider.nowClass)