diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/PrepareSerialization.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/PrepareSerialization.kt new file mode 100644 index 0000000000..6896475360 --- /dev/null +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/PrepareSerialization.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023, 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.cpg.passes + +import de.fraunhofer.aisec.cpg.TranslationContext +import de.fraunhofer.aisec.cpg.graph.Node +import de.fraunhofer.aisec.cpg.graph.allChildren +import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression +import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker +import de.fraunhofer.aisec.cpg.passes.order.ExecuteBefore +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.javaField + +/** Pass with some graph transformations useful when doing serialization. */ +@ExecuteBefore(FilenameMapper::class) +class PrepareSerialization(ctx: TranslationContext) : TranslationUnitPass(ctx) { + private val nodeNameField = + Node::class + .memberProperties + .first() { it.name == "name" } + .javaField + .also { it?.isAccessible = true } + + override fun cleanup() { + // nothing to do + } + + override fun accept(tr: TranslationUnitDeclaration) { + tr.allChildren().map { node -> + // Add explicit AST edge + node.astChildren = SubgraphWalker.getAstChildren(node) + // CallExpression overwrites name property and must be copied to JvmField + // to be visible by Neo4jOGM + if (node is CallExpression) nodeNameField?.set(node, node.name) + } + } +} diff --git a/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Application.kt b/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Application.kt index 185fd06ac0..5b55601c45 100644 --- a/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Application.kt +++ b/cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Application.kt @@ -27,28 +27,20 @@ package de.fraunhofer.aisec.cpg_vis_neo4j import de.fraunhofer.aisec.cpg.* import de.fraunhofer.aisec.cpg.frontends.CompilationDatabase.Companion.fromFile -import de.fraunhofer.aisec.cpg.graph.Node -import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression import de.fraunhofer.aisec.cpg.helpers.Benchmark -import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker import de.fraunhofer.aisec.cpg.passes.* -import de.fraunhofer.aisec.cpg.passes.order.* import java.io.File import java.lang.Class import java.net.ConnectException import java.nio.file.Paths import java.util.concurrent.Callable import kotlin.reflect.KClass -import kotlin.reflect.full.memberProperties -import kotlin.reflect.jvm.javaField import kotlin.system.exitProcess import org.neo4j.driver.exceptions.AuthenticationException import org.neo4j.ogm.config.Configuration import org.neo4j.ogm.exception.ConnectionException import org.neo4j.ogm.session.Session import org.neo4j.ogm.session.SessionFactory -import org.neo4j.ogm.session.event.Event -import org.neo4j.ogm.session.event.EventListenerAdapter import org.slf4j.Logger import org.slf4j.LoggerFactory import picocli.CommandLine @@ -303,7 +295,6 @@ class Application : Callable { "de.fraunhofer.aisec.cpg.graph", "de.fraunhofer.aisec.cpg.frontends" ) - sessionFactory.register(AstChildrenEventListener()) session = sessionFactory.openSession() } catch (ex: ConnectionException) { @@ -351,7 +342,7 @@ class Application : Callable { * point to a file, is a directory or point to a hidden file or the paths does not have the * same top level path. */ - private fun setupTranslationConfiguration(): TranslationConfiguration { + fun setupTranslationConfiguration(): TranslationConfiguration { val translationConfiguration = TranslationConfiguration.builder() .topLevel(topLevel) @@ -394,6 +385,7 @@ class Application : Callable { } } } + translationConfiguration.registerPass(PrepareSerialization::class) mutuallyExclusiveParameters.jsonCompilationDatabase?.let { val db = fromFile(it) @@ -477,27 +469,6 @@ class Application : Callable { } } -class AstChildrenEventListener : EventListenerAdapter() { - private val nodeNameField = - Node::class - .memberProperties - .first() { it.name == "name" } - .javaField - .also { it?.isAccessible = true } - - override fun onPreSave(event: Event?) { - val node = event?.`object` as? Node ?: return - node.astChildren = SubgraphWalker.getAstChildren(node) - if (node is CallExpression) fixBackingFields(node) - } - - private fun fixBackingFields(node: CallExpression) { - // CallExpression overwrites name property and must be copied to JvmField - // to be visible by Neo4jOGM - nodeNameField?.set(node, node.name) - } -} - /** * Starts a command line application of the cpg-vis-neo4j. * diff --git a/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt b/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt index 2d1d442867..33f38fe2cb 100644 --- a/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt +++ b/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt @@ -25,47 +25,35 @@ */ package de.fraunhofer.aisec.cpg_vis_neo4j -import de.fraunhofer.aisec.cpg.TranslationConfiguration import de.fraunhofer.aisec.cpg.TranslationManager -import de.fraunhofer.aisec.cpg.TranslationResult import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration import de.fraunhofer.aisec.cpg.graph.functions -import java.io.File import java.nio.file.Paths import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull import org.junit.jupiter.api.Tag +import picocli.CommandLine @Tag("integration") class ApplicationTest { - - private var translationResult: TranslationResult? = null - @Test @Throws(InterruptedException::class) fun testPush() { val topLevel = Paths.get("src").resolve("test").resolve("resources").toAbsolutePath() val path = topLevel.resolve("client.cpp").toAbsolutePath() - val file = File(path.toString()) - assert(file.exists() && !file.isDirectory && !file.isHidden) - val translationConfiguration = - TranslationConfiguration.builder() - .sourceLocations(file) - .topLevel(topLevel.toFile()) - .defaultPasses() - .defaultLanguages() - .debugParser(true) - .build() - val translationManager = - TranslationManager.builder().config(translationConfiguration).build() - translationResult = translationManager.analyze().get() - assertEquals(31, translationResult.functions.size) + val cmd = CommandLine(Application::class.java) + cmd.parseArgs(path.toString()) + val application = cmd.getCommand() - val application = Application() + val translationConfiguration = application.setupTranslationConfiguration() + val translationResult = + TranslationManager.builder().config(translationConfiguration).build().analyze().get() + + assertEquals(31, translationResult.functions.size) - application.pushToNeo4j(translationResult!!) + application.pushToNeo4j(translationResult) val sessionAndSessionFactoryPair = application.connect()