From 2ba2757295323ecea8728ea85a5ef68891aea88e Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Tue, 21 Jan 2025 11:39:46 +0100 Subject: [PATCH] Kotlin script works (at least with K2) --- .../aisec/codyze/compliance/Command.kt | 2 +- .../kotlin/codyze/QueryHostTest.kt | 7 ++----- .../resources/simple.query.kts | 10 +++++++--- .../de/fraunhofer/aisec/codyze/Project.kt | 2 +- .../de/fraunhofer/aisec/codyze/QueryHost.kt | 19 ++++++++++++++++--- .../aisec/codyze/QueryScriptDefinition.kt | 13 +++++++++++-- 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/codyze-compliance/src/main/kotlin/de/fraunhofer/aisec/codyze/compliance/Command.kt b/codyze-compliance/src/main/kotlin/de/fraunhofer/aisec/codyze/compliance/Command.kt index 06ccf8d886..b0a4e1c43a 100644 --- a/codyze-compliance/src/main/kotlin/de/fraunhofer/aisec/codyze/compliance/Command.kt +++ b/codyze-compliance/src/main/kotlin/de/fraunhofer/aisec/codyze/compliance/Command.kt @@ -28,7 +28,7 @@ package de.fraunhofer.aisec.codyze.compliance import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.subcommands import com.github.ajalt.clikt.parameters.groups.provideDelegate -import de.fraunhofer.aisec.cpg.codyze.* +import de.fraunhofer.aisec.codyze.* /** The main `compliance` command. */ class ComplianceCommand : CliktCommand() { diff --git a/codyze-core/src/integrationTest/kotlin/codyze/QueryHostTest.kt b/codyze-core/src/integrationTest/kotlin/codyze/QueryHostTest.kt index 185f17c77a..2c3c9f15da 100644 --- a/codyze-core/src/integrationTest/kotlin/codyze/QueryHostTest.kt +++ b/codyze-core/src/integrationTest/kotlin/codyze/QueryHostTest.kt @@ -32,8 +32,6 @@ import de.fraunhofer.aisec.cpg.query.QueryTree import de.fraunhofer.aisec.cpg.test.analyze import java.io.File import kotlin.io.path.Path -import kotlin.script.experimental.api.ResultValue -import kotlin.script.experimental.api.valueOrNull import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -46,9 +44,8 @@ class QueryHostTest { analyze(listOf(topLevel.resolve("simple.py").toFile()), topLevel, true) { it.registerLanguage() } - val scriptResult = result.evalQuery(File("src/integrationTest/resources/simple.query.kts")) - val evalResult = (scriptResult.valueOrNull()?.returnValue as? ResultValue.Value)?.value - + val evalResult = + result.evalQuery(File("src/integrationTest/resources/simple.query.kts"), "statement1") val queryTree = evalResult as? QueryTree<*> assertNotNull(queryTree) assertEquals(true, queryTree.value) diff --git a/codyze-core/src/integrationTest/resources/simple.query.kts b/codyze-core/src/integrationTest/resources/simple.query.kts index 0827088b29..f0fde1b495 100644 --- a/codyze-core/src/integrationTest/resources/simple.query.kts +++ b/codyze-core/src/integrationTest/resources/simple.query.kts @@ -23,8 +23,12 @@ * \______/ \__| \______/ * */ -import de.fraunhofer.aisec.cpg.graph.Node +import de.fraunhofer.aisec.cpg.TranslationResult import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration +import de.fraunhofer.aisec.cpg.query.QueryTree +import de.fraunhofer.aisec.cpg.query.allExtended -val queryResult = result.allExtended(mustSatisfy = { QueryTree(it.name.localName) eq "foo" }) -queryResult +fun statement1(tr: TranslationResult): QueryTree { + val result = tr.allExtended(mustSatisfy = { QueryTree(it.name.localName) eq "foo" }) + return result +} diff --git a/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/Project.kt b/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/Project.kt index 50b5d6adbe..810b6ee354 100644 --- a/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/Project.kt +++ b/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/Project.kt @@ -23,7 +23,7 @@ * \______/ \__| \______/ * */ -package de.fraunhofer.aisec.cpg.codyze +package de.fraunhofer.aisec.codyze import com.github.ajalt.clikt.parameters.groups.OptionGroup import com.github.ajalt.clikt.parameters.options.default diff --git a/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryHost.kt b/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryHost.kt index 3fddb83aff..347373536e 100644 --- a/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryHost.kt +++ b/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryHost.kt @@ -26,24 +26,37 @@ package de.fraunhofer.aisec.codyze import de.fraunhofer.aisec.cpg.TranslationResult +import de.fraunhofer.aisec.cpg.helpers.Benchmark import java.io.File +import kotlin.reflect.full.functions import kotlin.script.experimental.api.* import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate import kotlin.script.experimental.jvmhost.createJvmEvaluationConfigurationFromTemplate -fun TranslationResult.evalQuery(scriptFile: File): ResultWithDiagnostics { +fun TranslationResult.evalQuery(scriptFile: File, queryFunc: String): Any? { val evalCtx = QueryScriptContext(this) + var b = Benchmark(TranslationResult::class.java, "Compiling query script $scriptFile") val compilationConfiguration = createJvmCompilationConfigurationFromTemplate() val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate { implicitReceivers(evalCtx) } + val scriptResult = BasicJvmScriptingHost() .eval(scriptFile.toScriptSource(), compilationConfiguration, evaluationConfiguration) - println(scriptResult) + val value = scriptResult.valueOrThrow() + val klass = value.returnValue.scriptClass + val func = klass?.functions?.firstOrNull { it.name == queryFunc } + if (func == null) { + throw IllegalArgumentException("Query function $queryFunc not found in script") + } + b.stop() - return scriptResult + b = Benchmark(TranslationResult::class.java, "Executing query function $queryFunc") + val ret = func.call(value.returnValue.scriptInstance, this) + b.stop() + return ret } diff --git a/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryScriptDefinition.kt b/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryScriptDefinition.kt index 63621de942..0e8ee131b4 100644 --- a/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryScriptDefinition.kt +++ b/codyze-core/src/main/kotlin/de/fraunhofer/aisec/codyze/QueryScriptDefinition.kt @@ -28,9 +28,12 @@ package de.fraunhofer.aisec.codyze import de.fraunhofer.aisec.cpg.TranslationResult import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.* -import kotlin.script.experimental.jvm.dependenciesFromCurrentContext import kotlin.script.experimental.jvm.jvm +import kotlin.script.experimental.jvm.updateClasspath +import kotlin.script.experimental.jvm.util.classpathFromClassloader +import kotlin.script.templates.ScriptTemplateDefinition +@ScriptTemplateDefinition(scriptFilePattern = ".*\\.query\\.kts") @KotlinScript( // File extension for the script type fileExtension = "query.kts", @@ -44,7 +47,13 @@ open class QueryScriptContext(val result: TranslationResult) object QueryScriptConfiguration : ScriptCompilationConfiguration({ baseClass(QueryScript::class) - jvm { dependenciesFromCurrentContext(wholeClasspath = true) } + jvm { + val libraries = + setOf("codyze-core", "cpg-core", "cpg-analysis", "kotlin-stdlib", "kotlin-reflect") + val cp = classpathFromClassloader(QueryScript::class.java.classLoader) + checkNotNull(cp) { "Could not read classpath" } + updateClasspath(cp.filter { element -> libraries.any { it in element.toString() } }) + } implicitReceivers(QueryScriptContext::class) compilerOptions("-Xcontext-receivers", "-jvm-target=17") defaultImports.append(