diff --git a/codyze-backends/cpg/src/main/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDsl.kt b/codyze-backends/cpg/src/main/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDsl.kt index 9de960be9..1a9880ebf 100644 --- a/codyze-backends/cpg/src/main/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDsl.kt +++ b/codyze-backends/cpg/src/main/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDsl.kt @@ -26,8 +26,7 @@ import de.fraunhofer.aisec.cpg.TranslationResult import de.fraunhofer.aisec.cpg.graph.* import de.fraunhofer.aisec.cpg.graph.declarations.ValueDeclaration import de.fraunhofer.aisec.cpg.graph.statements.expressions.* -import de.fraunhofer.aisec.cpg.query.dataFlow -import de.fraunhofer.aisec.cpg.query.executionPath +import de.fraunhofer.aisec.cpg.query.* // // all functions/properties defined here must use CokoBackend @@ -168,14 +167,49 @@ infix fun Any.cpgFlowsTo(that: Collection): Boolean = val regex = Regex(this) regex.matches((it as? Expression)?.evaluate()?.toString().orEmpty()) || regex.matches(it.code.orEmpty()) } + // Separate cases for IntRange and LongRange result in a huge performance boost for large ranges + is LongRange, is IntRange -> checkRange(that) is Iterable<*> -> this.any { it?.cpgFlowsTo(that) ?: false } is Array<*> -> this.any { it?.cpgFlowsTo(that) ?: false } is Node -> that.any { dataFlow(this, it).value } is ParameterGroup -> this.parameters.all { it?.cpgFlowsTo(that) ?: false } + is Length -> checkLength(that) else -> this in that.map { (it as Expression).evaluate() } } } +private fun Any.checkRange(that: Collection): Boolean { + when (this) { + // I would love to combine the following two cases, but any implementation loses the benefit of + // quickly reading the last value of the range, therefore making the whole distinction useless. + is IntRange -> { + return that.all { + val minValue = min(it).value.toInt() + val maxValue = max(it).value.toInt() + minValue > this.first && maxValue < this.last + } + } + is LongRange -> { + return that.all { + val minValue = min(it).value.toInt() + val maxValue = max(it).value.toInt() + minValue > this.first && maxValue < this.last + } + } + else -> throw IllegalArgumentException("Unexpected type") + } +} + +private fun Length.checkLength(that: Collection): Boolean { + return that.all { + val size = sizeof(it).value + if (size == -1) { + // TODO: Handle case where size could not be determined -> OPEN Finding + } + size in this.value + } +} + context(CokoBackend) // TODO: better description // TODO: in mark there is "..." to symbolize that the last arguments don't matter diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/ImplementationDslTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/ImplementationDslTest.kt deleted file mode 100644 index 0dece26f6..000000000 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/ImplementationDslTest.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2022, Fraunhofer AISEC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.fraunhofer.aisec.codyze.backends.cpg - -import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend -import de.fraunhofer.aisec.codyze.backends.cpg.coko.dsl.cpgGetAllNodes -import de.fraunhofer.aisec.codyze.backends.cpg.coko.dsl.cpgGetNodes -import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.Wildcard -import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.op -import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.signature -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test -import kotlin.io.path.toPath -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -class ImplementationDslTest { - - @Test - fun `test cpgGetAllNodes`() { - val op = op { - "Foo.fun" { - signature(2) - } - } - with(backend) { - val allNodes = op.cpgGetAllNodes() - assertEquals( - 5, - allNodes.size, - "cpgGetAllNodes returned ${allNodes.size} node(s) instead of 5 nodes fo the Op: $op." - ) - } - } - - @Test - fun `test cpgGetNodes`() { - val op = op { - "Foo.fun" { - signature(1..10) - } - } - with(backend) { - val nodes = op.cpgGetNodes() - assertEquals( - 2, - nodes.size, - "cpgGetNodes returned ${nodes.size} node(s) instead of 2 nodes for the Op: $op." - ) - } - } - - @Test - fun `test cpgGetNodes with unordered parameters`() { - val op = op { - "Foo.bar" { - signature(arrayOf(".*Test.*")) { - - Wildcard - - Wildcard - } - } - } - with(backend) { - val nodes = op.cpgGetNodes() - assertEquals( - 3, - nodes.size, - "cpgGetNodes returned ${nodes.size} node(s) instead of 3 nodes for the Op: $op." - ) - } - } - - companion object { - - lateinit var backend: CokoCpgBackend - - @BeforeAll - @JvmStatic - fun startup() { - val classLoader = ImplementationDslTest::class.java.classLoader - - val testFileResource = classLoader.getResource("ImplementationDslTest/SimpleJavaFile.java") - assertNotNull(testFileResource) - val testFile = testFileResource.toURI().toPath() - backend = CokoCpgBackend(config = createCpgConfiguration(testFile)) - } - } -} diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/SignatureTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/SignatureTest.kt index ce1508e7e..0fc2a2a2f 100644 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/SignatureTest.kt +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/SignatureTest.kt @@ -17,6 +17,7 @@ package de.fraunhofer.aisec.codyze.backends.cpg import de.fraunhofer.aisec.codyze.backends.cpg.coko.dsl.* import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.CokoBackend +import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.Length import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.Type import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.withType import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression @@ -144,4 +145,22 @@ class SignatureTest { for (i in args.indices) verify { with(node) { params[i].cpgFlowsTo(args[i]) } } } // TODO hasVarargs + + @Test + fun `test signature with good String length`() { + every { node.arguments } returns listOf(stringArgument) + every { stringArgument.type.typeName } returns "kotlin.String" + every { stringArgument.value } returns "test" + + assertTrue { with(backend) { with(node) { cpgSignature(Length(4..4)) } } } + } + + @Test + fun `test signature with bad String length`() { + every { node.arguments } returns listOf(stringArgument) + every { stringArgument.type.typeName } returns "kotlin.String" + every { stringArgument.value } returns "string" + + assertFalse { with(backend) { with(node) { cpgSignature(Length(-1..4)) } } } + } } diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDslTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDslTest.kt new file mode 100644 index 000000000..215c63ec6 --- /dev/null +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/dsl/ImplementationDslTest.kt @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2022, Fraunhofer AISEC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.fraunhofer.aisec.codyze.backends.cpg.coko.dsl + +import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend +import de.fraunhofer.aisec.codyze.backends.cpg.createCpgConfiguration +import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.* +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import kotlin.io.path.toPath +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class ImplementationDslTest { + + @Test + fun `test cpgGetAllNodes`() { + val op = op { + "Foo.fun" { + signature(2) + } + } + with(simpleBackend) { + val allNodes = op.cpgGetAllNodes() + assertEquals( + 5, + allNodes.size, + "cpgGetAllNodes returned ${allNodes.size} node(s) instead of 5 nodes fo the Op: $op." + ) + } + } + + @Test + fun `test cpgGetNodes`() { + val op = op { + "Foo.fun" { + signature(1..10) + } + } + with(simpleBackend) { + val nodes = op.cpgGetNodes() + assertEquals( + 2, + nodes.size, + "cpgGetNodes returned ${nodes.size} node(s) instead of 2 nodes for the Op: $op." + ) + } + } + + @Test + fun `test cpgGetNodes with Long Range`() { + val op = op { + "Foo.fun" { + signature(1..10L) + } + } + with(simpleBackend) { + val nodes = op.cpgGetNodes() + assertEquals( + 2, + nodes.size, + "cpgGetNodes returned ${nodes.size} node(s) instead of 2 nodes for the Op: $op." + ) + } + } + + @Test + fun `test cpgGetNodes with unordered parameters`() { + val op = op { + "Foo.bar" { + signature(arrayOf(".*Test.*")) { + - Wildcard + - Wildcard + } + } + } + with(simpleBackend) { + val nodes = op.cpgGetNodes() + assertEquals( + 3, + nodes.size, + "cpgGetNodes returned ${nodes.size} node(s) instead of 3 nodes for the Op: $op." + ) + } + } + + @Disabled("sizeof in CPG currently does not support InitListExpression as initializer") + @Test + fun `test Array Length`() { + val opX: MutableList = mutableListOf() + for (i in 0..3) { + opX += op { + "Foo.fun" { + signature( + Length(i..i) + ) + } + } + } + + val results = arrayOf(1, 0, 1, 2) + for (i in 0..3) { + with(lengthBackend) { + val nodes = opX[i].cpgGetNodes() + // TODO: filter out false positives + assertEquals( + results[i], + nodes.size, + "cpgGetNodes returned ${nodes.size} node(s) instead of ${results[i]} nodes " + + "for the Op: ${opX[i]}." + ) + } + } + } + + @Disabled("sizeof in CPG currently does not support MemberCallExpression as Initializer") + @Test + fun `test List Length`() { + val opX: MutableList = mutableListOf() + for (i in 0..3) { + opX += op { + "Foo.bar" { + signature( + Length(i..i) + ) + } + } + } + + val results = arrayOf(1, 0, 1, 2) + for (i in 0..3) { + with(lengthBackend) { + val nodes = opX[i].cpgGetNodes() + // TODO: filter out false positives + assertEquals( + results[i], + nodes.size, + "cpgGetNodes returned ${nodes.size} node(s) instead of ${results[i]} nodes " + + "for the Op: ${opX[i]}." + ) + } + } + } + + companion object { + + lateinit var simpleBackend: CokoCpgBackend + lateinit var lengthBackend: CokoCpgBackend + + @BeforeAll + @JvmStatic + fun startup() { + val classLoader = ImplementationDslTest::class.java.classLoader + + val simpleFileResource = classLoader.getResource("ImplementationDslTest/SimpleJavaFile.java") + val lengthFileResource = classLoader.getResource("ImplementationDslTest/LengthJavaFile.java") + + assertNotNull(simpleFileResource) + assertNotNull(lengthFileResource) + + val simpleFile = simpleFileResource.toURI().toPath() + val lengthFile = lengthFileResource.toURI().toPath() + + simpleBackend = CokoCpgBackend(config = createCpgConfiguration(simpleFile)) + lengthBackend = CokoCpgBackend(config = createCpgConfiguration(lengthFile)) + } + } +} diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/FollowsEvaluationTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/FollowsEvaluationTest.kt similarity index 96% rename from codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/FollowsEvaluationTest.kt rename to codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/FollowsEvaluationTest.kt index 231f0b736..a0f43063f 100644 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/FollowsEvaluationTest.kt +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/FollowsEvaluationTest.kt @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.fraunhofer.aisec.codyze.backends.cpg +package de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend import de.fraunhofer.aisec.codyze.backends.cpg.coko.CpgFinding +import de.fraunhofer.aisec.codyze.backends.cpg.createCpgConfiguration +import de.fraunhofer.aisec.codyze.backends.cpg.dummyRule import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.EvaluationContext import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.Finding import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.definition diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/NeverEvaluationTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/NeverEvaluationTest.kt similarity index 95% rename from codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/NeverEvaluationTest.kt rename to codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/NeverEvaluationTest.kt index 615c531df..5068a2333 100644 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/NeverEvaluationTest.kt +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/NeverEvaluationTest.kt @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.fraunhofer.aisec.codyze.backends.cpg +package de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend +import de.fraunhofer.aisec.codyze.backends.cpg.createCpgConfiguration +import de.fraunhofer.aisec.codyze.backends.cpg.dummyRule import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.EvaluationContext import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.Finding import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.definition diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/OnlyEvaluationTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/OnlyEvaluationTest.kt similarity index 93% rename from codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/OnlyEvaluationTest.kt rename to codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/OnlyEvaluationTest.kt index 5b99e2a31..7d4d3e394 100644 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/OnlyEvaluationTest.kt +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/OnlyEvaluationTest.kt @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.fraunhofer.aisec.codyze.backends.cpg +package de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend +import de.fraunhofer.aisec.codyze.backends.cpg.createCpgConfiguration +import de.fraunhofer.aisec.codyze.backends.cpg.dummyRule import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.EvaluationContext import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.Finding import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.definition diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/OrderEvaluationTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/OrderEvaluationTest.kt similarity index 98% rename from codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/OrderEvaluationTest.kt rename to codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/OrderEvaluationTest.kt index e7f8fa616..741230829 100644 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/OrderEvaluationTest.kt +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/evaluators/OrderEvaluationTest.kt @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.fraunhofer.aisec.codyze.backends.cpg +package de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend import de.fraunhofer.aisec.codyze.backends.cpg.coko.CpgFinding +import de.fraunhofer.aisec.codyze.backends.cpg.createCpgConfiguration import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.CokoBackend import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.EvaluationContext import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.Evaluator diff --git a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/NfaDfaConstructionTest.kt b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/ordering/NfaDfaConstructionTest.kt similarity index 99% rename from codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/NfaDfaConstructionTest.kt rename to codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/ordering/NfaDfaConstructionTest.kt index fabb881a0..b8baf492f 100644 --- a/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/NfaDfaConstructionTest.kt +++ b/codyze-backends/cpg/src/test/kotlin/de/fraunhofer/aisec/codyze/backends/cpg/coko/ordering/NfaDfaConstructionTest.kt @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.fraunhofer.aisec.codyze.backends.cpg +package de.fraunhofer.aisec.codyze.backends.cpg.coko.ordering import de.fraunhofer.aisec.codyze.backends.cpg.coko.CokoCpgBackend -import de.fraunhofer.aisec.codyze.backends.cpg.coko.ordering.toNfa import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.* import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.ordering.* import de.fraunhofer.aisec.cpg.analysis.fsm.DFA @@ -48,7 +47,7 @@ class NfaDfaConstructionTest { } private val baseName = - "de.fraunhofer.aisec.codyze.backends.cpg.NfaDfaConstructionTest\$TestClass" + "de.fraunhofer.aisec.codyze.backends.cpg.coko.ordering.NfaDfaConstructionTest\$TestClass" private fun orderExpressionToNfa(block: Order.() -> Unit): NFA { val order = Order().apply(block) diff --git a/codyze-backends/cpg/src/test/resources/ImplementationDslTest/LengthJavaFile.java b/codyze-backends/cpg/src/test/resources/ImplementationDslTest/LengthJavaFile.java new file mode 100644 index 000000000..53b1ef7f4 --- /dev/null +++ b/codyze-backends/cpg/src/test/resources/ImplementationDslTest/LengthJavaFile.java @@ -0,0 +1,42 @@ +import java.util.List; +import java.lang.String; + +public class Length { + + public void one(int[] e) { + Foo f = new Foo(); + + int[] a = {1, 2, 3}; + int[] b = { }; + String[] c = {"a", "b", "c"}; + String[] d = {"ab", "c"}; + + f.fun(a); + f.fun(b); + f.fun(c); + f.fun(d); + f.fun(e); + } + + public void two(List e) { + Foo f = new Foo(); + + List a = List.of(1, 2, 3); + List b = List.of(); + List c = List.of("a", "b", "c"); + List c = List.of("ab", "c"); + + f.bar(a); + f.bar(b); + f.bar(c); + f.bar(d); + f.bar(e); + } +} + + +public class Foo { + public void fun(int[] a) {} + + public void bar(List l) {} +} diff --git a/codyze-specification-languages/coko/coko-core/src/main/kotlin/de/fraunhofer/aisec/codyze/specificationLanguages/coko/core/dsl/Types.kt b/codyze-specification-languages/coko/coko-core/src/main/kotlin/de/fraunhofer/aisec/codyze/specificationLanguages/coko/core/dsl/Types.kt index c0363f54e..28c097db4 100644 --- a/codyze-specification-languages/coko/coko-core/src/main/kotlin/de/fraunhofer/aisec/codyze/specificationLanguages/coko/core/dsl/Types.kt +++ b/codyze-specification-languages/coko/coko-core/src/main/kotlin/de/fraunhofer/aisec/codyze/specificationLanguages/coko/core/dsl/Types.kt @@ -29,4 +29,7 @@ data class Type(val fqn: String) data class ParamWithType(val param: Any, val type: Type) +/** Marks that we want to check the length of the argument, not the contents */ +data class Length(val value: IntRange) + infix fun Any.withType(fqn: String) = ParamWithType(this, Type(fqn))